@morojs/moro 1.6.1 → 1.6.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 (404) hide show
  1. package/README.md +74 -256
  2. package/dist/core/auth/morojs-adapter.js +20 -20
  3. package/dist/core/auth/morojs-adapter.js.map +1 -1
  4. package/dist/core/config/config-manager.d.ts +44 -0
  5. package/dist/core/config/config-manager.js +104 -0
  6. package/dist/core/config/config-manager.js.map +1 -0
  7. package/dist/core/config/config-sources.d.ts +21 -0
  8. package/dist/core/config/config-sources.js +503 -0
  9. package/dist/core/config/config-sources.js.map +1 -0
  10. package/dist/core/config/config-validator.d.ts +21 -0
  11. package/dist/core/config/config-validator.js +791 -0
  12. package/dist/core/config/config-validator.js.map +1 -0
  13. package/dist/core/config/file-loader.d.ts +1 -6
  14. package/dist/core/config/file-loader.js +21 -249
  15. package/dist/core/config/file-loader.js.map +1 -1
  16. package/dist/core/config/index.d.ts +41 -12
  17. package/dist/core/config/index.js +65 -54
  18. package/dist/core/config/index.js.map +1 -1
  19. package/dist/core/config/schema.d.ts +2 -2
  20. package/dist/core/config/schema.js +55 -44
  21. package/dist/core/config/schema.js.map +1 -1
  22. package/dist/core/config/utils.d.ts +10 -3
  23. package/dist/core/config/utils.js +31 -58
  24. package/dist/core/config/utils.js.map +1 -1
  25. package/dist/core/database/adapters/drizzle.d.ts +1 -1
  26. package/dist/core/database/adapters/drizzle.js +18 -11
  27. package/dist/core/database/adapters/drizzle.js.map +1 -1
  28. package/dist/core/database/adapters/index.d.ts +7 -7
  29. package/dist/core/database/adapters/index.js +19 -29
  30. package/dist/core/database/adapters/index.js.map +1 -1
  31. package/dist/core/database/adapters/mongodb.d.ts +13 -1
  32. package/dist/core/database/adapters/mongodb.js +46 -10
  33. package/dist/core/database/adapters/mongodb.js.map +1 -1
  34. package/dist/core/database/adapters/mysql.d.ts +14 -1
  35. package/dist/core/database/adapters/mysql.js +19 -9
  36. package/dist/core/database/adapters/mysql.js.map +1 -1
  37. package/dist/core/database/adapters/postgresql.d.ts +12 -2
  38. package/dist/core/database/adapters/postgresql.js +19 -9
  39. package/dist/core/database/adapters/postgresql.js.map +1 -1
  40. package/dist/core/database/adapters/redis.d.ts +12 -1
  41. package/dist/core/database/adapters/redis.js +48 -13
  42. package/dist/core/database/adapters/redis.js.map +1 -1
  43. package/dist/core/database/adapters/sqlite.d.ts +3 -1
  44. package/dist/core/database/adapters/sqlite.js +19 -8
  45. package/dist/core/database/adapters/sqlite.js.map +1 -1
  46. package/dist/core/database/index.d.ts +2 -2
  47. package/dist/core/database/index.js +2 -18
  48. package/dist/core/database/index.js.map +1 -1
  49. package/dist/core/docs/index.d.ts +9 -9
  50. package/dist/core/docs/index.js +14 -35
  51. package/dist/core/docs/index.js.map +1 -1
  52. package/dist/core/docs/openapi-generator.d.ts +2 -2
  53. package/dist/core/docs/openapi-generator.js +11 -16
  54. package/dist/core/docs/openapi-generator.js.map +1 -1
  55. package/dist/core/docs/schema-to-openapi.d.ts +2 -2
  56. package/dist/core/docs/schema-to-openapi.js +5 -11
  57. package/dist/core/docs/schema-to-openapi.js.map +1 -1
  58. package/dist/core/docs/simple-docs.d.ts +1 -1
  59. package/dist/core/docs/simple-docs.js +4 -9
  60. package/dist/core/docs/simple-docs.js.map +1 -1
  61. package/dist/core/docs/swagger-ui.d.ts +2 -2
  62. package/dist/core/docs/swagger-ui.js +26 -29
  63. package/dist/core/docs/swagger-ui.js.map +1 -1
  64. package/dist/core/docs/zod-to-openapi.js +31 -28
  65. package/dist/core/docs/zod-to-openapi.js.map +1 -1
  66. package/dist/core/events/event-bus.d.ts +1 -1
  67. package/dist/core/events/event-bus.js +7 -11
  68. package/dist/core/events/event-bus.js.map +1 -1
  69. package/dist/core/events/index.d.ts +2 -2
  70. package/dist/core/events/index.js +1 -5
  71. package/dist/core/events/index.js.map +1 -1
  72. package/dist/core/framework.d.ts +20 -13
  73. package/dist/core/framework.js +285 -102
  74. package/dist/core/framework.js.map +1 -1
  75. package/dist/core/http/http-server.d.ts +59 -7
  76. package/dist/core/http/http-server.js +190 -176
  77. package/dist/core/http/http-server.js.map +1 -1
  78. package/dist/core/http/index.d.ts +4 -3
  79. package/dist/core/http/index.js +3 -8
  80. package/dist/core/http/index.js.map +1 -1
  81. package/dist/core/http/uws-http-server.d.ts +46 -0
  82. package/dist/core/http/uws-http-server.js +523 -0
  83. package/dist/core/http/uws-http-server.js.map +1 -0
  84. package/dist/core/logger/filters.d.ts +1 -1
  85. package/dist/core/logger/filters.js +20 -23
  86. package/dist/core/logger/filters.js.map +1 -1
  87. package/dist/core/logger/index.d.ts +3 -3
  88. package/dist/core/logger/index.js +2 -24
  89. package/dist/core/logger/index.js.map +1 -1
  90. package/dist/core/logger/logger.d.ts +30 -14
  91. package/dist/core/logger/logger.js +398 -223
  92. package/dist/core/logger/logger.js.map +1 -1
  93. package/dist/core/logger/outputs.d.ts +1 -1
  94. package/dist/core/logger/outputs.js +8 -17
  95. package/dist/core/logger/outputs.js.map +1 -1
  96. package/dist/core/middleware/built-in/adapters/cache/file.d.ts +1 -1
  97. package/dist/core/middleware/built-in/adapters/cache/file.js +10 -47
  98. package/dist/core/middleware/built-in/adapters/cache/file.js.map +1 -1
  99. package/dist/core/middleware/built-in/adapters/cache/index.d.ts +4 -4
  100. package/dist/core/middleware/built-in/adapters/cache/index.js +10 -17
  101. package/dist/core/middleware/built-in/adapters/cache/index.js.map +1 -1
  102. package/dist/core/middleware/built-in/adapters/cache/memory.d.ts +1 -1
  103. package/dist/core/middleware/built-in/adapters/cache/memory.js +3 -7
  104. package/dist/core/middleware/built-in/adapters/cache/memory.js.map +1 -1
  105. package/dist/core/middleware/built-in/adapters/cache/redis.d.ts +3 -1
  106. package/dist/core/middleware/built-in/adapters/cache/redis.js +11 -9
  107. package/dist/core/middleware/built-in/adapters/cache/redis.js.map +1 -1
  108. package/dist/core/middleware/built-in/adapters/cdn/azure.d.ts +1 -1
  109. package/dist/core/middleware/built-in/adapters/cdn/azure.js +3 -7
  110. package/dist/core/middleware/built-in/adapters/cdn/azure.js.map +1 -1
  111. package/dist/core/middleware/built-in/adapters/cdn/cloudflare.d.ts +1 -1
  112. package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js +3 -7
  113. package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js.map +1 -1
  114. package/dist/core/middleware/built-in/adapters/cdn/cloudfront.d.ts +3 -1
  115. package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js +12 -10
  116. package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js.map +1 -1
  117. package/dist/core/middleware/built-in/adapters/cdn/index.d.ts +4 -4
  118. package/dist/core/middleware/built-in/adapters/cdn/index.js +10 -17
  119. package/dist/core/middleware/built-in/adapters/cdn/index.js.map +1 -1
  120. package/dist/core/middleware/built-in/adapters/index.d.ts +4 -4
  121. package/dist/core/middleware/built-in/adapters/index.js +4 -23
  122. package/dist/core/middleware/built-in/adapters/index.js.map +1 -1
  123. package/dist/core/middleware/built-in/auth-helpers.js +11 -22
  124. package/dist/core/middleware/built-in/auth-helpers.js.map +1 -1
  125. package/dist/core/middleware/built-in/auth-providers.d.ts +1 -1
  126. package/dist/core/middleware/built-in/auth-providers.js +4 -9
  127. package/dist/core/middleware/built-in/auth-providers.js.map +1 -1
  128. package/dist/core/middleware/built-in/auth.d.ts +2 -2
  129. package/dist/core/middleware/built-in/auth.js +93 -26
  130. package/dist/core/middleware/built-in/auth.js.map +1 -1
  131. package/dist/core/middleware/built-in/cache.d.ts +2 -2
  132. package/dist/core/middleware/built-in/cache.js +11 -12
  133. package/dist/core/middleware/built-in/cache.js.map +1 -1
  134. package/dist/core/middleware/built-in/cdn.d.ts +2 -2
  135. package/dist/core/middleware/built-in/cdn.js +5 -9
  136. package/dist/core/middleware/built-in/cdn.js.map +1 -1
  137. package/dist/core/middleware/built-in/cookie.d.ts +1 -1
  138. package/dist/core/middleware/built-in/cookie.js +3 -7
  139. package/dist/core/middleware/built-in/cookie.js.map +1 -1
  140. package/dist/core/middleware/built-in/cors.d.ts +1 -1
  141. package/dist/core/middleware/built-in/cors.js +3 -7
  142. package/dist/core/middleware/built-in/cors.js.map +1 -1
  143. package/dist/core/middleware/built-in/csp.d.ts +1 -1
  144. package/dist/core/middleware/built-in/csp.js +5 -8
  145. package/dist/core/middleware/built-in/csp.js.map +1 -1
  146. package/dist/core/middleware/built-in/csrf.d.ts +1 -1
  147. package/dist/core/middleware/built-in/csrf.js +5 -8
  148. package/dist/core/middleware/built-in/csrf.js.map +1 -1
  149. package/dist/core/middleware/built-in/error-tracker.js +3 -7
  150. package/dist/core/middleware/built-in/error-tracker.js.map +1 -1
  151. package/dist/core/middleware/built-in/index.d.ts +28 -27
  152. package/dist/core/middleware/built-in/index.js +48 -78
  153. package/dist/core/middleware/built-in/index.js.map +1 -1
  154. package/dist/core/middleware/built-in/jwt-helpers.d.ts +118 -0
  155. package/dist/core/middleware/built-in/jwt-helpers.js +218 -0
  156. package/dist/core/middleware/built-in/jwt-helpers.js.map +1 -0
  157. package/dist/core/middleware/built-in/performance-monitor.js +3 -7
  158. package/dist/core/middleware/built-in/performance-monitor.js.map +1 -1
  159. package/dist/core/middleware/built-in/rate-limit.d.ts +1 -1
  160. package/dist/core/middleware/built-in/rate-limit.js +3 -7
  161. package/dist/core/middleware/built-in/rate-limit.js.map +1 -1
  162. package/dist/core/middleware/built-in/request-logger.js +5 -8
  163. package/dist/core/middleware/built-in/request-logger.js.map +1 -1
  164. package/dist/core/middleware/built-in/session.d.ts +2 -2
  165. package/dist/core/middleware/built-in/session.js +11 -15
  166. package/dist/core/middleware/built-in/session.js.map +1 -1
  167. package/dist/core/middleware/built-in/sse.d.ts +1 -1
  168. package/dist/core/middleware/built-in/sse.js +12 -14
  169. package/dist/core/middleware/built-in/sse.js.map +1 -1
  170. package/dist/core/middleware/built-in/validation.d.ts +1 -1
  171. package/dist/core/middleware/built-in/validation.js +3 -7
  172. package/dist/core/middleware/built-in/validation.js.map +1 -1
  173. package/dist/core/middleware/index.d.ts +4 -4
  174. package/dist/core/middleware/index.js +8 -28
  175. package/dist/core/middleware/index.js.map +1 -1
  176. package/dist/core/modules/auto-discovery.d.ts +19 -2
  177. package/dist/core/modules/auto-discovery.js +391 -74
  178. package/dist/core/modules/auto-discovery.js.map +1 -1
  179. package/dist/core/modules/index.d.ts +2 -2
  180. package/dist/core/modules/index.js +2 -9
  181. package/dist/core/modules/index.js.map +1 -1
  182. package/dist/core/modules/modules.d.ts +3 -3
  183. package/dist/core/modules/modules.js +23 -54
  184. package/dist/core/modules/modules.js.map +1 -1
  185. package/dist/core/networking/adapters/index.d.ts +4 -3
  186. package/dist/core/networking/adapters/index.js +3 -7
  187. package/dist/core/networking/adapters/index.js.map +1 -1
  188. package/dist/core/networking/adapters/socketio-adapter.d.ts +1 -1
  189. package/dist/core/networking/adapters/socketio-adapter.js +5 -40
  190. package/dist/core/networking/adapters/socketio-adapter.js.map +1 -1
  191. package/dist/core/networking/adapters/uws-adapter.d.ts +44 -0
  192. package/dist/core/networking/adapters/uws-adapter.js +513 -0
  193. package/dist/core/networking/adapters/uws-adapter.js.map +1 -0
  194. package/dist/core/networking/adapters/ws-adapter.d.ts +2 -2
  195. package/dist/core/networking/adapters/ws-adapter.js +8 -43
  196. package/dist/core/networking/adapters/ws-adapter.js.map +1 -1
  197. package/dist/core/networking/index.d.ts +3 -2
  198. package/dist/core/networking/index.js +2 -7
  199. package/dist/core/networking/index.js.map +1 -1
  200. package/dist/core/networking/service-discovery.js +8 -12
  201. package/dist/core/networking/service-discovery.js.map +1 -1
  202. package/dist/core/networking/websocket-adapter.js +1 -2
  203. package/dist/core/networking/websocket-adapter.js.map +1 -1
  204. package/dist/core/networking/websocket-manager.d.ts +3 -3
  205. package/dist/core/networking/websocket-manager.js +9 -11
  206. package/dist/core/networking/websocket-manager.js.map +1 -1
  207. package/dist/core/pooling/object-pool-manager.d.ts +140 -0
  208. package/dist/core/pooling/object-pool-manager.js +502 -0
  209. package/dist/core/pooling/object-pool-manager.js.map +1 -0
  210. package/dist/core/routing/app-integration.d.ts +14 -12
  211. package/dist/core/routing/app-integration.js +49 -85
  212. package/dist/core/routing/app-integration.js.map +1 -1
  213. package/dist/core/routing/index.d.ts +17 -11
  214. package/dist/core/routing/index.js +48 -237
  215. package/dist/core/routing/index.js.map +1 -1
  216. package/dist/core/routing/path-matcher.d.ts +67 -0
  217. package/dist/core/routing/path-matcher.js +182 -0
  218. package/dist/core/routing/path-matcher.js.map +1 -0
  219. package/dist/core/routing/router.d.ts +38 -0
  220. package/dist/core/routing/router.js +68 -0
  221. package/dist/core/routing/router.js.map +1 -0
  222. package/dist/core/routing/unified-router.d.ts +148 -0
  223. package/dist/core/routing/unified-router.js +684 -0
  224. package/dist/core/routing/unified-router.js.map +1 -0
  225. package/dist/core/runtime/aws-lambda-adapter.d.ts +3 -3
  226. package/dist/core/runtime/aws-lambda-adapter.js +2 -6
  227. package/dist/core/runtime/aws-lambda-adapter.js.map +1 -1
  228. package/dist/core/runtime/base-adapter.d.ts +2 -2
  229. package/dist/core/runtime/base-adapter.js +3 -7
  230. package/dist/core/runtime/base-adapter.js.map +1 -1
  231. package/dist/core/runtime/cloudflare-workers-adapter.d.ts +3 -3
  232. package/dist/core/runtime/cloudflare-workers-adapter.js +2 -6
  233. package/dist/core/runtime/cloudflare-workers-adapter.js.map +1 -1
  234. package/dist/core/runtime/index.d.ts +12 -12
  235. package/dist/core/runtime/index.js +22 -35
  236. package/dist/core/runtime/index.js.map +1 -1
  237. package/dist/core/runtime/node-adapter.d.ts +4 -4
  238. package/dist/core/runtime/node-adapter.js +18 -49
  239. package/dist/core/runtime/node-adapter.js.map +1 -1
  240. package/dist/core/runtime/vercel-edge-adapter.d.ts +3 -3
  241. package/dist/core/runtime/vercel-edge-adapter.js +2 -6
  242. package/dist/core/runtime/vercel-edge-adapter.js.map +1 -1
  243. package/dist/core/utilities/circuit-breaker.js +1 -5
  244. package/dist/core/utilities/circuit-breaker.js.map +1 -1
  245. package/dist/core/utilities/container.js +12 -22
  246. package/dist/core/utilities/container.js.map +1 -1
  247. package/dist/core/utilities/hooks.d.ts +2 -2
  248. package/dist/core/utilities/hooks.js +7 -12
  249. package/dist/core/utilities/hooks.js.map +1 -1
  250. package/dist/core/utilities/index.d.ts +5 -4
  251. package/dist/core/utilities/index.js +5 -19
  252. package/dist/core/utilities/index.js.map +1 -1
  253. package/dist/core/utilities/package-utils.d.ts +38 -0
  254. package/dist/core/utilities/package-utils.js +57 -0
  255. package/dist/core/utilities/package-utils.js.map +1 -0
  256. package/dist/core/validation/adapters.d.ts +1 -1
  257. package/dist/core/validation/adapters.js +15 -26
  258. package/dist/core/validation/adapters.js.map +1 -1
  259. package/dist/core/validation/index.d.ts +6 -4
  260. package/dist/core/validation/index.js +57 -28
  261. package/dist/core/validation/index.js.map +1 -1
  262. package/dist/core/validation/schema-interface.js +3 -9
  263. package/dist/core/validation/schema-interface.js.map +1 -1
  264. package/dist/index.d.ts +51 -52
  265. package/dist/index.js +23 -132
  266. package/dist/index.js.map +1 -1
  267. package/dist/moro.d.ts +70 -16
  268. package/dist/moro.js +658 -271
  269. package/dist/moro.js.map +1 -1
  270. package/dist/types/auth.js +3 -9
  271. package/dist/types/auth.js.map +1 -1
  272. package/dist/types/cache.js +1 -2
  273. package/dist/types/cdn.js +1 -2
  274. package/dist/types/config.d.ts +73 -2
  275. package/dist/types/config.js +1 -2
  276. package/dist/types/config.js.map +1 -1
  277. package/dist/types/core.d.ts +36 -42
  278. package/dist/types/core.js +1 -2
  279. package/dist/types/database.js +1 -2
  280. package/dist/types/discovery.js +1 -2
  281. package/dist/types/events.js +1 -2
  282. package/dist/types/hooks.d.ts +1 -1
  283. package/dist/types/hooks.js +1 -2
  284. package/dist/types/http.d.ts +16 -1
  285. package/dist/types/http.js +1 -2
  286. package/dist/types/logger.d.ts +7 -0
  287. package/dist/types/logger.js +1 -2
  288. package/dist/types/module.d.ts +11 -0
  289. package/dist/types/module.js +1 -2
  290. package/dist/types/runtime.d.ts +1 -1
  291. package/dist/types/runtime.js +1 -2
  292. package/dist/types/session.js +1 -2
  293. package/jest.config.mjs +41 -0
  294. package/package.json +19 -52
  295. package/src/core/auth/morojs-adapter.ts +18 -13
  296. package/src/core/config/config-manager.ts +133 -0
  297. package/src/core/config/config-sources.ts +600 -0
  298. package/src/core/config/config-validator.ts +1116 -0
  299. package/src/core/config/file-loader.ts +16 -273
  300. package/src/core/config/index.ts +83 -34
  301. package/src/core/config/schema.ts +47 -33
  302. package/src/core/config/utils.ts +24 -31
  303. package/src/core/database/README.md +26 -16
  304. package/src/core/database/adapters/drizzle.ts +18 -6
  305. package/src/core/database/adapters/index.ts +13 -13
  306. package/src/core/database/adapters/mongodb.ts +53 -5
  307. package/src/core/database/adapters/mysql.ts +32 -4
  308. package/src/core/database/adapters/postgresql.ts +30 -5
  309. package/src/core/database/adapters/redis.ts +61 -8
  310. package/src/core/database/adapters/sqlite.ts +19 -3
  311. package/src/core/database/index.ts +2 -2
  312. package/src/core/docs/index.ts +8 -8
  313. package/src/core/docs/openapi-generator.ts +4 -4
  314. package/src/core/docs/schema-to-openapi.ts +3 -6
  315. package/src/core/docs/simple-docs.ts +2 -2
  316. package/src/core/docs/swagger-ui.ts +19 -16
  317. package/src/core/docs/zod-to-openapi.ts +34 -34
  318. package/src/core/events/event-bus.ts +3 -3
  319. package/src/core/events/index.ts +2 -2
  320. package/src/core/framework.ts +320 -71
  321. package/src/core/http/http-server.ts +203 -143
  322. package/src/core/http/index.ts +4 -3
  323. package/src/core/http/uws-http-server.ts +591 -0
  324. package/src/core/logger/filters.ts +13 -5
  325. package/src/core/logger/index.ts +4 -3
  326. package/src/core/logger/logger.ts +435 -216
  327. package/src/core/logger/outputs.ts +1 -3
  328. package/src/core/middleware/built-in/adapters/cache/file.ts +3 -3
  329. package/src/core/middleware/built-in/adapters/cache/index.ts +7 -7
  330. package/src/core/middleware/built-in/adapters/cache/memory.ts +2 -2
  331. package/src/core/middleware/built-in/adapters/cache/redis.ts +18 -4
  332. package/src/core/middleware/built-in/adapters/cdn/azure.ts +2 -2
  333. package/src/core/middleware/built-in/adapters/cdn/cloudflare.ts +2 -2
  334. package/src/core/middleware/built-in/adapters/cdn/cloudfront.ts +16 -5
  335. package/src/core/middleware/built-in/adapters/cdn/index.ts +7 -7
  336. package/src/core/middleware/built-in/adapters/index.ts +4 -4
  337. package/src/core/middleware/built-in/auth-helpers.ts +1 -1
  338. package/src/core/middleware/built-in/auth-providers.ts +1 -1
  339. package/src/core/middleware/built-in/auth.ts +102 -21
  340. package/src/core/middleware/built-in/cache.ts +8 -6
  341. package/src/core/middleware/built-in/cdn.ts +4 -4
  342. package/src/core/middleware/built-in/cookie.ts +2 -2
  343. package/src/core/middleware/built-in/cors.ts +2 -2
  344. package/src/core/middleware/built-in/csp.ts +3 -3
  345. package/src/core/middleware/built-in/csrf.ts +3 -3
  346. package/src/core/middleware/built-in/error-tracker.ts +1 -1
  347. package/src/core/middleware/built-in/index.ts +38 -30
  348. package/src/core/middleware/built-in/jwt-helpers.ts +243 -0
  349. package/src/core/middleware/built-in/performance-monitor.ts +1 -1
  350. package/src/core/middleware/built-in/rate-limit.ts +2 -2
  351. package/src/core/middleware/built-in/request-logger.ts +3 -1
  352. package/src/core/middleware/built-in/session.ts +7 -8
  353. package/src/core/middleware/built-in/sse.ts +11 -9
  354. package/src/core/middleware/built-in/validation.ts +2 -2
  355. package/src/core/middleware/index.ts +6 -6
  356. package/src/core/modules/auto-discovery.ts +478 -15
  357. package/src/core/modules/index.ts +2 -2
  358. package/src/core/modules/modules.ts +23 -12
  359. package/src/core/networking/adapters/index.ts +4 -3
  360. package/src/core/networking/adapters/socketio-adapter.ts +5 -3
  361. package/src/core/networking/adapters/uws-adapter.ts +619 -0
  362. package/src/core/networking/adapters/ws-adapter.ts +8 -9
  363. package/src/core/networking/index.ts +3 -2
  364. package/src/core/networking/service-discovery.ts +6 -7
  365. package/src/core/networking/websocket-manager.ts +7 -7
  366. package/src/core/pooling/object-pool-manager.ts +630 -0
  367. package/src/core/routing/app-integration.ts +60 -112
  368. package/src/core/routing/index.ts +66 -293
  369. package/src/core/routing/path-matcher.ts +222 -0
  370. package/src/core/routing/router.ts +97 -0
  371. package/src/core/routing/unified-router.ts +870 -0
  372. package/src/core/runtime/aws-lambda-adapter.ts +3 -3
  373. package/src/core/runtime/base-adapter.ts +2 -2
  374. package/src/core/runtime/cloudflare-workers-adapter.ts +3 -3
  375. package/src/core/runtime/index.ts +13 -13
  376. package/src/core/runtime/node-adapter.ts +16 -10
  377. package/src/core/runtime/vercel-edge-adapter.ts +3 -3
  378. package/src/core/utilities/hooks.ts +3 -3
  379. package/src/core/utilities/index.ts +5 -4
  380. package/src/core/utilities/package-utils.ts +59 -0
  381. package/src/core/validation/adapters.ts +1 -1
  382. package/src/core/validation/index.ts +68 -16
  383. package/src/index.ts +73 -66
  384. package/src/moro.ts +784 -253
  385. package/src/types/config.ts +74 -2
  386. package/src/types/core.ts +49 -47
  387. package/src/types/hooks.ts +1 -1
  388. package/src/types/http.ts +23 -1
  389. package/src/types/logger.ts +9 -0
  390. package/src/types/module.ts +12 -0
  391. package/src/types/runtime.ts +1 -1
  392. package/tsconfig.json +4 -2
  393. package/dist/core/config/loader.d.ts +0 -7
  394. package/dist/core/config/loader.js +0 -269
  395. package/dist/core/config/loader.js.map +0 -1
  396. package/dist/core/config/validation.d.ts +0 -17
  397. package/dist/core/config/validation.js +0 -131
  398. package/dist/core/config/validation.js.map +0 -1
  399. package/dist/core/http/router.d.ts +0 -14
  400. package/dist/core/http/router.js +0 -109
  401. package/dist/core/http/router.js.map +0 -1
  402. package/src/core/config/loader.ts +0 -633
  403. package/src/core/config/validation.ts +0 -140
  404. package/src/core/http/router.ts +0 -141
package/dist/moro.js CHANGED
@@ -1,154 +1,99 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.Moro = void 0;
37
- exports.createApp = createApp;
38
- exports.createAppNode = createAppNode;
39
- exports.createAppEdge = createAppEdge;
40
- exports.createAppLambda = createAppLambda;
41
- exports.createAppWorker = createAppWorker;
42
1
  // Moro Framework - Modern TypeScript API Framework
43
2
  // Built for developers who demand performance, elegance, and zero compromises
44
3
  // Event-driven • Modular • Enterprise-ready • Developer-first
45
- const framework_1 = require("./core/framework");
46
- const http_1 = require("./core/http");
47
- const logger_1 = require("./core/logger");
48
- const middleware_1 = require("./core/middleware");
49
- const app_integration_1 = require("./core/routing/app-integration");
50
- const docs_1 = require("./core/docs");
51
- const fs_1 = require("fs");
52
- const path_1 = require("path");
53
- const events_1 = require("events");
4
+ import { Moro as MoroCore } from './core/framework.js';
5
+ import { middleware } from './core/http/index.js';
6
+ import { createFrameworkLogger, applyLoggingConfiguration } from './core/logger/index.js';
7
+ import { MiddlewareManager } from './core/middleware/index.js';
8
+ import { IntelligentRoutingManager } from './core/routing/app-integration.js';
9
+ import { UnifiedRouter, } from './core/routing/unified-router.js';
10
+ import { AppDocumentationManager } from './core/docs/index.js';
11
+ import { EventEmitter } from 'events';
12
+ import cluster from 'cluster';
13
+ import os from 'os';
14
+ import { normalizeValidationError } from './core/validation/schema-interface.js';
54
15
  // Configuration System Integration
55
- const config_1 = require("./core/config");
16
+ import { initializeConfig } from './core/config/index.js';
56
17
  // Runtime System Integration
57
- const runtime_1 = require("./core/runtime");
58
- class Moro extends events_1.EventEmitter {
18
+ import { createRuntimeAdapter } from './core/runtime/index.js';
19
+ export class Moro extends EventEmitter {
59
20
  coreFramework;
60
21
  routes = [];
61
22
  moduleCounter = 0;
62
23
  loadedModules = new Set();
24
+ lazyModules = new Map();
63
25
  routeHandlers = {};
26
+ moduleDiscovery; // Store for cleanup
27
+ autoDiscoveryOptions = null;
28
+ autoDiscoveryInitialized = false;
29
+ autoDiscoveryPromise = null;
64
30
  // Enterprise event system integration
65
31
  eventBus;
66
32
  // Application logger
67
- logger = (0, logger_1.createFrameworkLogger)('App');
68
- // Intelligent routing system
69
- intelligentRouting = new app_integration_1.IntelligentRoutingManager();
33
+ logger;
34
+ // Unified routing system (singleton - shared across all routers)
35
+ unifiedRouter;
36
+ // Legacy intelligent routing (kept for backward compatibility, now a facade)
37
+ intelligentRouting;
70
38
  // Documentation system
71
- documentation = new docs_1.AppDocumentationManager();
39
+ documentation = new AppDocumentationManager();
72
40
  // Configuration system
73
41
  config;
42
+ // Track if user explicitly set logger options (for worker log level handling)
43
+ userSetLogger = false;
74
44
  // Runtime system
75
45
  runtimeAdapter;
76
46
  runtimeType;
77
47
  // Middleware system
78
48
  middlewareManager;
49
+ // Queued WebSocket registrations (for async adapter detection)
50
+ queuedWebSocketRegistrations = [];
79
51
  constructor(options = {}) {
80
52
  super(); // Call EventEmitter constructor
81
- // Configure logger from environment variables BEFORE config system initialization
82
- // This ensures the config loading process respects the log level
53
+ // Track if user explicitly set logger/logging options
54
+ this.userSetLogger = !!(options.logger || options.logging);
55
+ // Apply logging configuration BEFORE config loading to avoid DEBUG spam
56
+ // 1. Environment variables (base level)
83
57
  const envLogLevel = process.env.LOG_LEVEL || process.env.MORO_LOG_LEVEL;
84
58
  if (envLogLevel) {
85
- (0, logger_1.applyLoggingConfiguration)({ level: envLogLevel }, undefined);
86
- }
87
- // Initialize configuration system - create a deep copy for this instance
88
- this.config = JSON.parse(JSON.stringify((0, config_1.initializeConfig)()));
89
- // Apply logging configuration from the loaded config (this happens after config file processing)
90
- if (this.config.logging) {
91
- (0, logger_1.applyLoggingConfiguration)(this.config.logging, undefined);
59
+ applyLoggingConfiguration({ level: envLogLevel }, undefined);
92
60
  }
93
- // Apply additional logging configuration from createApp options (takes precedence)
61
+ // 2. createApp logger options (highest precedence)
94
62
  if (options.logger !== undefined) {
95
- (0, logger_1.applyLoggingConfiguration)(undefined, options.logger);
96
- }
97
- // Apply performance configuration from createApp options (takes precedence)
98
- if (options.performance) {
99
- if (options.performance.clustering) {
100
- this.config.performance.clustering = {
101
- ...this.config.performance.clustering,
102
- ...options.performance.clustering,
103
- };
104
- }
105
- if (options.performance.compression) {
106
- this.config.performance.compression = {
107
- ...this.config.performance.compression,
108
- ...options.performance.compression,
109
- };
110
- }
111
- if (options.performance.circuitBreaker) {
112
- this.config.performance.circuitBreaker = {
113
- ...this.config.performance.circuitBreaker,
114
- ...options.performance.circuitBreaker,
115
- };
116
- }
63
+ applyLoggingConfiguration(undefined, options.logger);
117
64
  }
118
- // Apply modules configuration from createApp options (takes precedence)
119
- if (options.modules) {
120
- if (options.modules.cache) {
121
- this.config.modules.cache = {
122
- ...this.config.modules.cache,
123
- ...options.modules.cache,
124
- };
125
- }
126
- if (options.modules.rateLimit) {
127
- this.config.modules.rateLimit = {
128
- ...this.config.modules.rateLimit,
129
- ...options.modules.rateLimit,
130
- };
131
- }
132
- if (options.modules.validation) {
133
- this.config.modules.validation = {
134
- ...this.config.modules.validation,
135
- ...options.modules.validation,
136
- };
137
- }
65
+ // Create logger AFTER initial configuration
66
+ this.logger = createFrameworkLogger('App');
67
+ // Use simplified global configuration system
68
+ this.config = initializeConfig(options);
69
+ // Apply final config logging (this includes normalized logger → logging conversion)
70
+ // Always apply this as it's the authoritative merged config
71
+ if (this.config.logging) {
72
+ applyLoggingConfiguration(this.config.logging, undefined);
73
+ // Recreate logger with updated config
74
+ this.logger = createFrameworkLogger('App');
138
75
  }
139
- this.logger.info(`Configuration system initialized: ${this.config.server.environment}:${this.config.server.port}`);
76
+ // NOW initialize routing systems AFTER logger is configured
77
+ this.unifiedRouter = UnifiedRouter.getInstance();
78
+ this.intelligentRouting = new IntelligentRoutingManager();
79
+ this.logger.info(`Configuration system initialized: ${process.env.NODE_ENV || 'development'}:${this.config.server.port}`);
140
80
  // Initialize runtime system
141
81
  this.runtimeType = options.runtime?.type || 'node';
142
- this.runtimeAdapter = options.runtime?.adapter || (0, runtime_1.createRuntimeAdapter)(this.runtimeType);
82
+ this.runtimeAdapter = options.runtime?.adapter || createRuntimeAdapter(this.runtimeType);
143
83
  this.logger.info(`Runtime system initialized: ${this.runtimeType}`, 'Runtime');
144
- // Pass logging configuration from config to framework
84
+ // Pass configuration from config to framework
145
85
  const frameworkOptions = {
146
86
  ...options,
147
87
  logger: this.config.logging,
88
+ // Enable websockets if either config has it enabled OR user passed websocket options
89
+ websocket: this.config.websocket.enabled || options.websocket
90
+ ? options.websocket || this.config.websocket || {}
91
+ : false,
92
+ config: this.config,
148
93
  };
149
- this.coreFramework = new framework_1.Moro(frameworkOptions);
94
+ this.coreFramework = new MoroCore(frameworkOptions);
150
95
  // Initialize middleware system
151
- this.middlewareManager = new middleware_1.MiddlewareManager();
96
+ this.middlewareManager = new MiddlewareManager();
152
97
  // Integrate hooks system with HTTP server
153
98
  const httpServer = this.coreFramework.httpServer;
154
99
  if (httpServer && httpServer.setHookManager) {
@@ -169,10 +114,10 @@ class Moro extends events_1.EventEmitter {
169
114
  ...this.getDefaultOptionsFromConfig(),
170
115
  ...options,
171
116
  });
172
- // Auto-discover modules if enabled
173
- if (options.autoDiscover !== false) {
174
- this.autoDiscoverModules(options.modulesPath || './modules');
175
- }
117
+ // Store auto-discovery options for later initialization
118
+ // IMPORTANT: Auto-discovery is deferred to ensure user middleware (like auth)
119
+ // is registered before module middleware that might bypass it
120
+ this.autoDiscoveryOptions = options.autoDiscover !== false ? options : null;
176
121
  // Emit initialization event through enterprise event bus
177
122
  this.eventBus.emit('framework:initialized', {
178
123
  options,
@@ -213,44 +158,45 @@ class Moro extends events_1.EventEmitter {
213
158
  // Direct route registration
214
159
  return this.addRoute('GET', path, handler, options);
215
160
  }
216
- // Chainable route builder
217
- return this.intelligentRouting.get(path);
161
+ // Use unified router for chainable API
162
+ return this.unifiedRouter.get(path);
218
163
  }
219
164
  post(path, handler, options) {
220
165
  if (handler) {
221
166
  // Direct route registration
222
167
  return this.addRoute('POST', path, handler, options);
223
168
  }
224
- // Chainable route builder
225
- return this.intelligentRouting.post(path);
169
+ // Use unified router for chainable API
170
+ return this.unifiedRouter.post(path);
226
171
  }
227
172
  put(path, handler, options) {
228
173
  if (handler) {
229
174
  // Direct route registration
230
175
  return this.addRoute('PUT', path, handler, options);
231
176
  }
232
- // Chainable route builder
233
- return this.intelligentRouting.put(path);
177
+ // Use unified router for chainable API
178
+ return this.unifiedRouter.put(path);
234
179
  }
235
180
  delete(path, handler, options) {
236
181
  if (handler) {
237
182
  // Direct route registration
238
183
  return this.addRoute('DELETE', path, handler, options);
239
184
  }
240
- // Chainable route builder
241
- return this.intelligentRouting.delete(path);
185
+ // Use unified router for chainable API
186
+ return this.unifiedRouter.delete(path);
242
187
  }
243
188
  patch(path, handler, options) {
244
189
  if (handler) {
245
190
  // Direct route registration
246
191
  return this.addRoute('PATCH', path, handler, options);
247
192
  }
248
- // Chainable route builder
249
- return this.intelligentRouting.patch(path);
193
+ // Use unified router for chainable API
194
+ return this.unifiedRouter.patch(path);
250
195
  }
251
196
  // Schema-first route method
252
197
  route(schema) {
253
- return this.intelligentRouting.route(schema);
198
+ // Use unified router for schema-first registration
199
+ this.unifiedRouter.route(schema);
254
200
  }
255
201
  // Enable automatic API documentation
256
202
  enableDocs(config) {
@@ -338,6 +284,11 @@ class Moro extends events_1.EventEmitter {
338
284
  version: moduleOrPath.version || '1.0.0',
339
285
  });
340
286
  }
287
+ // IMPORTANT: If modules are loaded manually after auto-discovery,
288
+ // ensure the final module handler is set up to maintain middleware order
289
+ if (this.autoDiscoveryInitialized) {
290
+ this.coreFramework.setupFinalModuleHandler();
291
+ }
341
292
  return this;
342
293
  }
343
294
  // Database helper with events
@@ -351,29 +302,36 @@ class Moro extends events_1.EventEmitter {
351
302
  }
352
303
  // WebSocket helper with events
353
304
  websocket(namespace, handlers) {
305
+ // Queue the registration to be processed after adapter initialization
306
+ const registration = { namespace, handlers, processed: false };
307
+ this.queuedWebSocketRegistrations.push(registration);
308
+ // Try to process immediately if adapter is already ready
354
309
  const adapter = this.coreFramework.getWebSocketAdapter();
355
- if (!adapter) {
356
- throw new Error('WebSocket features require a WebSocket adapter. Install socket.io or configure an adapter:\n' +
357
- 'npm install socket.io\n' +
358
- 'or\n' +
359
- 'new Moro({ websocket: { adapter: new SocketIOAdapter() } })');
310
+ if (adapter && !registration.processed) {
311
+ // Adapter is ready, process immediately
312
+ this.processWebSocketRegistration(namespace, handlers, adapter);
313
+ registration.processed = true;
360
314
  }
315
+ // Otherwise, it will be processed when the server starts
316
+ return this;
317
+ }
318
+ processWebSocketRegistration(namespace, handlers, adapter) {
361
319
  this.emit('websocket:registering', { namespace, handlers });
362
320
  const ns = adapter.createNamespace(namespace);
363
321
  Object.entries(handlers).forEach(([event, handler]) => {
364
- ns.on('connection', socket => {
322
+ ns.on('connection', (socket) => {
365
323
  this.emit('websocket:connection', { namespace, event, socket });
366
324
  socket.on(event, (data, callback) => {
367
325
  this.emit('websocket:event', { namespace, event, data });
368
326
  Promise.resolve(handler(socket, data))
369
- .then(result => {
327
+ .then((result) => {
370
328
  this.emit('websocket:response', { namespace, event, result });
371
329
  if (callback)
372
330
  callback(result);
373
331
  else if (result)
374
332
  socket.emit(`${event}:response`, result);
375
333
  })
376
- .catch(error => {
334
+ .catch((error) => {
377
335
  this.emit('websocket:error', { namespace, event, error });
378
336
  const errorResponse = { success: false, error: error.message };
379
337
  if (callback)
@@ -385,7 +343,33 @@ class Moro extends events_1.EventEmitter {
385
343
  });
386
344
  });
387
345
  this.emit('websocket:registered', { namespace, handlers });
388
- return this;
346
+ }
347
+ async processQueuedWebSocketRegistrations() {
348
+ // Wait for WebSocket adapter to be ready
349
+ await this.coreFramework.ensureWebSocketReady();
350
+ const adapter = this.coreFramework.getWebSocketAdapter();
351
+ // Check if any unprocessed registrations exist
352
+ const unprocessedRegistrations = this.queuedWebSocketRegistrations.filter(r => !r.processed);
353
+ if (!adapter && unprocessedRegistrations.length > 0) {
354
+ throw new Error('WebSocket features require a WebSocket adapter.\n\n' +
355
+ 'Option 1: Install socket.io (auto-detected):\n' +
356
+ ' npm install socket.io\n' +
357
+ ' const app = new Moro({ websocket: {} });\n\n' +
358
+ 'Option 2: Configure a specific adapter:\n' +
359
+ " import { SocketIOAdapter } from '@morojs/moro';\n" +
360
+ ' const app = new Moro({ websocket: { adapter: new SocketIOAdapter() } });\n\n' +
361
+ 'Option 3: Enable in config file (moro.config.js):\n' +
362
+ ' export default { websocket: { enabled: true } };');
363
+ }
364
+ if (adapter) {
365
+ // Process all unprocessed registrations
366
+ for (const registration of this.queuedWebSocketRegistrations) {
367
+ if (!registration.processed) {
368
+ this.processWebSocketRegistration(registration.namespace, registration.handlers, adapter);
369
+ registration.processed = true;
370
+ }
371
+ }
372
+ }
389
373
  }
390
374
  listen(portOrCallback, hostOrCallback, callback) {
391
375
  // Only available for Node.js runtime
@@ -427,9 +411,18 @@ class Moro extends events_1.EventEmitter {
427
411
  throw new Error('Port not specified and not found in configuration. Please provide a port number or configure it in moro.config.js/ts');
428
412
  }
429
413
  // Check if clustering is enabled for massive performance gains
414
+ // NOTE: uWebSockets.js does NOT support Node.js clustering - it's single-threaded only
415
+ const usingUWebSockets = this.config.server?.useUWebSockets || false;
430
416
  if (this.config.performance?.clustering?.enabled) {
431
- this.startWithClustering(port, host, callback);
432
- return;
417
+ if (usingUWebSockets) {
418
+ this.logger.warn('Clustering is not supported with uWebSockets.js - running in single-threaded mode. ' +
419
+ 'uWebSockets is so fast that single-threaded performance often exceeds multi-threaded Node.js!', 'Cluster');
420
+ // Continue without clustering
421
+ }
422
+ else {
423
+ this.startWithClustering(port, host, callback);
424
+ return;
425
+ }
433
426
  }
434
427
  this.eventBus.emit('server:starting', { port, runtime: this.runtimeType });
435
428
  // Add documentation middleware first (if enabled)
@@ -442,44 +435,168 @@ class Moro extends events_1.EventEmitter {
442
435
  // Documentation not enabled, that's fine
443
436
  this.logger.debug('Documentation not enabled', 'Documentation');
444
437
  }
445
- // Add intelligent routing middleware to handle chainable routes
446
- this.coreFramework.addMiddleware(async (req, res, next) => {
447
- // Try intelligent routing first
448
- const handled = await this.intelligentRouting.handleIntelligentRoute(req, res);
449
- if (!handled) {
450
- next(); // Fall back to direct routes
438
+ // Add unified routing middleware (handles both chainable and direct routes)
439
+ // Optimized: call router without extra async wrapper when possible
440
+ this.coreFramework.addMiddleware((req, res, next) => {
441
+ // Try unified router first (handles all route types)
442
+ const handled = this.unifiedRouter.handleRequest(req, res);
443
+ // Check if it's a promise (async route) or sync
444
+ if (handled && typeof handled.then === 'function') {
445
+ // Async - await the result
446
+ handled
447
+ .then(isHandled => {
448
+ if (!isHandled) {
449
+ next(); // Fall back to legacy routes if any
450
+ }
451
+ })
452
+ .catch(() => next());
453
+ }
454
+ else {
455
+ // Sync - check immediately
456
+ if (!handled) {
457
+ next();
458
+ }
451
459
  }
452
460
  });
453
- // Register direct routes with the HTTP server
461
+ // Register legacy direct routes with the HTTP server (for backward compatibility)
454
462
  if (this.routes.length > 0) {
455
463
  this.registerDirectRoutes();
456
464
  }
457
- const actualCallback = () => {
458
- const displayHost = host || 'localhost';
459
- this.logger.info('Moro Server Started', 'Server');
460
- this.logger.info(`Runtime: ${this.runtimeType}`, 'Server');
461
- this.logger.info(`HTTP API: http://${displayHost}:${port}`, 'Server');
462
- this.logger.info(`WebSocket: ws://${displayHost}:${port}`, 'Server');
463
- this.logger.info('Native Node.js HTTP • Zero Dependencies • Maximum Performance', 'Server');
464
- this.logger.info('Learn more at https://morojs.com', 'Server');
465
- // Log intelligent routes info
466
- const intelligentRoutes = this.intelligentRouting.getIntelligentRoutes();
467
- if (intelligentRoutes.length > 0) {
468
- this.logger.info(`Intelligent Routes: ${intelligentRoutes.length} registered`, 'Server');
465
+ const startServer = () => {
466
+ const actualCallback = () => {
467
+ const displayHost = host || 'localhost';
468
+ this.logger.info('Moro Server Started', 'Server');
469
+ this.logger.info(`Runtime: ${this.runtimeType}`, 'Server');
470
+ this.logger.info(`HTTP API: http://${displayHost}:${port}`, 'Server');
471
+ if (this.config.websocket.enabled) {
472
+ this.logger.info(`WebSocket: ws://${displayHost}:${port}`, 'Server');
473
+ }
474
+ this.logger.info('Learn more at https://morojs.com', 'Server');
475
+ // Log unified router stats
476
+ const routeCount = this.unifiedRouter.getRouteCount();
477
+ if (routeCount > 0) {
478
+ this.logger.info(`Unified Router: ${routeCount} routes registered`, 'Server');
479
+ // Log performance stats
480
+ this.unifiedRouter.logPerformanceStats();
481
+ }
482
+ this.eventBus.emit('server:started', { port, runtime: this.runtimeType });
483
+ if (callback)
484
+ callback();
485
+ };
486
+ if (host && typeof host === 'string') {
487
+ this.coreFramework.listen(port, host, actualCallback);
488
+ }
489
+ else {
490
+ this.coreFramework.listen(port, actualCallback);
469
491
  }
470
- this.eventBus.emit('server:started', { port, runtime: this.runtimeType });
471
- if (callback)
472
- callback();
473
492
  };
474
- if (host && typeof host === 'string') {
475
- this.coreFramework.listen(port, host, actualCallback);
493
+ // Ensure auto-discovery and WebSocket setup is complete before starting server
494
+ Promise.all([this.ensureAutoDiscoveryComplete(), this.processQueuedWebSocketRegistrations()])
495
+ .then(() => {
496
+ startServer();
497
+ })
498
+ .catch(error => {
499
+ this.logger.error('Initialization failed during server start', 'Framework', {
500
+ error: error instanceof Error ? error.message : String(error),
501
+ });
502
+ // For auto-discovery failures, start server anyway
503
+ // For WebSocket failures with queued registrations, error will propagate
504
+ if (error instanceof Error &&
505
+ error.message.includes('WebSocket features require a WebSocket adapter')) {
506
+ throw error;
507
+ }
508
+ startServer();
509
+ });
510
+ }
511
+ // Public method to manually initialize auto-discovery
512
+ // Useful for ensuring auth middleware is registered before auto-discovery
513
+ async initializeAutoDiscoveryNow() {
514
+ return this.ensureAutoDiscoveryComplete();
515
+ }
516
+ // Public API: Initialize modules explicitly after middleware setup
517
+ // This provides users with explicit control over module loading timing
518
+ // IMPORTANT: This forces module loading even if autoDiscovery.enabled is false
519
+ // Usage: app.initModules() or app.initModules({ paths: ['./my-modules'] })
520
+ initModules(options) {
521
+ this.logger.info('User-requested module initialization', 'ModuleSystem');
522
+ // If already initialized, do nothing
523
+ if (this.autoDiscoveryInitialized) {
524
+ this.logger.debug('Auto-discovery already completed, skipping', 'ModuleSystem');
525
+ return;
476
526
  }
477
- else {
478
- this.coreFramework.listen(port, actualCallback);
527
+ // Store the options and mark that we want to force initialization
528
+ this.autoDiscoveryOptions = {
529
+ autoDiscover: {
530
+ enabled: true, // Force enabled regardless of original config
531
+ paths: options?.paths || ['./modules', './src/modules'],
532
+ patterns: options?.patterns || [
533
+ '**/*.module.{ts,js}',
534
+ '**/index.{ts,js}',
535
+ '**/*.config.{ts,js}',
536
+ ],
537
+ recursive: options?.recursive ?? true,
538
+ loadingStrategy: options?.loadingStrategy || 'eager',
539
+ watchForChanges: options?.watchForChanges ?? false,
540
+ ignorePatterns: options?.ignorePatterns || [
541
+ '**/*.test.{ts,js}',
542
+ '**/*.spec.{ts,js}',
543
+ '**/node_modules/**',
544
+ ],
545
+ loadOrder: options?.loadOrder || 'dependency',
546
+ failOnError: options?.failOnError ?? false,
547
+ maxDepth: options?.maxDepth ?? 5,
548
+ },
549
+ };
550
+ this.logger.debug('Module initialization options stored, will execute on next listen/getHandler call', 'ModuleSystem');
551
+ }
552
+ // Robust method to ensure auto-discovery is complete, handling race conditions
553
+ async ensureAutoDiscoveryComplete() {
554
+ // If already initialized, nothing to do
555
+ if (this.autoDiscoveryInitialized) {
556
+ return;
479
557
  }
558
+ // If auto-discovery is disabled, mark as initialized
559
+ if (!this.autoDiscoveryOptions) {
560
+ this.autoDiscoveryInitialized = true;
561
+ return;
562
+ }
563
+ // If already in progress, wait for it to complete
564
+ if (this.autoDiscoveryPromise) {
565
+ return this.autoDiscoveryPromise;
566
+ }
567
+ // Start auto-discovery
568
+ this.autoDiscoveryPromise = this.performAutoDiscovery();
569
+ try {
570
+ await this.autoDiscoveryPromise;
571
+ this.autoDiscoveryInitialized = true;
572
+ }
573
+ catch (error) {
574
+ // Reset promise on error so it can be retried
575
+ this.autoDiscoveryPromise = null;
576
+ throw error;
577
+ }
578
+ finally {
579
+ this.autoDiscoveryOptions = null; // Clear after attempt
580
+ }
581
+ }
582
+ // Perform the actual auto-discovery work
583
+ async performAutoDiscovery(optionsOverride) {
584
+ const optionsToUse = optionsOverride || this.autoDiscoveryOptions;
585
+ if (!optionsToUse)
586
+ return;
587
+ this.logger.debug('Starting auto-discovery initialization', 'AutoDiscovery');
588
+ await this.initializeAutoDiscovery(optionsToUse);
589
+ this.logger.debug('Auto-discovery initialization completed', 'AutoDiscovery');
480
590
  }
481
591
  // Get handler for non-Node.js runtimes
482
592
  getHandler() {
593
+ // Ensure auto-discovery is complete for non-Node.js runtimes
594
+ // This handles the case where users call getHandler() immediately after createApp()
595
+ this.ensureAutoDiscoveryComplete().catch(error => {
596
+ this.logger.error('Auto-discovery initialization failed for runtime handler', 'Framework', {
597
+ error: error instanceof Error ? error.message : String(error),
598
+ });
599
+ });
483
600
  // Create a unified request handler that works with the runtime adapter
484
601
  const handler = async (req, res) => {
485
602
  // Add documentation middleware first (if enabled)
@@ -492,11 +609,11 @@ class Moro extends events_1.EventEmitter {
492
609
  catch (error) {
493
610
  // Documentation not enabled, that's fine
494
611
  }
495
- // Try intelligent routing first
496
- const handled = await this.intelligentRouting.handleIntelligentRoute(req, res);
612
+ // Try unified router first (handles all routes)
613
+ const handled = await this.unifiedRouter.handleRequest(req, res);
497
614
  if (handled)
498
615
  return;
499
- // Handle direct routes
616
+ // Handle legacy direct routes (backward compatibility)
500
617
  if (this.routes.length > 0) {
501
618
  await this.handleDirectRoutes(req, res);
502
619
  }
@@ -644,6 +761,9 @@ class Moro extends events_1.EventEmitter {
644
761
  }
645
762
  // Private methods
646
763
  addRoute(method, path, handler, options = {}) {
764
+ // Register with unified router (primary routing system)
765
+ this.unifiedRouter.addRoute(method, path, handler, options.middleware || []);
766
+ // Also store in legacy routes array for backward compatibility
647
767
  const handlerName = `handler_${this.routes.length}`;
648
768
  const route = {
649
769
  method: method,
@@ -655,9 +775,9 @@ class Moro extends events_1.EventEmitter {
655
775
  middleware: options.middleware,
656
776
  };
657
777
  this.routes.push(route);
658
- // Organize routes for optimal lookup
778
+ // Organize routes for optimal lookup (legacy)
659
779
  this.organizeRouteForLookup(route);
660
- // Store handler for later module creation
780
+ // Store handler for later module creation (legacy)
661
781
  this.routeHandlers[handlerName] = handler;
662
782
  return this;
663
783
  }
@@ -697,7 +817,6 @@ class Moro extends events_1.EventEmitter {
697
817
  }
698
818
  catch (error) {
699
819
  // Handle universal validation errors
700
- const { normalizeValidationError } = require('./core/validation/schema-interface');
701
820
  const normalizedError = normalizeValidationError(error);
702
821
  res.status(400).json({
703
822
  success: false,
@@ -767,91 +886,266 @@ class Moro extends events_1.EventEmitter {
767
886
  return true;
768
887
  }
769
888
  setupDefaultMiddleware(options) {
770
- // CORS
771
- if (options.cors !== false) {
772
- const corsOptions = typeof options.cors === 'object' ? options.cors : {};
773
- this.use(http_1.middleware.cors(corsOptions));
889
+ // CORS - check config enabled property OR options.security.cors.enabled === true
890
+ if (this.config.security.cors.enabled || options.security?.cors?.enabled === true) {
891
+ const corsOptions = typeof options.cors === 'object'
892
+ ? options.cors
893
+ : this.config.security.cors
894
+ ? this.config.security.cors
895
+ : {};
896
+ this.use(middleware.cors(corsOptions));
774
897
  }
775
- // Helmet
776
- if (options.helmet !== false) {
777
- this.use(http_1.middleware.helmet());
898
+ // Helmet - check config enabled property OR options.security.helmet.enabled === true
899
+ if (this.config.security.helmet.enabled || options.security?.helmet?.enabled === true) {
900
+ this.use(middleware.helmet());
778
901
  }
779
- // Compression
780
- if (options.compression !== false) {
781
- const compressionOptions = typeof options.compression === 'object' ? options.compression : {};
782
- this.use(http_1.middleware.compression(compressionOptions));
902
+ // Compression - check config enabled property OR options.performance.compression.enabled === true
903
+ if (this.config.performance.compression.enabled ||
904
+ options.performance?.compression?.enabled === true) {
905
+ const compressionOptions = typeof options.compression === 'object'
906
+ ? options.compression
907
+ : this.config.performance.compression
908
+ ? this.config.performance.compression
909
+ : {};
910
+ this.use(middleware.compression(compressionOptions));
783
911
  }
784
912
  // Body size limiting
785
- this.use(http_1.middleware.bodySize({ limit: '10mb' }));
913
+ this.use(middleware.bodySize({ limit: '10mb' }));
786
914
  }
787
- autoDiscoverModules(modulesPath) {
915
+ // Enhanced auto-discovery initialization
916
+ async initializeAutoDiscovery(options) {
917
+ const { ModuleDiscovery } = await import('./core/modules/auto-discovery.js');
918
+ // Merge auto-discovery configuration
919
+ const autoDiscoveryConfig = this.mergeAutoDiscoveryConfig(options);
920
+ if (!autoDiscoveryConfig.enabled) {
921
+ return;
922
+ }
923
+ this.moduleDiscovery = new ModuleDiscovery(process.cwd());
788
924
  try {
789
- if (!(0, fs_1.statSync)(modulesPath).isDirectory())
790
- return;
791
- const items = (0, fs_1.readdirSync)(modulesPath);
792
- items.forEach(item => {
793
- const fullPath = (0, path_1.join)(modulesPath, item);
794
- if ((0, fs_1.statSync)(fullPath).isDirectory()) {
795
- const indexPath = (0, path_1.join)(fullPath, 'index.ts');
796
- try {
797
- (0, fs_1.statSync)(indexPath);
798
- // Module directory found, will be loaded later
799
- this.logger.debug(`Discovered module: ${item}`, 'ModuleDiscovery');
800
- }
801
- catch {
802
- // No index.ts, skip
803
- }
925
+ // Discover modules based on configuration
926
+ const modules = await this.moduleDiscovery.discoverModulesAdvanced(autoDiscoveryConfig);
927
+ // Load modules based on strategy
928
+ await this.loadDiscoveredModules(modules, autoDiscoveryConfig);
929
+ // Setup final module handler to run after user middleware (like auth)
930
+ this.coreFramework.setupFinalModuleHandler();
931
+ // Setup file watching if enabled
932
+ if (autoDiscoveryConfig.watchForChanges) {
933
+ this.moduleDiscovery.watchModulesAdvanced(autoDiscoveryConfig, async (updatedModules) => {
934
+ await this.handleModuleChanges(updatedModules);
935
+ });
936
+ }
937
+ this.logger.info(`Auto-discovery completed: ${modules.length} modules loaded`, 'ModuleDiscovery');
938
+ }
939
+ catch (error) {
940
+ const errorMsg = error instanceof Error ? error.message : String(error);
941
+ if (autoDiscoveryConfig.failOnError) {
942
+ throw new Error(`Module auto-discovery failed: ${errorMsg}`);
943
+ }
944
+ else {
945
+ this.logger.warn(`Module auto-discovery failed: ${errorMsg}`, 'ModuleDiscovery');
946
+ }
947
+ }
948
+ }
949
+ // Merge auto-discovery configuration from multiple sources
950
+ mergeAutoDiscoveryConfig(options) {
951
+ const defaultConfig = this.config.modules.autoDiscovery;
952
+ // Handle legacy modulesPath option
953
+ if (options.modulesPath && !options.autoDiscover) {
954
+ return {
955
+ ...defaultConfig,
956
+ paths: [options.modulesPath],
957
+ };
958
+ }
959
+ // Handle boolean autoDiscover option
960
+ if (typeof options.autoDiscover === 'boolean') {
961
+ return {
962
+ ...defaultConfig,
963
+ enabled: options.autoDiscover,
964
+ };
965
+ }
966
+ // Handle object autoDiscover option
967
+ if (typeof options.autoDiscover === 'object') {
968
+ return {
969
+ ...defaultConfig,
970
+ ...options.autoDiscover,
971
+ };
972
+ }
973
+ return defaultConfig;
974
+ }
975
+ // Load discovered modules based on strategy
976
+ async loadDiscoveredModules(modules, config) {
977
+ switch (config.loadingStrategy) {
978
+ case 'eager':
979
+ // Load all modules immediately
980
+ for (const module of modules) {
981
+ await this.loadModule(module);
982
+ }
983
+ break;
984
+ case 'lazy':
985
+ // Register modules for lazy loading
986
+ this.registerLazyModules(modules);
987
+ break;
988
+ case 'conditional':
989
+ // Load modules based on conditions
990
+ await this.loadConditionalModules(modules);
991
+ break;
992
+ default:
993
+ // Default to eager loading
994
+ for (const module of modules) {
995
+ await this.loadModule(module);
804
996
  }
805
- });
806
997
  }
807
- catch {
808
- // Modules directory doesn't exist, that's fine
998
+ }
999
+ // Register modules for lazy loading
1000
+ registerLazyModules(modules) {
1001
+ modules.forEach(module => {
1002
+ // Store module for lazy loading when first route is accessed
1003
+ this.lazyModules.set(module.name, module);
1004
+ // Register placeholder routes that trigger lazy loading
1005
+ if (module.routes) {
1006
+ module.routes.forEach(route => {
1007
+ const basePath = `/api/v${module.version}/${module.name}`;
1008
+ const fullPath = `${basePath}${route.path}`;
1009
+ // Note: Lazy loading will be implemented when route is accessed
1010
+ // For now, we'll store the module for later loading
1011
+ this.logger.debug(`Registered lazy route: ${route.method} ${fullPath}`, 'ModuleDiscovery');
1012
+ });
1013
+ }
1014
+ });
1015
+ this.logger.info(`Registered ${modules.length} modules for lazy loading`, 'ModuleDiscovery');
1016
+ }
1017
+ // Load modules conditionally based on environment or configuration
1018
+ async loadConditionalModules(modules) {
1019
+ for (const module of modules) {
1020
+ const shouldLoad = this.shouldLoadModule(module);
1021
+ if (shouldLoad) {
1022
+ await this.loadModule(module);
1023
+ }
1024
+ else {
1025
+ this.logger.debug(`Skipping module ${module.name} due to conditions`, 'ModuleDiscovery');
1026
+ }
809
1027
  }
810
1028
  }
1029
+ // Determine if a module should be loaded based on conditions
1030
+ shouldLoadModule(module) {
1031
+ const moduleConfig = module.config;
1032
+ // Check environment conditions
1033
+ if (moduleConfig?.conditions?.environment) {
1034
+ const requiredEnv = moduleConfig.conditions.environment;
1035
+ const currentEnv = process.env.NODE_ENV || 'development';
1036
+ if (Array.isArray(requiredEnv)) {
1037
+ if (!requiredEnv.includes(currentEnv)) {
1038
+ return false;
1039
+ }
1040
+ }
1041
+ else if (requiredEnv !== currentEnv) {
1042
+ return false;
1043
+ }
1044
+ }
1045
+ // Check feature flags
1046
+ if (moduleConfig?.conditions?.features) {
1047
+ const requiredFeatures = moduleConfig.conditions.features;
1048
+ for (const feature of requiredFeatures) {
1049
+ if (!process.env[`FEATURE_${feature.toUpperCase()}`]) {
1050
+ return false;
1051
+ }
1052
+ }
1053
+ }
1054
+ // Check custom conditions
1055
+ if (moduleConfig?.conditions?.custom) {
1056
+ const customCondition = moduleConfig.conditions.custom;
1057
+ if (typeof customCondition === 'function') {
1058
+ return customCondition();
1059
+ }
1060
+ }
1061
+ return true;
1062
+ }
1063
+ // Handle module changes during development
1064
+ async handleModuleChanges(modules) {
1065
+ this.logger.info('Module changes detected, reloading...', 'ModuleDiscovery');
1066
+ // Unload existing modules (if supported)
1067
+ // For now, just log the change
1068
+ this.eventBus.emit('modules:changed', {
1069
+ modules: modules.map(m => ({ name: m.name, version: m.version })),
1070
+ timestamp: new Date(),
1071
+ });
1072
+ }
1073
+ // Legacy method for backward compatibility
1074
+ autoDiscoverModules(modulesPath) {
1075
+ // Redirect to new system
1076
+ this.initializeAutoDiscovery({
1077
+ autoDiscover: {
1078
+ enabled: true,
1079
+ paths: [modulesPath],
1080
+ },
1081
+ });
1082
+ }
811
1083
  async importModule(modulePath) {
812
- const module = await Promise.resolve(`${modulePath}`).then(s => __importStar(require(s)));
1084
+ const module = await import(modulePath);
813
1085
  return module.default || module;
814
1086
  }
815
- // Clustering support for massive performance gains with proper cleanup
1087
+ /**
1088
+ * Node.js Clustering Implementation
1089
+ * This clustering algorithm is based on published research and Node.js best practices.
1090
+ *
1091
+ * IPC (Inter-Process Communication) Considerations:
1092
+ * - Excessive workers create IPC bottlenecks (Source: BetterStack Node.js Guide)
1093
+ * - Round-robin scheduling provides better load distribution (Node.js Documentation)
1094
+ * - Message passing overhead increases significantly with worker count
1095
+ *
1096
+ * Memory Management:
1097
+ * - ~2GB per worker prevents memory pressure and GC overhead
1098
+ * - Conservative heap limits reduce memory fragmentation
1099
+ *
1100
+ * References:
1101
+ * - Node.js Cluster Documentation: https://nodejs.org/api/cluster.html
1102
+ * - BetterStack Node.js Clustering: https://betterstack.com/community/guides/scaling-nodejs/node-clustering/
1103
+ */
816
1104
  clusterWorkers = new Map();
817
1105
  startWithClustering(port, host, callback) {
818
- const cluster = require('cluster');
819
- const os = require('os');
820
- // Smart worker count calculation based on actual bottlenecks
1106
+ // Worker count calculation - respect user choice
821
1107
  let workerCount = this.config.performance?.clustering?.workers || os.cpus().length;
822
- // Auto-optimize worker count based on system characteristics
823
- if (workerCount === 'auto' || workerCount > 8) {
824
- // For high-core machines, limit workers to prevent IPC/memory bottlenecks
1108
+ // Only auto-optimize if user hasn't specified a number or set it to 'auto'
1109
+ if (workerCount === 'auto') {
825
1110
  const cpuCount = os.cpus().length;
826
1111
  const totalMemoryGB = os.totalmem() / (1024 * 1024 * 1024);
827
- // Optimal worker count formula based on research
828
- if (cpuCount >= 16) {
829
- // High-core machines: focus on memory/IPC efficiency
830
- workerCount = Math.min(Math.ceil(totalMemoryGB / 2), 4); // 2GB per worker max, cap at 4
831
- }
832
- else if (cpuCount >= 8) {
833
- // Mid-range machines: balanced approach
834
- workerCount = Math.min(cpuCount / 2, 4);
1112
+ // Get memory per worker from config - if not set by user, calculate dynamically
1113
+ let memoryPerWorkerGB = this.config.performance?.clustering?.memoryPerWorkerGB;
1114
+ if (!memoryPerWorkerGB) {
1115
+ // Dynamic calculation: (Total RAM - 4GB headroom) / CPU cores
1116
+ const headroomGB = 4;
1117
+ memoryPerWorkerGB = Math.max(0.5, Math.floor((totalMemoryGB - headroomGB) / cpuCount));
835
1118
  }
836
- else {
837
- // Low-core machines: use all cores
838
- workerCount = cpuCount;
839
- }
840
- this.logger.info(`Auto-optimized workers: ${workerCount} (CPU: ${cpuCount}, RAM: ${totalMemoryGB.toFixed(1)}GB)`, 'Cluster');
1119
+ // Conservative formula based on general guidelines:
1120
+ // - Don't exceed CPU cores
1121
+ // - Respect user's memory allocation preference
1122
+ // - Let the system resources determine the limit
1123
+ workerCount = Math.min(cpuCount, // Don't exceed CPU cores
1124
+ Math.floor(totalMemoryGB / memoryPerWorkerGB) // User-configurable memory per worker
1125
+ );
1126
+ this.logger.info(`Auto-calculated worker count: ${workerCount} (CPU: ${cpuCount}, RAM: ${totalMemoryGB.toFixed(1)}GB, ${memoryPerWorkerGB}GB per worker)`, 'Cluster');
1127
+ }
1128
+ else if (typeof workerCount === 'number') {
1129
+ // User specified a number - respect their choice
1130
+ this.logger.info(`Using user-specified worker count: ${workerCount}`, 'Cluster');
841
1131
  }
842
1132
  if (cluster.isPrimary) {
843
- this.logger.info(`🚀 Starting ${workerCount} workers for maximum performance`, 'Cluster');
1133
+ this.logger.info(`Starting ${workerCount} workers`, 'Cluster');
844
1134
  // Optimize cluster scheduling for high concurrency
845
- cluster.schedulingPolicy = cluster.SCHED_RR; // Round-robin scheduling
1135
+ // Round-robin is the default on all platforms except Windows (Node.js docs)
1136
+ // Provides better load distribution than shared socket approach
1137
+ cluster.schedulingPolicy = cluster.SCHED_RR;
846
1138
  // Set cluster settings for better performance
847
1139
  cluster.setupMaster({
848
- exec: process.argv[1],
1140
+ exec: process.argv[1] || process.execPath,
849
1141
  args: process.argv.slice(2),
850
1142
  silent: false,
851
1143
  });
852
- // Optimize IPC to reduce communication overhead
1144
+ // IPC Optimization: Reduce communication overhead between master and workers
1145
+ // Research shows excessive IPC can create bottlenecks in clustered applications
1146
+ // (Source: BetterStack - Node.js Clustering Guide)
853
1147
  process.env.NODE_CLUSTER_SCHED_POLICY = 'rr'; // Ensure round-robin
854
- process.env.NODE_DISABLE_COLORS = '1'; // Reduce IPC message size
1148
+ process.env.NODE_DISABLE_COLORS = '1'; // Reduce IPC message size by disabling color codes
855
1149
  // Graceful shutdown handler
856
1150
  const gracefulShutdown = () => {
857
1151
  this.logger.info('Gracefully shutting down cluster...', 'Cluster');
@@ -867,27 +1161,25 @@ class Moro extends events_1.EventEmitter {
867
1161
  // Handle process signals for graceful shutdown
868
1162
  process.on('SIGINT', gracefulShutdown);
869
1163
  process.on('SIGTERM', gracefulShutdown);
870
- // Fork workers with proper tracking and CPU affinity
1164
+ // Fork workers with basic tracking
871
1165
  for (let i = 0; i < workerCount; i++) {
872
- const worker = cluster.fork({
873
- WORKER_ID: i,
874
- WORKER_CPU_AFFINITY: i % os.cpus().length, // Distribute workers across CPUs
875
- });
1166
+ const worker = cluster.fork();
876
1167
  this.clusterWorkers.set(worker.process.pid, worker);
877
- this.logger.info(`Worker ${worker.process.pid} started (CPU ${i % os.cpus().length})`, 'Cluster');
878
- // Handle individual worker messages (reuse handler)
1168
+ this.logger.info(`Worker ${worker.process.pid} started`, 'Cluster');
1169
+ // Handle individual worker messages
879
1170
  worker.on('message', this.handleWorkerMessage.bind(this));
880
1171
  }
881
- // Handle worker exits with cleanup
1172
+ // Simple worker exit handling
882
1173
  cluster.on('exit', (worker, code, signal) => {
883
- // Clean up worker tracking
884
- this.clusterWorkers.delete(worker.process.pid);
885
- this.logger.warn(`Worker ${worker.process.pid} died (${signal || code}). Restarting...`, 'Cluster');
886
- // Restart worker with proper tracking
887
- const newWorker = cluster.fork();
888
- this.clusterWorkers.set(newWorker.process.pid, newWorker);
889
- newWorker.on('message', this.handleWorkerMessage.bind(this));
890
- this.logger.info(`Worker ${newWorker.process.pid} started`, 'Cluster');
1174
+ const pid = worker.process.pid;
1175
+ this.clusterWorkers.delete(pid);
1176
+ if (code !== 0 && !worker.exitedAfterDisconnect) {
1177
+ this.logger.warn(`Worker ${pid} died unexpectedly (${signal || code}). Restarting...`, 'Cluster');
1178
+ // Simple restart
1179
+ const newWorker = cluster.fork();
1180
+ this.clusterWorkers.set(newWorker.process.pid, newWorker);
1181
+ this.logger.info(`Worker ${newWorker.process.pid} restarted`, 'Cluster');
1182
+ }
891
1183
  });
892
1184
  // Master process callback
893
1185
  if (callback)
@@ -899,15 +1191,24 @@ class Moro extends events_1.EventEmitter {
899
1191
  // Worker-specific optimizations for high concurrency
900
1192
  process.env.UV_THREADPOOL_SIZE = '64';
901
1193
  // Reduce logging contention in workers (major bottleneck)
902
- if (this.config.logging) {
903
- // Workers log less frequently to reduce I/O contention
904
- this.config.logging.level = 'warn'; // Only warnings and errors
1194
+ // Multiple workers writing to same log files creates I/O contention
1195
+ // ONLY reduce log level if user didn't explicitly set one
1196
+ if (!this.userSetLogger) {
1197
+ // Workers log less frequently to reduce I/O contention (only if not explicitly configured)
1198
+ applyLoggingConfiguration(undefined, { level: 'warn' }); // Only warnings and errors
905
1199
  }
906
- // Memory optimization for workers
907
- process.env.NODE_OPTIONS = '--max-old-space-size=1024'; // Limit memory per worker
908
- // Optimize V8 flags for better performance (Rust-level optimizations)
1200
+ // Research-based memory optimization for workers
1201
+ const totalMemoryGB = os.totalmem() / (1024 * 1024 * 1024);
1202
+ const workerCount = Object.keys(cluster.workers || {}).length || 1;
1203
+ // Conservative memory allocation
1204
+ const heapSizePerWorkerMB = Math.min(Math.floor(((totalMemoryGB * 1024) / workerCount) * 0.8), // 80% of available memory
1205
+ 1536 // Cap at 1.5GB (GC efficiency threshold from research)
1206
+ );
1207
+ process.env.NODE_OPTIONS = `--max-old-space-size=${heapSizePerWorkerMB}`;
1208
+ this.logger.debug(`Worker memory allocated: ${heapSizePerWorkerMB}MB heap (${workerCount} workers, ${totalMemoryGB.toFixed(1)}GB total)`, 'Worker');
1209
+ // Optimize V8 flags for better performance
909
1210
  if (process.env.NODE_ENV === 'production') {
910
- // Ultra-aggressive V8 optimizations for maximum performance
1211
+ // Aggressive V8 optimizations for maximum performance
911
1212
  const v8Flags = [
912
1213
  '--optimize-for-size', // Trade memory for speed
913
1214
  '--always-opt', // Always optimize functions
@@ -960,14 +1261,30 @@ class Moro extends events_1.EventEmitter {
960
1261
  catch (error) {
961
1262
  // Documentation not enabled, that's fine
962
1263
  }
963
- // Add intelligent routing middleware
964
- this.coreFramework.addMiddleware(async (req, res, next) => {
965
- const handled = await this.intelligentRouting.handleIntelligentRoute(req, res);
966
- if (!handled) {
967
- next();
1264
+ // Add unified routing middleware (handles both chainable and direct routes)
1265
+ // Optimized: call router without extra async wrapper when possible
1266
+ this.coreFramework.addMiddleware((req, res, next) => {
1267
+ // Try unified router first (handles all route types)
1268
+ const handled = this.unifiedRouter.handleRequest(req, res);
1269
+ // Check if it's a promise (async route) or sync
1270
+ if (handled && typeof handled.then === 'function') {
1271
+ // Async - await the result
1272
+ handled
1273
+ .then(isHandled => {
1274
+ if (!isHandled) {
1275
+ next(); // Fall back to legacy routes if any
1276
+ }
1277
+ })
1278
+ .catch(() => next());
1279
+ }
1280
+ else {
1281
+ // Sync - check immediately
1282
+ if (!handled) {
1283
+ next();
1284
+ }
968
1285
  }
969
1286
  });
970
- // Register direct routes
1287
+ // Register legacy direct routes with the HTTP server (for backward compatibility)
971
1288
  if (this.routes.length > 0) {
972
1289
  this.registerDirectRoutes();
973
1290
  }
@@ -980,15 +1297,36 @@ class Moro extends events_1.EventEmitter {
980
1297
  worker: process.pid,
981
1298
  });
982
1299
  };
983
- if (host) {
984
- this.coreFramework.listen(port, host, workerCallback);
985
- }
986
- else {
987
- this.coreFramework.listen(port, workerCallback);
988
- }
1300
+ // Ensure WebSocket setup is complete before starting worker
1301
+ this.processQueuedWebSocketRegistrations()
1302
+ .then(() => {
1303
+ if (host) {
1304
+ this.coreFramework.listen(port, host, workerCallback);
1305
+ }
1306
+ else {
1307
+ this.coreFramework.listen(port, workerCallback);
1308
+ }
1309
+ })
1310
+ .catch(error => {
1311
+ this.logger.error('WebSocket initialization failed in worker', 'Worker', {
1312
+ error: error instanceof Error ? error.message : String(error),
1313
+ });
1314
+ // For WebSocket failures with queued registrations, error will propagate
1315
+ if (error instanceof Error &&
1316
+ error.message.includes('WebSocket features require a WebSocket adapter')) {
1317
+ throw error;
1318
+ }
1319
+ // Start anyway for other errors
1320
+ if (host) {
1321
+ this.coreFramework.listen(port, host, workerCallback);
1322
+ }
1323
+ else {
1324
+ this.coreFramework.listen(port, workerCallback);
1325
+ }
1326
+ });
989
1327
  }
990
1328
  }
991
- // Reusable worker message handler (avoids creating new functions)
1329
+ // Simple worker message handler
992
1330
  handleWorkerMessage(message) {
993
1331
  // Handle inter-worker communication if needed
994
1332
  if (message.type === 'health-check') {
@@ -998,32 +1336,81 @@ class Moro extends events_1.EventEmitter {
998
1336
  // Log other worker messages
999
1337
  this.logger.debug(`Worker message: ${JSON.stringify(message)}`, 'Cluster');
1000
1338
  }
1339
+ /**
1340
+ * Gracefully close the application and clean up resources
1341
+ * This should be called in tests and during shutdown
1342
+ */
1343
+ async close() {
1344
+ this.logger.debug('Closing Moro application...');
1345
+ // Flush logger buffer before shutdown
1346
+ try {
1347
+ // Use flushBuffer for immediate synchronous flush
1348
+ this.logger.flushBuffer();
1349
+ }
1350
+ catch (error) {
1351
+ // Ignore flush errors during shutdown
1352
+ }
1353
+ // Close the core framework with timeout
1354
+ if (this.coreFramework && this.coreFramework.httpServer) {
1355
+ try {
1356
+ await Promise.race([
1357
+ new Promise(resolve => {
1358
+ this.coreFramework.httpServer.close(() => {
1359
+ resolve();
1360
+ });
1361
+ }),
1362
+ new Promise(resolve => setTimeout(resolve, 2000)), // 2 second timeout
1363
+ ]);
1364
+ }
1365
+ catch (error) {
1366
+ // Force close if graceful close fails
1367
+ this.logger.warn('Force closing HTTP server due to timeout');
1368
+ }
1369
+ }
1370
+ // Clean up module discovery watchers
1371
+ if (this.moduleDiscovery && typeof this.moduleDiscovery.cleanup === 'function') {
1372
+ try {
1373
+ this.moduleDiscovery.cleanup();
1374
+ }
1375
+ catch (error) {
1376
+ // Ignore cleanup errors
1377
+ }
1378
+ }
1379
+ // Clean up event listeners
1380
+ try {
1381
+ this.eventBus.removeAllListeners();
1382
+ this.removeAllListeners();
1383
+ }
1384
+ catch (error) {
1385
+ // Ignore cleanup errors
1386
+ }
1387
+ this.logger.debug('Moro application closed successfully');
1388
+ }
1001
1389
  }
1002
- exports.Moro = Moro;
1003
1390
  // Export convenience function
1004
- function createApp(options) {
1391
+ export function createApp(options) {
1005
1392
  return new Moro(options);
1006
1393
  }
1007
1394
  // Runtime-specific convenience functions
1008
- function createAppNode(options) {
1395
+ export function createAppNode(options) {
1009
1396
  return new Moro({
1010
1397
  ...options,
1011
1398
  runtime: { type: 'node' },
1012
1399
  });
1013
1400
  }
1014
- function createAppEdge(options) {
1401
+ export function createAppEdge(options) {
1015
1402
  return new Moro({
1016
1403
  ...options,
1017
1404
  runtime: { type: 'vercel-edge' },
1018
1405
  });
1019
1406
  }
1020
- function createAppLambda(options) {
1407
+ export function createAppLambda(options) {
1021
1408
  return new Moro({
1022
1409
  ...options,
1023
1410
  runtime: { type: 'aws-lambda' },
1024
1411
  });
1025
1412
  }
1026
- function createAppWorker(options) {
1413
+ export function createAppWorker(options) {
1027
1414
  return new Moro({
1028
1415
  ...options,
1029
1416
  runtime: { type: 'cloudflare-workers' },