@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.
Files changed (260) hide show
  1. package/dist/__tests__/autowired.test.d.ts +1 -0
  2. package/dist/__tests__/autowired.test.js +109 -0
  3. package/dist/__tests__/autowired.test.js.map +1 -0
  4. package/dist/__tests__/cinnabun-application.test.d.ts +1 -0
  5. package/dist/__tests__/cinnabun-application.test.js +96 -0
  6. package/dist/__tests__/cinnabun-application.test.js.map +1 -0
  7. package/dist/__tests__/cinnabun-factory.test.d.ts +1 -0
  8. package/dist/__tests__/cinnabun-factory.test.js +269 -0
  9. package/dist/__tests__/cinnabun-factory.test.js.map +1 -0
  10. package/dist/__tests__/circular-dependency.test.d.ts +1 -0
  11. package/dist/__tests__/circular-dependency.test.js +318 -0
  12. package/dist/__tests__/circular-dependency.test.js.map +1 -0
  13. package/dist/__tests__/compression.test.d.ts +1 -0
  14. package/dist/__tests__/compression.test.js +459 -0
  15. package/dist/__tests__/compression.test.js.map +1 -0
  16. package/dist/__tests__/config.test.d.ts +1 -0
  17. package/dist/__tests__/config.test.js +86 -0
  18. package/dist/__tests__/config.test.js.map +1 -0
  19. package/dist/__tests__/cors.test.d.ts +1 -0
  20. package/dist/__tests__/cors.test.js +575 -0
  21. package/dist/__tests__/cors.test.js.map +1 -0
  22. package/dist/__tests__/env-config.test.d.ts +1 -0
  23. package/dist/__tests__/env-config.test.js +367 -0
  24. package/dist/__tests__/env-config.test.js.map +1 -0
  25. package/dist/__tests__/exception.test.d.ts +1 -0
  26. package/dist/__tests__/exception.test.js +207 -0
  27. package/dist/__tests__/exception.test.js.map +1 -0
  28. package/dist/__tests__/guards-interceptors.test.d.ts +1 -0
  29. package/dist/__tests__/guards-interceptors.test.js +660 -0
  30. package/dist/__tests__/guards-interceptors.test.js.map +1 -0
  31. package/dist/__tests__/health-check.test.d.ts +1 -0
  32. package/dist/__tests__/health-check.test.js +240 -0
  33. package/dist/__tests__/health-check.test.js.map +1 -0
  34. package/dist/__tests__/http.test.d.ts +1 -0
  35. package/dist/__tests__/http.test.js +629 -0
  36. package/dist/__tests__/http.test.js.map +1 -0
  37. package/dist/__tests__/integration/e2e.test.d.ts +1 -0
  38. package/dist/__tests__/integration/e2e.test.js +192 -0
  39. package/dist/__tests__/integration/e2e.test.js.map +1 -0
  40. package/dist/__tests__/integration/performance.bench.d.ts +1 -0
  41. package/dist/__tests__/integration/performance.bench.js +129 -0
  42. package/dist/__tests__/integration/performance.bench.js.map +1 -0
  43. package/dist/__tests__/integration/validation.test.d.ts +1 -0
  44. package/dist/__tests__/integration/validation.test.js +133 -0
  45. package/dist/__tests__/integration/validation.test.js.map +1 -0
  46. package/dist/__tests__/lifecycle-management.test.d.ts +1 -0
  47. package/dist/__tests__/lifecycle-management.test.js +688 -0
  48. package/dist/__tests__/lifecycle-management.test.js.map +1 -0
  49. package/dist/__tests__/lifecycle.test.d.ts +1 -0
  50. package/dist/__tests__/lifecycle.test.js +196 -0
  51. package/dist/__tests__/lifecycle.test.js.map +1 -0
  52. package/dist/__tests__/logger.test.d.ts +1 -0
  53. package/dist/__tests__/logger.test.js +109 -0
  54. package/dist/__tests__/logger.test.js.map +1 -0
  55. package/dist/__tests__/middleware.test.d.ts +1 -0
  56. package/dist/__tests__/middleware.test.js +329 -0
  57. package/dist/__tests__/middleware.test.js.map +1 -0
  58. package/dist/__tests__/module.test.d.ts +1 -0
  59. package/dist/__tests__/module.test.js +280 -0
  60. package/dist/__tests__/module.test.js.map +1 -0
  61. package/dist/__tests__/plugin.test.d.ts +1 -0
  62. package/dist/__tests__/plugin.test.js +283 -0
  63. package/dist/__tests__/plugin.test.js.map +1 -0
  64. package/dist/__tests__/request-logger.test.d.ts +1 -0
  65. package/dist/__tests__/request-logger.test.js +342 -0
  66. package/dist/__tests__/request-logger.test.js.map +1 -0
  67. package/dist/__tests__/request-mapping.test.d.ts +1 -0
  68. package/dist/__tests__/request-mapping.test.js +201 -0
  69. package/dist/__tests__/request-mapping.test.js.map +1 -0
  70. package/dist/__tests__/routes.test.d.ts +1 -0
  71. package/dist/__tests__/routes.test.js +119 -0
  72. package/dist/__tests__/routes.test.js.map +1 -0
  73. package/dist/__tests__/scan-fixtures/controllers/hello.controller.d.ts +4 -0
  74. package/dist/__tests__/scan-fixtures/controllers/hello.controller.js +28 -0
  75. package/dist/__tests__/scan-fixtures/controllers/hello.controller.js.map +1 -0
  76. package/dist/__tests__/scan-fixtures/modules/feature.module.d.ts +6 -0
  77. package/dist/__tests__/scan-fixtures/modules/feature.module.js +28 -0
  78. package/dist/__tests__/scan-fixtures/modules/feature.module.js.map +1 -0
  79. package/dist/__tests__/scan-fixtures/services/greeting.service.d.ts +4 -0
  80. package/dist/__tests__/scan-fixtures/services/greeting.service.js +18 -0
  81. package/dist/__tests__/scan-fixtures/services/greeting.service.js.map +1 -0
  82. package/dist/__tests__/scanner.test.d.ts +1 -0
  83. package/dist/__tests__/scanner.test.js +49 -0
  84. package/dist/__tests__/scanner.test.js.map +1 -0
  85. package/dist/__tests__/validation.test.d.ts +1 -0
  86. package/dist/__tests__/validation.test.js +561 -0
  87. package/dist/__tests__/validation.test.js.map +1 -0
  88. package/dist/__tests__/websocket-auth.test.d.ts +1 -0
  89. package/dist/__tests__/websocket-auth.test.js +431 -0
  90. package/dist/__tests__/websocket-auth.test.js.map +1 -0
  91. package/dist/__tests__/websocket-decorators.test.d.ts +1 -0
  92. package/dist/__tests__/websocket-decorators.test.js +173 -0
  93. package/dist/__tests__/websocket-decorators.test.js.map +1 -0
  94. package/dist/__tests__/websocket-validation.test.d.ts +1 -0
  95. package/dist/__tests__/websocket-validation.test.js +827 -0
  96. package/dist/__tests__/websocket-validation.test.js.map +1 -0
  97. package/dist/__tests__/websocket.test.d.ts +1 -0
  98. package/dist/__tests__/websocket.test.js +415 -0
  99. package/dist/__tests__/websocket.test.js.map +1 -0
  100. package/dist/config/config.module.d.ts +2 -0
  101. package/dist/config/config.module.js +18 -0
  102. package/dist/config/config.module.js.map +1 -0
  103. package/dist/config/config.service.d.ts +15 -0
  104. package/dist/config/config.service.js +58 -0
  105. package/dist/config/config.service.js.map +1 -0
  106. package/dist/config/schemas.d.ts +107 -0
  107. package/dist/config/schemas.js +87 -0
  108. package/dist/config/schemas.js.map +1 -0
  109. package/dist/core/app.d.ts +44 -0
  110. package/dist/core/app.js +178 -0
  111. package/dist/core/app.js.map +1 -0
  112. package/dist/core/cinnabun-factory.d.ts +5 -0
  113. package/dist/core/cinnabun-factory.js +130 -0
  114. package/dist/core/cinnabun-factory.js.map +1 -0
  115. package/dist/core/config-loader.d.ts +2 -0
  116. package/dist/core/config-loader.js +76 -0
  117. package/dist/core/config-loader.js.map +1 -0
  118. package/dist/core/config.d.ts +12 -0
  119. package/dist/core/config.js +27 -0
  120. package/dist/core/config.js.map +1 -0
  121. package/dist/core/container.d.ts +10 -0
  122. package/dist/core/container.js +82 -0
  123. package/dist/core/container.js.map +1 -0
  124. package/dist/core/dependency-validator.d.ts +12 -0
  125. package/dist/core/dependency-validator.js +76 -0
  126. package/dist/core/dependency-validator.js.map +1 -0
  127. package/dist/core/guard.d.ts +3 -0
  128. package/dist/core/guard.js +2 -0
  129. package/dist/core/guard.js.map +1 -0
  130. package/dist/core/interceptor.d.ts +4 -0
  131. package/dist/core/interceptor.js +2 -0
  132. package/dist/core/interceptor.js.map +1 -0
  133. package/dist/core/logger.d.ts +15 -0
  134. package/dist/core/logger.js +71 -0
  135. package/dist/core/logger.js.map +1 -0
  136. package/dist/core/module-resolver.d.ts +6 -0
  137. package/dist/core/module-resolver.js +67 -0
  138. package/dist/core/module-resolver.js.map +1 -0
  139. package/dist/core/plugin.d.ts +12 -0
  140. package/dist/core/plugin.js +2 -0
  141. package/dist/core/plugin.js.map +1 -0
  142. package/dist/core/router.d.ts +38 -0
  143. package/dist/core/router.js +406 -0
  144. package/dist/core/router.js.map +1 -0
  145. package/dist/core/scanner.d.ts +7 -0
  146. package/dist/core/scanner.js +83 -0
  147. package/dist/core/scanner.js.map +1 -0
  148. package/dist/core/shutdown-manager.d.ts +15 -0
  149. package/dist/core/shutdown-manager.js +68 -0
  150. package/dist/core/shutdown-manager.js.map +1 -0
  151. package/dist/core/websocket-handler.d.ts +41 -0
  152. package/dist/core/websocket-handler.js +242 -0
  153. package/dist/core/websocket-handler.js.map +1 -0
  154. package/dist/decorators/autowired.d.ts +3 -0
  155. package/dist/decorators/autowired.js +11 -0
  156. package/dist/decorators/autowired.js.map +1 -0
  157. package/dist/decorators/cinnabun-application.d.ts +14 -0
  158. package/dist/decorators/cinnabun-application.js +17 -0
  159. package/dist/decorators/cinnabun-application.js.map +1 -0
  160. package/dist/decorators/lifecycle.d.ts +2 -0
  161. package/dist/decorators/lifecycle.js +12 -0
  162. package/dist/decorators/lifecycle.js.map +1 -0
  163. package/dist/decorators/middleware.d.ts +2 -0
  164. package/dist/decorators/middleware.js +12 -0
  165. package/dist/decorators/middleware.js.map +1 -0
  166. package/dist/decorators/module.d.ts +10 -0
  167. package/dist/decorators/module.js +13 -0
  168. package/dist/decorators/module.js.map +1 -0
  169. package/dist/decorators/on-shutdown.d.ts +1 -0
  170. package/dist/decorators/on-shutdown.js +10 -0
  171. package/dist/decorators/on-shutdown.js.map +1 -0
  172. package/dist/decorators/params.d.ts +6 -0
  173. package/dist/decorators/params.js +31 -0
  174. package/dist/decorators/params.js.map +1 -0
  175. package/dist/decorators/request-mapping.d.ts +7 -0
  176. package/dist/decorators/request-mapping.js +34 -0
  177. package/dist/decorators/request-mapping.js.map +1 -0
  178. package/dist/decorators/response.d.ts +2 -0
  179. package/dist/decorators/response.js +17 -0
  180. package/dist/decorators/response.js.map +1 -0
  181. package/dist/decorators/rest-controller.d.ts +1 -0
  182. package/dist/decorators/rest-controller.js +19 -0
  183. package/dist/decorators/rest-controller.js.map +1 -0
  184. package/dist/decorators/routes.d.ts +5 -0
  185. package/dist/decorators/routes.js +19 -0
  186. package/dist/decorators/routes.js.map +1 -0
  187. package/dist/decorators/service.d.ts +1 -0
  188. package/dist/decorators/service.js +7 -0
  189. package/dist/decorators/service.js.map +1 -0
  190. package/dist/decorators/use-guard.d.ts +2 -0
  191. package/dist/decorators/use-guard.js +12 -0
  192. package/dist/decorators/use-guard.js.map +1 -0
  193. package/dist/decorators/use-interceptor.d.ts +2 -0
  194. package/dist/decorators/use-interceptor.js +12 -0
  195. package/dist/decorators/use-interceptor.js.map +1 -0
  196. package/dist/decorators/validate.d.ts +12 -0
  197. package/dist/decorators/validate.js +7 -0
  198. package/dist/decorators/validate.js.map +1 -0
  199. package/dist/decorators/websocket.d.ts +9 -0
  200. package/dist/decorators/websocket.js +38 -0
  201. package/dist/decorators/websocket.js.map +1 -0
  202. package/dist/decorators/ws-event.d.ts +28 -0
  203. package/dist/decorators/ws-event.js +37 -0
  204. package/dist/decorators/ws-event.js.map +1 -0
  205. package/dist/decorators/ws-gateway.d.ts +18 -0
  206. package/dist/decorators/ws-gateway.js +24 -0
  207. package/dist/decorators/ws-gateway.js.map +1 -0
  208. package/dist/dev/index.d.ts +6 -0
  209. package/dist/dev/index.js +28 -0
  210. package/dist/dev/index.js.map +1 -0
  211. package/dist/exceptions/circular-dependency-error.d.ts +5 -0
  212. package/dist/exceptions/circular-dependency-error.js +16 -0
  213. package/dist/exceptions/circular-dependency-error.js.map +1 -0
  214. package/dist/exceptions/http-exception.d.ts +41 -0
  215. package/dist/exceptions/http-exception.js +96 -0
  216. package/dist/exceptions/http-exception.js.map +1 -0
  217. package/dist/guards/jwt-websocket.guard.d.ts +11 -0
  218. package/dist/guards/jwt-websocket.guard.js +37 -0
  219. package/dist/guards/jwt-websocket.guard.js.map +1 -0
  220. package/dist/guards/websocket-auth.guard.d.ts +16 -0
  221. package/dist/guards/websocket-auth.guard.js +43 -0
  222. package/dist/guards/websocket-auth.guard.js.map +1 -0
  223. package/dist/health/health-check.service.d.ts +45 -0
  224. package/dist/health/health-check.service.js +95 -0
  225. package/dist/health/health-check.service.js.map +1 -0
  226. package/dist/health/health.controller.d.ts +15 -0
  227. package/dist/health/health.controller.js +63 -0
  228. package/dist/health/health.controller.js.map +1 -0
  229. package/dist/health/health.module.d.ts +2 -0
  230. package/dist/health/health.module.js +20 -0
  231. package/dist/health/health.module.js.map +1 -0
  232. package/dist/index.d.ts +74 -11
  233. package/dist/index.js +54 -0
  234. package/dist/index.js.map +1 -0
  235. package/dist/metadata/storage.d.ts +171 -0
  236. package/dist/metadata/storage.js +257 -0
  237. package/dist/metadata/storage.js.map +1 -0
  238. package/dist/middleware/compression.middleware.d.ts +32 -0
  239. package/dist/middleware/compression.middleware.js +113 -0
  240. package/dist/middleware/compression.middleware.js.map +1 -0
  241. package/dist/middleware/cors.middleware.d.ts +18 -0
  242. package/dist/middleware/cors.middleware.js +79 -0
  243. package/dist/middleware/cors.middleware.js.map +1 -0
  244. package/dist/middleware/performance-tracker.middleware.d.ts +35 -0
  245. package/dist/middleware/performance-tracker.middleware.js +79 -0
  246. package/dist/middleware/performance-tracker.middleware.js.map +1 -0
  247. package/dist/middleware/request-logger.middleware.d.ts +32 -0
  248. package/dist/middleware/request-logger.middleware.js +125 -0
  249. package/dist/middleware/request-logger.middleware.js.map +1 -0
  250. package/dist/types/index.d.ts +14 -0
  251. package/dist/types/index.js +5 -0
  252. package/dist/types/index.js.map +1 -0
  253. package/dist/validation/helpers.d.ts +36 -0
  254. package/dist/validation/helpers.js +27 -0
  255. package/dist/validation/helpers.js.map +1 -0
  256. package/dist/websocket/error.d.ts +27 -0
  257. package/dist/websocket/error.js +38 -0
  258. package/dist/websocket/error.js.map +1 -0
  259. package/package.json +38 -5
  260. 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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"}