@morojs/moro 1.5.16 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (373) hide show
  1. package/README.md +70 -269
  2. package/dist/core/auth/morojs-adapter.js +5 -9
  3. package/dist/core/auth/morojs-adapter.js.map +1 -1
  4. package/dist/core/config/config-manager.d.ts +1 -1
  5. package/dist/core/config/config-manager.js +10 -20
  6. package/dist/core/config/config-manager.js.map +1 -1
  7. package/dist/core/config/config-sources.d.ts +2 -2
  8. package/dist/core/config/config-sources.js +17 -20
  9. package/dist/core/config/config-sources.js.map +1 -1
  10. package/dist/core/config/config-validator.d.ts +1 -1
  11. package/dist/core/config/config-validator.js +33 -10
  12. package/dist/core/config/config-validator.js.map +1 -1
  13. package/dist/core/config/file-loader.d.ts +1 -1
  14. package/dist/core/config/file-loader.js +19 -78
  15. package/dist/core/config/file-loader.js.map +1 -1
  16. package/dist/core/config/index.d.ts +8 -8
  17. package/dist/core/config/index.js +25 -51
  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 +11 -13
  21. package/dist/core/config/schema.js.map +1 -1
  22. package/dist/core/config/utils.d.ts +1 -1
  23. package/dist/core/config/utils.js +18 -32
  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 +3 -1
  32. package/dist/core/database/adapters/mongodb.js +23 -8
  33. package/dist/core/database/adapters/mongodb.js.map +1 -1
  34. package/dist/core/database/adapters/mysql.d.ts +3 -1
  35. package/dist/core/database/adapters/mysql.js +18 -9
  36. package/dist/core/database/adapters/mysql.js.map +1 -1
  37. package/dist/core/database/adapters/postgresql.d.ts +3 -1
  38. package/dist/core/database/adapters/postgresql.js +18 -8
  39. package/dist/core/database/adapters/postgresql.js.map +1 -1
  40. package/dist/core/database/adapters/redis.d.ts +3 -1
  41. package/dist/core/database/adapters/redis.js +34 -9
  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 +6 -10
  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 +16 -6
  73. package/dist/core/framework.js +182 -92
  74. package/dist/core/framework.js.map +1 -1
  75. package/dist/core/http/http-server.d.ts +1 -1
  76. package/dist/core/http/http-server.js +26 -209
  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/router.d.ts +1 -1
  82. package/dist/core/http/router.js +3 -7
  83. package/dist/core/http/router.js.map +1 -1
  84. package/dist/core/http/uws-http-server.d.ts +64 -0
  85. package/dist/core/http/uws-http-server.js +688 -0
  86. package/dist/core/http/uws-http-server.js.map +1 -0
  87. package/dist/core/logger/filters.d.ts +1 -1
  88. package/dist/core/logger/filters.js +8 -19
  89. package/dist/core/logger/filters.js.map +1 -1
  90. package/dist/core/logger/index.d.ts +3 -3
  91. package/dist/core/logger/index.js +2 -25
  92. package/dist/core/logger/index.js.map +1 -1
  93. package/dist/core/logger/logger.d.ts +1 -1
  94. package/dist/core/logger/logger.js +21 -23
  95. package/dist/core/logger/logger.js.map +1 -1
  96. package/dist/core/logger/outputs.d.ts +1 -1
  97. package/dist/core/logger/outputs.js +8 -15
  98. package/dist/core/logger/outputs.js.map +1 -1
  99. package/dist/core/middleware/built-in/adapters/cache/file.d.ts +1 -1
  100. package/dist/core/middleware/built-in/adapters/cache/file.js +10 -47
  101. package/dist/core/middleware/built-in/adapters/cache/file.js.map +1 -1
  102. package/dist/core/middleware/built-in/adapters/cache/index.d.ts +4 -4
  103. package/dist/core/middleware/built-in/adapters/cache/index.js +10 -17
  104. package/dist/core/middleware/built-in/adapters/cache/index.js.map +1 -1
  105. package/dist/core/middleware/built-in/adapters/cache/memory.d.ts +1 -1
  106. package/dist/core/middleware/built-in/adapters/cache/memory.js +3 -7
  107. package/dist/core/middleware/built-in/adapters/cache/memory.js.map +1 -1
  108. package/dist/core/middleware/built-in/adapters/cache/redis.d.ts +3 -1
  109. package/dist/core/middleware/built-in/adapters/cache/redis.js +11 -9
  110. package/dist/core/middleware/built-in/adapters/cache/redis.js.map +1 -1
  111. package/dist/core/middleware/built-in/adapters/cdn/azure.d.ts +1 -1
  112. package/dist/core/middleware/built-in/adapters/cdn/azure.js +3 -7
  113. package/dist/core/middleware/built-in/adapters/cdn/azure.js.map +1 -1
  114. package/dist/core/middleware/built-in/adapters/cdn/cloudflare.d.ts +1 -1
  115. package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js +3 -7
  116. package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js.map +1 -1
  117. package/dist/core/middleware/built-in/adapters/cdn/cloudfront.d.ts +3 -1
  118. package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js +12 -10
  119. package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js.map +1 -1
  120. package/dist/core/middleware/built-in/adapters/cdn/index.d.ts +4 -4
  121. package/dist/core/middleware/built-in/adapters/cdn/index.js +10 -17
  122. package/dist/core/middleware/built-in/adapters/cdn/index.js.map +1 -1
  123. package/dist/core/middleware/built-in/adapters/index.d.ts +4 -4
  124. package/dist/core/middleware/built-in/adapters/index.js +4 -23
  125. package/dist/core/middleware/built-in/adapters/index.js.map +1 -1
  126. package/dist/core/middleware/built-in/auth-helpers.js +11 -22
  127. package/dist/core/middleware/built-in/auth-helpers.js.map +1 -1
  128. package/dist/core/middleware/built-in/auth-providers.d.ts +1 -1
  129. package/dist/core/middleware/built-in/auth-providers.js +4 -9
  130. package/dist/core/middleware/built-in/auth-providers.js.map +1 -1
  131. package/dist/core/middleware/built-in/auth.d.ts +2 -2
  132. package/dist/core/middleware/built-in/auth.js +51 -44
  133. package/dist/core/middleware/built-in/auth.js.map +1 -1
  134. package/dist/core/middleware/built-in/cache.d.ts +2 -2
  135. package/dist/core/middleware/built-in/cache.js +8 -11
  136. package/dist/core/middleware/built-in/cache.js.map +1 -1
  137. package/dist/core/middleware/built-in/cdn.d.ts +2 -2
  138. package/dist/core/middleware/built-in/cdn.js +5 -9
  139. package/dist/core/middleware/built-in/cdn.js.map +1 -1
  140. package/dist/core/middleware/built-in/cookie.d.ts +1 -1
  141. package/dist/core/middleware/built-in/cookie.js +3 -7
  142. package/dist/core/middleware/built-in/cookie.js.map +1 -1
  143. package/dist/core/middleware/built-in/cors.d.ts +1 -1
  144. package/dist/core/middleware/built-in/cors.js +3 -7
  145. package/dist/core/middleware/built-in/cors.js.map +1 -1
  146. package/dist/core/middleware/built-in/csp.d.ts +1 -1
  147. package/dist/core/middleware/built-in/csp.js +5 -8
  148. package/dist/core/middleware/built-in/csp.js.map +1 -1
  149. package/dist/core/middleware/built-in/csrf.d.ts +1 -1
  150. package/dist/core/middleware/built-in/csrf.js +5 -8
  151. package/dist/core/middleware/built-in/csrf.js.map +1 -1
  152. package/dist/core/middleware/built-in/error-tracker.js +3 -7
  153. package/dist/core/middleware/built-in/error-tracker.js.map +1 -1
  154. package/dist/core/middleware/built-in/index.d.ts +28 -28
  155. package/dist/core/middleware/built-in/index.js +47 -82
  156. package/dist/core/middleware/built-in/index.js.map +1 -1
  157. package/dist/core/middleware/built-in/jwt-helpers.d.ts +27 -2
  158. package/dist/core/middleware/built-in/jwt-helpers.js +32 -10
  159. package/dist/core/middleware/built-in/jwt-helpers.js.map +1 -1
  160. package/dist/core/middleware/built-in/performance-monitor.js +3 -7
  161. package/dist/core/middleware/built-in/performance-monitor.js.map +1 -1
  162. package/dist/core/middleware/built-in/rate-limit.d.ts +1 -1
  163. package/dist/core/middleware/built-in/rate-limit.js +3 -7
  164. package/dist/core/middleware/built-in/rate-limit.js.map +1 -1
  165. package/dist/core/middleware/built-in/request-logger.js +3 -7
  166. package/dist/core/middleware/built-in/request-logger.js.map +1 -1
  167. package/dist/core/middleware/built-in/session.d.ts +2 -2
  168. package/dist/core/middleware/built-in/session.js +11 -15
  169. package/dist/core/middleware/built-in/session.js.map +1 -1
  170. package/dist/core/middleware/built-in/sse.d.ts +1 -1
  171. package/dist/core/middleware/built-in/sse.js +3 -7
  172. package/dist/core/middleware/built-in/sse.js.map +1 -1
  173. package/dist/core/middleware/built-in/validation.d.ts +1 -1
  174. package/dist/core/middleware/built-in/validation.js +3 -7
  175. package/dist/core/middleware/built-in/validation.js.map +1 -1
  176. package/dist/core/middleware/index.d.ts +4 -4
  177. package/dist/core/middleware/index.js +8 -28
  178. package/dist/core/middleware/index.js.map +1 -1
  179. package/dist/core/modules/auto-discovery.d.ts +3 -3
  180. package/dist/core/modules/auto-discovery.js +43 -81
  181. package/dist/core/modules/auto-discovery.js.map +1 -1
  182. package/dist/core/modules/index.d.ts +2 -2
  183. package/dist/core/modules/index.js +2 -9
  184. package/dist/core/modules/index.js.map +1 -1
  185. package/dist/core/modules/modules.d.ts +3 -3
  186. package/dist/core/modules/modules.js +11 -52
  187. package/dist/core/modules/modules.js.map +1 -1
  188. package/dist/core/networking/adapters/index.d.ts +4 -3
  189. package/dist/core/networking/adapters/index.js +3 -7
  190. package/dist/core/networking/adapters/index.js.map +1 -1
  191. package/dist/core/networking/adapters/socketio-adapter.d.ts +1 -1
  192. package/dist/core/networking/adapters/socketio-adapter.js +5 -40
  193. package/dist/core/networking/adapters/socketio-adapter.js.map +1 -1
  194. package/dist/core/networking/adapters/uws-adapter.d.ts +44 -0
  195. package/dist/core/networking/adapters/uws-adapter.js +513 -0
  196. package/dist/core/networking/adapters/uws-adapter.js.map +1 -0
  197. package/dist/core/networking/adapters/ws-adapter.d.ts +1 -1
  198. package/dist/core/networking/adapters/ws-adapter.js +7 -42
  199. package/dist/core/networking/adapters/ws-adapter.js.map +1 -1
  200. package/dist/core/networking/index.d.ts +3 -2
  201. package/dist/core/networking/index.js +2 -7
  202. package/dist/core/networking/index.js.map +1 -1
  203. package/dist/core/networking/service-discovery.js +3 -7
  204. package/dist/core/networking/service-discovery.js.map +1 -1
  205. package/dist/core/networking/websocket-adapter.js +1 -2
  206. package/dist/core/networking/websocket-adapter.js.map +1 -1
  207. package/dist/core/networking/websocket-manager.d.ts +3 -3
  208. package/dist/core/networking/websocket-manager.js +9 -11
  209. package/dist/core/networking/websocket-manager.js.map +1 -1
  210. package/dist/core/routing/app-integration.d.ts +2 -2
  211. package/dist/core/routing/app-integration.js +7 -12
  212. package/dist/core/routing/app-integration.js.map +1 -1
  213. package/dist/core/routing/index.d.ts +2 -2
  214. package/dist/core/routing/index.js +7 -14
  215. package/dist/core/routing/index.js.map +1 -1
  216. package/dist/core/runtime/aws-lambda-adapter.d.ts +3 -3
  217. package/dist/core/runtime/aws-lambda-adapter.js +2 -6
  218. package/dist/core/runtime/aws-lambda-adapter.js.map +1 -1
  219. package/dist/core/runtime/base-adapter.d.ts +2 -2
  220. package/dist/core/runtime/base-adapter.js +3 -7
  221. package/dist/core/runtime/base-adapter.js.map +1 -1
  222. package/dist/core/runtime/cloudflare-workers-adapter.d.ts +3 -3
  223. package/dist/core/runtime/cloudflare-workers-adapter.js +2 -6
  224. package/dist/core/runtime/cloudflare-workers-adapter.js.map +1 -1
  225. package/dist/core/runtime/index.d.ts +12 -12
  226. package/dist/core/runtime/index.js +22 -35
  227. package/dist/core/runtime/index.js.map +1 -1
  228. package/dist/core/runtime/node-adapter.d.ts +4 -4
  229. package/dist/core/runtime/node-adapter.js +6 -43
  230. package/dist/core/runtime/node-adapter.js.map +1 -1
  231. package/dist/core/runtime/vercel-edge-adapter.d.ts +3 -3
  232. package/dist/core/runtime/vercel-edge-adapter.js +2 -6
  233. package/dist/core/runtime/vercel-edge-adapter.js.map +1 -1
  234. package/dist/core/utilities/circuit-breaker.js +1 -5
  235. package/dist/core/utilities/circuit-breaker.js.map +1 -1
  236. package/dist/core/utilities/container.js +12 -22
  237. package/dist/core/utilities/container.js.map +1 -1
  238. package/dist/core/utilities/hooks.d.ts +2 -2
  239. package/dist/core/utilities/hooks.js +7 -12
  240. package/dist/core/utilities/hooks.js.map +1 -1
  241. package/dist/core/utilities/index.d.ts +5 -4
  242. package/dist/core/utilities/index.js +5 -19
  243. package/dist/core/utilities/index.js.map +1 -1
  244. package/dist/core/utilities/package-utils.d.ts +38 -0
  245. package/dist/core/utilities/package-utils.js +57 -0
  246. package/dist/core/utilities/package-utils.js.map +1 -0
  247. package/dist/core/validation/adapters.d.ts +1 -1
  248. package/dist/core/validation/adapters.js +15 -26
  249. package/dist/core/validation/adapters.js.map +1 -1
  250. package/dist/core/validation/index.d.ts +6 -4
  251. package/dist/core/validation/index.js +57 -28
  252. package/dist/core/validation/index.js.map +1 -1
  253. package/dist/core/validation/schema-interface.js +3 -9
  254. package/dist/core/validation/schema-interface.js.map +1 -1
  255. package/dist/index.d.ts +51 -52
  256. package/dist/index.js +23 -132
  257. package/dist/index.js.map +1 -1
  258. package/dist/moro.d.ts +30 -10
  259. package/dist/moro.js +262 -126
  260. package/dist/moro.js.map +1 -1
  261. package/dist/types/auth.js +3 -9
  262. package/dist/types/auth.js.map +1 -1
  263. package/dist/types/cache.js +1 -2
  264. package/dist/types/cdn.js +1 -2
  265. package/dist/types/config.d.ts +13 -1
  266. package/dist/types/config.js +1 -2
  267. package/dist/types/config.js.map +1 -1
  268. package/dist/types/core.d.ts +3 -3
  269. package/dist/types/core.js +1 -2
  270. package/dist/types/database.js +1 -2
  271. package/dist/types/discovery.js +1 -2
  272. package/dist/types/events.js +1 -2
  273. package/dist/types/hooks.d.ts +1 -1
  274. package/dist/types/hooks.js +1 -2
  275. package/dist/types/http.js +1 -2
  276. package/dist/types/logger.js +1 -2
  277. package/dist/types/module.js +1 -2
  278. package/dist/types/runtime.d.ts +1 -1
  279. package/dist/types/runtime.js +1 -2
  280. package/dist/types/session.js +1 -2
  281. package/jest.config.mjs +41 -0
  282. package/package.json +18 -51
  283. package/src/core/auth/morojs-adapter.ts +1 -1
  284. package/src/core/config/config-manager.ts +2 -2
  285. package/src/core/config/config-sources.ts +6 -6
  286. package/src/core/config/config-validator.ts +38 -3
  287. package/src/core/config/file-loader.ts +13 -40
  288. package/src/core/config/index.ts +15 -11
  289. package/src/core/config/schema.ts +3 -2
  290. package/src/core/config/utils.ts +3 -3
  291. package/src/core/database/adapters/drizzle.ts +18 -6
  292. package/src/core/database/adapters/index.ts +13 -13
  293. package/src/core/database/adapters/mongodb.ts +23 -3
  294. package/src/core/database/adapters/mysql.ts +18 -4
  295. package/src/core/database/adapters/postgresql.ts +18 -3
  296. package/src/core/database/adapters/redis.ts +34 -4
  297. package/src/core/database/adapters/sqlite.ts +19 -3
  298. package/src/core/database/index.ts +2 -2
  299. package/src/core/docs/index.ts +8 -8
  300. package/src/core/docs/openapi-generator.ts +4 -4
  301. package/src/core/docs/schema-to-openapi.ts +3 -6
  302. package/src/core/docs/simple-docs.ts +2 -2
  303. package/src/core/docs/swagger-ui.ts +19 -16
  304. package/src/core/docs/zod-to-openapi.ts +34 -34
  305. package/src/core/events/event-bus.ts +2 -2
  306. package/src/core/events/index.ts +2 -2
  307. package/src/core/framework.ts +190 -49
  308. package/src/core/http/http-server.ts +16 -159
  309. package/src/core/http/index.ts +4 -3
  310. package/src/core/http/router.ts +2 -2
  311. package/src/core/http/uws-http-server.ts +794 -0
  312. package/src/core/logger/filters.ts +1 -1
  313. package/src/core/logger/index.ts +3 -3
  314. package/src/core/logger/logger.ts +9 -1
  315. package/src/core/logger/outputs.ts +1 -1
  316. package/src/core/middleware/built-in/adapters/cache/file.ts +3 -3
  317. package/src/core/middleware/built-in/adapters/cache/index.ts +7 -7
  318. package/src/core/middleware/built-in/adapters/cache/memory.ts +2 -2
  319. package/src/core/middleware/built-in/adapters/cache/redis.ts +18 -4
  320. package/src/core/middleware/built-in/adapters/cdn/azure.ts +2 -2
  321. package/src/core/middleware/built-in/adapters/cdn/cloudflare.ts +2 -2
  322. package/src/core/middleware/built-in/adapters/cdn/cloudfront.ts +16 -5
  323. package/src/core/middleware/built-in/adapters/cdn/index.ts +7 -7
  324. package/src/core/middleware/built-in/adapters/index.ts +4 -4
  325. package/src/core/middleware/built-in/auth-helpers.ts +1 -1
  326. package/src/core/middleware/built-in/auth-providers.ts +1 -1
  327. package/src/core/middleware/built-in/auth.ts +64 -41
  328. package/src/core/middleware/built-in/cache.ts +5 -5
  329. package/src/core/middleware/built-in/cdn.ts +4 -4
  330. package/src/core/middleware/built-in/cookie.ts +2 -2
  331. package/src/core/middleware/built-in/cors.ts +2 -2
  332. package/src/core/middleware/built-in/csp.ts +3 -3
  333. package/src/core/middleware/built-in/csrf.ts +3 -3
  334. package/src/core/middleware/built-in/error-tracker.ts +1 -1
  335. package/src/core/middleware/built-in/index.ts +31 -31
  336. package/src/core/middleware/built-in/jwt-helpers.ts +32 -4
  337. package/src/core/middleware/built-in/performance-monitor.ts +1 -1
  338. package/src/core/middleware/built-in/rate-limit.ts +2 -2
  339. package/src/core/middleware/built-in/request-logger.ts +1 -1
  340. package/src/core/middleware/built-in/session.ts +7 -8
  341. package/src/core/middleware/built-in/sse.ts +2 -2
  342. package/src/core/middleware/built-in/validation.ts +2 -2
  343. package/src/core/middleware/index.ts +6 -6
  344. package/src/core/modules/auto-discovery.ts +4 -4
  345. package/src/core/modules/index.ts +2 -2
  346. package/src/core/modules/modules.ts +4 -4
  347. package/src/core/networking/adapters/index.ts +4 -3
  348. package/src/core/networking/adapters/socketio-adapter.ts +5 -3
  349. package/src/core/networking/adapters/uws-adapter.ts +619 -0
  350. package/src/core/networking/adapters/ws-adapter.ts +6 -4
  351. package/src/core/networking/index.ts +3 -2
  352. package/src/core/networking/service-discovery.ts +1 -1
  353. package/src/core/networking/websocket-manager.ts +7 -7
  354. package/src/core/routing/app-integration.ts +3 -3
  355. package/src/core/routing/index.ts +3 -3
  356. package/src/core/runtime/aws-lambda-adapter.ts +3 -3
  357. package/src/core/runtime/base-adapter.ts +2 -2
  358. package/src/core/runtime/cloudflare-workers-adapter.ts +3 -3
  359. package/src/core/runtime/index.ts +13 -13
  360. package/src/core/runtime/node-adapter.ts +4 -4
  361. package/src/core/runtime/vercel-edge-adapter.ts +3 -3
  362. package/src/core/utilities/hooks.ts +3 -3
  363. package/src/core/utilities/index.ts +5 -4
  364. package/src/core/utilities/package-utils.ts +59 -0
  365. package/src/core/validation/adapters.ts +1 -1
  366. package/src/core/validation/index.ts +68 -16
  367. package/src/index.ts +73 -66
  368. package/src/moro.ts +303 -75
  369. package/src/types/config.ts +13 -1
  370. package/src/types/core.ts +3 -3
  371. package/src/types/hooks.ts +1 -1
  372. package/src/types/runtime.ts +1 -1
  373. package/tsconfig.json +4 -2
@@ -0,0 +1,794 @@
1
+ // uWebSockets.js HTTP Server Implementation for Moro Framework
2
+ // Provides ultra-high-performance HTTP and WebSocket server using uWebSockets.js
3
+
4
+ import cluster from 'cluster';
5
+ import { createFrameworkLogger } from '../logger/index.js';
6
+ import {
7
+ HttpRequest,
8
+ HttpResponse,
9
+ HttpHandler,
10
+ Middleware,
11
+ RouteEntry,
12
+ } from '../../types/http.js';
13
+
14
+ /**
15
+ * uWebSockets HTTP Server Adapter
16
+ * Bridges uWebSockets.js with Moro's HTTP abstractions
17
+ */
18
+ export class UWebSocketsHttpServer {
19
+ private app: any; // uWebSockets app instance
20
+ private uws: any; // uWebSockets module reference (stored to avoid re-importing)
21
+ private listenSocket: any; // uWebSockets listen socket
22
+ private routes: RouteEntry[] = [];
23
+ private globalMiddleware: Middleware[] = [];
24
+ private logger = createFrameworkLogger('UWSHttpServer');
25
+ private hookManager: any;
26
+ private requestCounter = 0;
27
+ private isListening = false;
28
+ private port?: number;
29
+ private host?: string;
30
+ private initPromise: Promise<void>;
31
+
32
+ // Route caching for performance
33
+ private staticRoutes = new Map<string, RouteEntry>();
34
+ private dynamicRoutes: RouteEntry[] = [];
35
+
36
+ // Performance optimizations - object pooling
37
+ private paramObjectPool: Record<string, string>[] = [];
38
+ private queryObjectPool: Record<string, string>[] = [];
39
+ private readonly maxPoolSize = 100;
40
+
41
+ // String interning for common values
42
+ private static readonly INTERNED_METHODS = new Map([
43
+ ['get', 'GET'],
44
+ ['post', 'POST'],
45
+ ['put', 'PUT'],
46
+ ['delete', 'DELETE'],
47
+ ['patch', 'PATCH'],
48
+ ['head', 'HEAD'],
49
+ ['options', 'OPTIONS'],
50
+ ]);
51
+
52
+ // Pre-compiled response buffers
53
+ private static readonly RESPONSE_BUFFERS = {
54
+ notFound: Buffer.from('{"success":false,"error":"Not found"}'),
55
+ serverError: Buffer.from('{"success":false,"error":"Internal server error"}'),
56
+ };
57
+
58
+ constructor(
59
+ options: {
60
+ ssl?: { key_file_name?: string; cert_file_name?: string; passphrase?: string };
61
+ } = {}
62
+ ) {
63
+ this.initPromise = this.initialize(options);
64
+ }
65
+
66
+ private async initialize(options: {
67
+ ssl?: { key_file_name?: string; cert_file_name?: string; passphrase?: string };
68
+ }): Promise<void> {
69
+ try {
70
+ // Lazy load uWebSockets.js - only when explicitly configured
71
+ // This ensures it's an optional dependency with graceful fallback
72
+ const uwsModule = await import('uWebSockets.js');
73
+ this.uws = uwsModule.default || uwsModule;
74
+
75
+ if (options.ssl && options.ssl.key_file_name && options.ssl.cert_file_name) {
76
+ this.app = this.uws.SSLApp({
77
+ key_file_name: options.ssl.key_file_name,
78
+ cert_file_name: options.ssl.cert_file_name,
79
+ passphrase: options.ssl.passphrase,
80
+ });
81
+ this.logger.info('uWebSockets SSL/TLS HTTP server created', 'Init');
82
+ } else {
83
+ this.app = this.uws.App();
84
+ this.logger.info('uWebSockets HTTP server created', 'Init');
85
+ }
86
+
87
+ // Setup generic route handler for all HTTP methods and paths
88
+ this.setupRouteHandlers();
89
+ } catch (error) {
90
+ // Log helpful error message with installation instructions
91
+ this.logger.error(
92
+ 'Failed to load uWebSockets.js (optional dependency)\n' +
93
+ 'To use uWebSockets, install it with:\n' +
94
+ ' npm install --save-dev github:uNetworking/uWebSockets.js#v20.52.0\n' +
95
+ 'Or set useUWebSockets: false in your config to use the standard HTTP server.\n' +
96
+ 'Error: ' +
97
+ (error instanceof Error ? error.message : String(error)),
98
+ 'Init'
99
+ );
100
+ throw error; // Re-throw so framework.ts can catch and fallback
101
+ }
102
+ }
103
+
104
+ private setupRouteHandlers(): void {
105
+ // Handle all HTTP methods through catchall for proper routing
106
+ this.app.any('/*', (res: any, req: any) => {
107
+ // Try fast synchronous path first
108
+ const method = req.getMethod().toUpperCase();
109
+ const path = req.getUrl();
110
+
111
+ // Fast path: No body, no global middleware
112
+ if (this.globalMiddleware.length === 0 && method === 'GET') {
113
+ const route = this.findRoute(method, path);
114
+ if (route && (!route.middleware || route.middleware.length === 0)) {
115
+ this.handleRequestSync(req, res, route, method, path);
116
+ return;
117
+ }
118
+ }
119
+
120
+ // Slow path: Has middleware or body or other complexity
121
+ this.handleRequest(req, res);
122
+ });
123
+ }
124
+
125
+ // Fast synchronous handler for simple GET requests
126
+ private handleRequestSync(
127
+ req: any,
128
+ res: any,
129
+ route: RouteEntry,
130
+ method: string,
131
+ path: string
132
+ ): void {
133
+ this.requestCounter++;
134
+ let httpReq: any;
135
+
136
+ try {
137
+ httpReq = this.createMoroRequest(req, res);
138
+ const httpRes = this.createMoroResponse(req, res);
139
+
140
+ // Extract params if needed
141
+ if (route.paramNames.length > 0) {
142
+ const matches = path.match(route.pattern);
143
+ if (matches) {
144
+ httpReq.params = this.acquireParamObject();
145
+ route.paramNames.forEach((name: string, index: number) => {
146
+ httpReq.params![name] = matches[index + 1];
147
+ });
148
+ (httpReq as any)._pooledParams = httpReq.params;
149
+ }
150
+ }
151
+
152
+ // Execute handler synchronously
153
+ const result = route.handler(httpReq, httpRes);
154
+
155
+ // Handle return value
156
+ if (result && typeof result.then === 'function') {
157
+ // Oops, handler is async - handle it
158
+ result
159
+ .then((data: any) => {
160
+ if (data !== undefined && data !== null && !httpRes.headersSent) {
161
+ httpRes.json(data);
162
+ }
163
+ })
164
+ .catch(() => {
165
+ if (!res.aborted) {
166
+ res.cork(() => {
167
+ res.writeStatus('500 Internal Server Error');
168
+ res.end('{"success":false,"error":"Internal server error"}');
169
+ });
170
+ }
171
+ });
172
+ } else if (result !== undefined && result !== null && !httpRes.headersSent) {
173
+ httpRes.json(result);
174
+ }
175
+ } finally {
176
+ const pooledParams = (httpReq as any)?._pooledParams;
177
+ if (pooledParams) this.releaseParamObject(pooledParams);
178
+
179
+ const pooledQuery = (httpReq as any)?._pooledQuery;
180
+ if (pooledQuery) this.releaseQueryObject(pooledQuery);
181
+ }
182
+ }
183
+
184
+ // Object pooling methods for performance
185
+ private acquireParamObject(): Record<string, string> {
186
+ return this.paramObjectPool.pop() || {};
187
+ }
188
+
189
+ private releaseParamObject(obj: Record<string, string>): void {
190
+ if (this.paramObjectPool.length < this.maxPoolSize) {
191
+ for (const key in obj) delete obj[key];
192
+ this.paramObjectPool.push(obj);
193
+ }
194
+ }
195
+
196
+ private acquireQueryObject(): Record<string, string> {
197
+ return this.queryObjectPool.pop() || {};
198
+ }
199
+
200
+ private releaseQueryObject(obj: Record<string, string>): void {
201
+ if (this.queryObjectPool.length < this.maxPoolSize) {
202
+ for (const key in obj) delete obj[key];
203
+ this.queryObjectPool.push(obj);
204
+ }
205
+ }
206
+
207
+ private async handleRequest(req: any, res: any): Promise<void> {
208
+ this.requestCounter++;
209
+
210
+ // Declare outside try block for cleanup in finally
211
+ let httpReq: any;
212
+
213
+ try {
214
+ // Create Moro-compatible request object
215
+ httpReq = this.createMoroRequest(req, res);
216
+ const httpRes = this.createMoroResponse(req, res);
217
+
218
+ // Parse body only if there's actually a body (check content-length)
219
+ const method = req.getMethod().toUpperCase();
220
+ const contentLength = req.getHeader('content-length');
221
+ if (
222
+ (method === 'POST' || method === 'PUT' || method === 'PATCH') &&
223
+ contentLength &&
224
+ parseInt(contentLength) > 0
225
+ ) {
226
+ await this.readBody(res, httpReq);
227
+ }
228
+
229
+ // Execute hooks before request processing
230
+ if (this.hookManager) {
231
+ await this.hookManager.execute('request', {
232
+ request: httpReq,
233
+ response: httpRes,
234
+ });
235
+ }
236
+
237
+ // Find route first (before middleware)
238
+ const route = this.findRoute(httpReq.method!, httpReq.path);
239
+
240
+ if (!route) {
241
+ // 404 Not Found - fast path
242
+ if (!httpRes.headersSent) {
243
+ httpRes.statusCode = 404;
244
+ httpRes.setHeader('Content-Type', 'application/json');
245
+ httpRes.end('{"success":false,"error":"Not found"}');
246
+ }
247
+ return;
248
+ }
249
+
250
+ // Extract path parameters early - use pooled object
251
+ const matches = httpReq.path.match(route.pattern);
252
+ if (matches) {
253
+ httpReq.params = this.acquireParamObject();
254
+ route.paramNames.forEach((name: string, index: number) => {
255
+ httpReq.params![name] = matches[index + 1];
256
+ });
257
+ // Store for cleanup
258
+ (httpReq as any)._pooledParams = httpReq.params;
259
+ }
260
+
261
+ // Execute ALL middleware in one pass (global + route)
262
+ if (this.globalMiddleware.length > 0 || (route.middleware && route.middleware.length > 0)) {
263
+ const allMiddleware =
264
+ route.middleware && route.middleware.length > 0
265
+ ? [...this.globalMiddleware, ...route.middleware]
266
+ : this.globalMiddleware;
267
+
268
+ await this.executeMiddleware(allMiddleware, httpReq, httpRes);
269
+ if (httpRes.headersSent) return;
270
+ }
271
+
272
+ // Execute route handler
273
+ const result = await route.handler(httpReq, httpRes);
274
+
275
+ // If handler returns data and response hasn't been sent, send it
276
+ if (result !== undefined && result !== null && !httpRes.headersSent) {
277
+ httpRes.json(result);
278
+ }
279
+ } catch (error) {
280
+ this.logger.error(
281
+ `Request handling error: ${error instanceof Error ? error.message : String(error)}`,
282
+ 'RequestError'
283
+ );
284
+
285
+ // Send error response if not already sent
286
+ if (!res.aborted) {
287
+ try {
288
+ res.cork(() => {
289
+ res.writeStatus('500 Internal Server Error');
290
+ res.writeHeader('Content-Type', 'application/json');
291
+ res.end('{"success":false,"error":"Internal server error"}');
292
+ });
293
+ } catch (writeError) {
294
+ this.logger.error('Failed to send error response', 'ResponseError');
295
+ }
296
+ }
297
+ } finally {
298
+ // Cleanup: Release pooled objects back to pool for reuse
299
+ const pooledParams = (httpReq as any)._pooledParams;
300
+ if (pooledParams) {
301
+ this.releaseParamObject(pooledParams);
302
+ }
303
+
304
+ const pooledQuery = (httpReq as any)._pooledQuery;
305
+ if (pooledQuery) {
306
+ this.releaseQueryObject(pooledQuery);
307
+ }
308
+ }
309
+ }
310
+
311
+ private createMoroRequest(req: any, res: any): HttpRequest {
312
+ const url = req.getUrl();
313
+ const queryString = req.getQuery();
314
+ const methodRaw = req.getMethod();
315
+
316
+ // Use interned method string if available
317
+ const method = UWebSocketsHttpServer.INTERNED_METHODS.get(methodRaw) || methodRaw.toUpperCase();
318
+
319
+ // Lazy query parsing - use pooled object
320
+ let queryParams: Record<string, string> | undefined;
321
+ if (queryString) {
322
+ queryParams = this.acquireQueryObject();
323
+ // Fast query parsing without URLSearchParams overhead
324
+ const pairs = queryString.split('&');
325
+ for (let i = 0; i < pairs.length; i++) {
326
+ const pair = pairs[i];
327
+ const eqIdx = pair.indexOf('=');
328
+ if (eqIdx > 0) {
329
+ const key = pair.substring(0, eqIdx);
330
+ const value = pair.substring(eqIdx + 1);
331
+ queryParams[decodeURIComponent(key)] = decodeURIComponent(value);
332
+ }
333
+ }
334
+ }
335
+
336
+ // Lazy header parsing - only parse headers that exist
337
+ const headers: Record<string, string> = {};
338
+ req.forEach((key: string, value: string) => {
339
+ const lowerKey = key.toLowerCase();
340
+ headers[lowerKey] = value;
341
+ });
342
+
343
+ const httpReq = {
344
+ method,
345
+ path: url,
346
+ url: url,
347
+ query: queryParams || {},
348
+ params: {}, // Will be filled by route matching
349
+ headers,
350
+ body: null,
351
+ ip: '', // Lazy - only compute if accessed
352
+ requestId: '', // Lazy - only generate if accessed
353
+ } as HttpRequest;
354
+
355
+ // Store original query object for cleanup
356
+ (httpReq as any)._pooledQuery = queryParams;
357
+
358
+ return httpReq;
359
+ }
360
+
361
+ private createMoroResponse(req: any, res: any): HttpResponse {
362
+ let headersSent = false;
363
+ let statusCode = 200;
364
+ const responseHeaders: Record<string, string | string[]> = {};
365
+ //eslint-disable-next-line @typescript-eslint/no-this-alias
366
+ const self = this;
367
+
368
+ const httpRes = {
369
+ statusCode,
370
+ get headersSent() {
371
+ return headersSent;
372
+ },
373
+
374
+ status(code: number) {
375
+ statusCode = code;
376
+ (httpRes as any).statusCode = code;
377
+ return httpRes as HttpResponse;
378
+ },
379
+
380
+ setHeader(name: string, value: string | string[]) {
381
+ responseHeaders[name.toLowerCase()] = value;
382
+ return httpRes as HttpResponse;
383
+ },
384
+
385
+ getHeader(name: string) {
386
+ return responseHeaders[name.toLowerCase()];
387
+ },
388
+
389
+ removeHeader(name: string) {
390
+ delete responseHeaders[name.toLowerCase()];
391
+ return httpRes as HttpResponse;
392
+ },
393
+
394
+ json(data: any) {
395
+ if (headersSent || res.aborted) return;
396
+
397
+ const body = JSON.stringify(data);
398
+ responseHeaders['content-type'] = 'application/json';
399
+
400
+ try {
401
+ res.cork(() => {
402
+ res.writeStatus(`${statusCode} OK`);
403
+ Object.entries(responseHeaders).forEach(([key, value]) => {
404
+ res.writeHeader(key, Array.isArray(value) ? value.join(', ') : String(value));
405
+ });
406
+ res.end(body);
407
+ });
408
+ headersSent = true;
409
+ } catch (error) {
410
+ self.logger.error('Failed to send JSON response', 'ResponseError');
411
+ }
412
+ },
413
+
414
+ send(data: string | Buffer) {
415
+ if (headersSent || res.aborted) return;
416
+
417
+ const body = typeof data === 'string' ? data : data.toString();
418
+
419
+ try {
420
+ res.cork(() => {
421
+ res.writeStatus(`${statusCode} OK`);
422
+ Object.entries(responseHeaders).forEach(([key, value]) => {
423
+ res.writeHeader(key, Array.isArray(value) ? value.join(', ') : String(value));
424
+ });
425
+ res.end(body);
426
+ });
427
+ headersSent = true;
428
+ } catch (error) {
429
+ self.logger.error('Failed to send response', 'ResponseError');
430
+ }
431
+ },
432
+
433
+ end(data?: any, encoding?: any, callback?: any) {
434
+ if (headersSent || res.aborted) {
435
+ if (typeof callback === 'function') callback();
436
+ return httpRes as HttpResponse;
437
+ }
438
+
439
+ try {
440
+ res.cork(() => {
441
+ res.writeStatus(`${statusCode} OK`);
442
+ Object.entries(responseHeaders).forEach(([key, value]) => {
443
+ res.writeHeader(key, Array.isArray(value) ? value.join(', ') : String(value));
444
+ });
445
+ res.end(data || '');
446
+ });
447
+ headersSent = true;
448
+ if (typeof callback === 'function') callback();
449
+ } catch (error) {
450
+ self.logger.error('Failed to end response', 'ResponseError');
451
+ if (typeof callback === 'function') callback();
452
+ }
453
+
454
+ return httpRes as HttpResponse;
455
+ },
456
+
457
+ redirect(url: string, code?: number) {
458
+ if (headersSent || res.aborted) return;
459
+
460
+ const redirectCode = code || 302;
461
+ statusCode = redirectCode;
462
+
463
+ try {
464
+ res.cork(() => {
465
+ res.writeStatus(`${redirectCode} Found`);
466
+ res.writeHeader('Location', url);
467
+ res.end();
468
+ });
469
+ headersSent = true;
470
+ } catch (error) {
471
+ self.logger.error('Failed to send redirect', 'ResponseError');
472
+ }
473
+ },
474
+
475
+ // EventEmitter compatibility - stub implementations for middleware
476
+ on(event: string, callback: Function) {
477
+ // uWebSockets doesn't use events like Node.js, but middleware might try to listen
478
+ // Only implement 'finish' and 'close' events as stubs
479
+ return httpRes;
480
+ },
481
+
482
+ once(event: string, callback: Function) {
483
+ return httpRes;
484
+ },
485
+
486
+ emit(event: string, ...args: any[]) {
487
+ return true;
488
+ },
489
+
490
+ removeListener(event: string, callback: Function) {
491
+ return httpRes;
492
+ },
493
+
494
+ cookie(name: string, value: string, options?: any) {
495
+ let cookie = `${name}=${value}`;
496
+
497
+ if (options) {
498
+ if (options.maxAge) cookie += `; Max-Age=${options.maxAge}`;
499
+ if (options.domain) cookie += `; Domain=${options.domain}`;
500
+ if (options.path) cookie += `; Path=${options.path}`;
501
+ if (options.secure) cookie += '; Secure';
502
+ if (options.httpOnly) cookie += '; HttpOnly';
503
+ if (options.sameSite) cookie += `; SameSite=${options.sameSite}`;
504
+ }
505
+
506
+ const existing = responseHeaders['set-cookie'];
507
+ if (existing) {
508
+ if (Array.isArray(existing)) {
509
+ responseHeaders['set-cookie'] = [...existing, cookie];
510
+ } else {
511
+ responseHeaders['set-cookie'] = [existing as string, cookie];
512
+ }
513
+ } else {
514
+ responseHeaders['set-cookie'] = cookie;
515
+ }
516
+
517
+ return httpRes as HttpResponse;
518
+ },
519
+ } as any;
520
+
521
+ return httpRes as HttpResponse;
522
+ }
523
+
524
+ private async readBody(res: any, httpReq: HttpRequest): Promise<void> {
525
+ return new Promise((resolve, reject) => {
526
+ let buffer: Buffer;
527
+
528
+ res.onData((chunk: ArrayBuffer, isLast: boolean) => {
529
+ const chunkBuffer = Buffer.from(chunk);
530
+
531
+ if (isLast) {
532
+ if (buffer) {
533
+ buffer = Buffer.concat([buffer, chunkBuffer]);
534
+ } else {
535
+ buffer = chunkBuffer;
536
+ }
537
+
538
+ try {
539
+ const contentType = httpReq.headers['content-type'] || '';
540
+
541
+ if (contentType.includes('application/json')) {
542
+ httpReq.body = JSON.parse(buffer.toString('utf-8'));
543
+ } else if (contentType.includes('application/x-www-form-urlencoded')) {
544
+ const params = new URLSearchParams(buffer.toString('utf-8'));
545
+ const body: Record<string, any> = {};
546
+ params.forEach((value, key) => {
547
+ body[key] = value;
548
+ });
549
+ httpReq.body = body;
550
+ } else {
551
+ httpReq.body = buffer.toString('utf-8');
552
+ }
553
+
554
+ resolve();
555
+ } catch (error) {
556
+ this.logger.error('Failed to parse request body', 'BodyParseError');
557
+ httpReq.body = null;
558
+ resolve();
559
+ }
560
+ } else {
561
+ if (buffer) {
562
+ buffer = Buffer.concat([buffer, chunkBuffer]);
563
+ } else {
564
+ buffer = chunkBuffer;
565
+ }
566
+ }
567
+ });
568
+
569
+ res.onAborted(() => {
570
+ this.logger.debug('Request aborted', 'RequestAborted');
571
+ resolve();
572
+ });
573
+ });
574
+ }
575
+
576
+ private async executeMiddleware(
577
+ middleware: Middleware[],
578
+ req: HttpRequest,
579
+ res: HttpResponse
580
+ ): Promise<void> {
581
+ for (const mw of middleware) {
582
+ if (res.headersSent) break;
583
+
584
+ await new Promise<void>((resolve, reject) => {
585
+ try {
586
+ const result = mw(req, res, (err?: Error) => {
587
+ if (err) reject(err);
588
+ else resolve();
589
+ });
590
+
591
+ // Handle async middleware
592
+ if (result && typeof result.then === 'function') {
593
+ result.then(() => resolve()).catch(reject);
594
+ }
595
+ } catch (error) {
596
+ reject(error);
597
+ }
598
+ });
599
+ }
600
+ }
601
+
602
+ private findRoute(method: string, path: string): RouteEntry | null {
603
+ // Fast path: static route lookup
604
+ const staticKey = `${method}:${path}`;
605
+ const staticRoute = this.staticRoutes.get(staticKey);
606
+ if (staticRoute) return staticRoute;
607
+
608
+ // Dynamic route matching
609
+ for (const route of this.dynamicRoutes) {
610
+ if (route.method === method && route.pattern.test(path)) {
611
+ return route;
612
+ }
613
+ }
614
+
615
+ return null;
616
+ }
617
+
618
+ // Public API - matches MoroHttpServer interface
619
+
620
+ use(middleware: Middleware): void {
621
+ this.globalMiddleware.push(middleware);
622
+ }
623
+
624
+ get(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
625
+ this.addRoute('GET', path, handler, middleware);
626
+ }
627
+
628
+ post(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
629
+ this.addRoute('POST', path, handler, middleware);
630
+ }
631
+
632
+ put(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
633
+ this.addRoute('PUT', path, handler, middleware);
634
+ }
635
+
636
+ delete(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
637
+ this.addRoute('DELETE', path, handler, middleware);
638
+ }
639
+
640
+ patch(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
641
+ this.addRoute('PATCH', path, handler, middleware);
642
+ }
643
+
644
+ options(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
645
+ this.addRoute('OPTIONS', path, handler, middleware);
646
+ }
647
+
648
+ head(path: string, handler: HttpHandler, middleware?: Middleware[]): void {
649
+ this.addRoute('HEAD', path, handler, middleware);
650
+ }
651
+
652
+ private addRoute(
653
+ method: string,
654
+ path: string,
655
+ handler: HttpHandler,
656
+ middleware?: Middleware[]
657
+ ): void {
658
+ const { pattern, paramNames } = this.pathToRegex(path);
659
+
660
+ const route: RouteEntry = {
661
+ method,
662
+ path,
663
+ pattern,
664
+ paramNames,
665
+ handler,
666
+ middleware: middleware || [],
667
+ };
668
+
669
+ this.routes.push(route);
670
+
671
+ // Optimize route lookup
672
+ if (paramNames.length === 0) {
673
+ // Static route
674
+ this.staticRoutes.set(`${method}:${path}`, route);
675
+ } else {
676
+ // Dynamic route
677
+ this.dynamicRoutes.push(route);
678
+ }
679
+
680
+ this.logger.debug(`Route registered: ${method} ${path}`, 'RouteRegistration');
681
+ }
682
+
683
+ private pathToRegex(path: string): { pattern: RegExp; paramNames: string[] } {
684
+ const paramNames: string[] = [];
685
+ const regexPath = path.replace(/\//g, '\\/').replace(/:([^/]+)/g, (match, paramName) => {
686
+ paramNames.push(paramName);
687
+ return '([^/]+)';
688
+ });
689
+
690
+ return {
691
+ pattern: new RegExp(`^${regexPath}$`),
692
+ paramNames,
693
+ };
694
+ }
695
+
696
+ setHookManager(hookManager: any): void {
697
+ this.hookManager = hookManager;
698
+ }
699
+
700
+ configurePerformance(config: any): void {
701
+ // uWebSockets is already highly optimized
702
+ // This method exists for API compatibility
703
+ this.logger.debug('Performance configuration noted (uWebSockets is pre-optimized)', 'Config');
704
+ }
705
+
706
+ listen(port: number, callback?: () => void): void;
707
+ listen(port: number, host: string, callback?: () => void): void;
708
+ listen(port: number, hostOrCallback?: string | (() => void), callback?: () => void): void {
709
+ // Wrap in async to await init
710
+ this.initPromise
711
+ .then(() => {
712
+ if (this.isListening) {
713
+ this.logger.warn('Server is already listening', 'Listen');
714
+ return;
715
+ }
716
+
717
+ const host = typeof hostOrCallback === 'string' ? hostOrCallback : '0.0.0.0';
718
+ const cb = typeof hostOrCallback === 'function' ? hostOrCallback : callback;
719
+
720
+ this.port = port;
721
+ this.host = host;
722
+
723
+ // Check if we're in a cluster environment
724
+ const isClusterWorker = cluster.isWorker;
725
+ const isClusterPrimary = cluster.isPrimary;
726
+
727
+ // ALWAYS use LIBUS_LISTEN_EXCLUSIVE_PORT when clustering
728
+ // This enables SO_REUSEPORT at the OS level, allowing multiple processes to bind to the same port
729
+ // NOTE: uWebSockets.js API doesn't have listen(host, port, options, cb)
730
+ // We must use listen(port, options, cb) which binds to 0.0.0.0
731
+ const listenOptions = 1; // ALWAYS use LIBUS_LISTEN_EXCLUSIVE_PORT for clustering support
732
+
733
+ this.app.listen(port, listenOptions, (token: any) => {
734
+ if (token) {
735
+ this.listenSocket = token;
736
+ this.isListening = true;
737
+ const clusterInfo = isClusterWorker ? ` (worker ${process.pid})` : '';
738
+ this.logger.info(
739
+ `uWebSockets HTTP server listening on 0.0.0.0:${port}${clusterInfo}`,
740
+ 'Listen'
741
+ );
742
+ if (cb) cb();
743
+ } else {
744
+ const clusterInfo = isClusterWorker ? ` (worker ${process.pid})` : '';
745
+ this.logger.error(`Failed to listen on port ${port}${clusterInfo}`, 'Listen');
746
+ // Don't throw in cluster workers - let them fail gracefully
747
+ if (!isClusterWorker) {
748
+ throw new Error(`Failed to bind to port ${port}`);
749
+ }
750
+ }
751
+ });
752
+ })
753
+ .catch(error => {
754
+ this.logger.error('Failed to initialize server before listen', 'Listen', {
755
+ error: error instanceof Error ? error.message : String(error),
756
+ });
757
+ });
758
+ }
759
+
760
+ async close(callback?: () => void): Promise<void> {
761
+ if (!this.isListening) {
762
+ if (callback) callback();
763
+ return;
764
+ }
765
+
766
+ try {
767
+ // Use stored module reference instead of re-importing
768
+ if (this.listenSocket && this.uws) {
769
+ this.uws.us_listen_socket_close(this.listenSocket);
770
+ this.listenSocket = null;
771
+ this.isListening = false;
772
+ this.logger.info('uWebSockets HTTP server closed', 'Close');
773
+ }
774
+ if (callback) callback();
775
+ } catch (error) {
776
+ this.logger.error('Error closing server', 'Close');
777
+ if (callback) callback();
778
+ }
779
+ }
780
+
781
+ getServer(): any {
782
+ // Return the uWebSockets app for direct access if needed
783
+ return this.app;
784
+ }
785
+
786
+ getApp(): any {
787
+ return this.app;
788
+ }
789
+
790
+ forceCleanup(): void {
791
+ // Cleanup method for compatibility
792
+ this.logger.debug('Force cleanup called', 'Cleanup');
793
+ }
794
+ }