@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
@@ -1,6 +1,6 @@
1
1
  // Moro Logger - Beautiful, Fast, Feature-Rich
2
2
  import { performance } from 'perf_hooks';
3
- // import { format } from 'util'; // Not currently used
3
+
4
4
  import {
5
5
  LogLevel,
6
6
  LogEntry,
@@ -10,7 +10,7 @@ import {
10
10
  LogFilter,
11
11
  LogMetrics,
12
12
  ColorScheme,
13
- } from '../../types/logger';
13
+ } from '../../types/logger.js';
14
14
 
15
15
  export class MoroLogger implements Logger {
16
16
  private level: LogLevel = 'info';
@@ -41,13 +41,27 @@ export class MoroLogger implements Logger {
41
41
  private lastTimestamp = 0;
42
42
  private timestampCacheInterval = 100; // 100ms for better precision
43
43
 
44
- // Buffered output for micro-batching
44
+ // Object pooling for LogEntry objects (Pino's technique)
45
+ private static readonly ENTRY_POOL: LogEntry[] = [];
46
+ private static readonly MAX_POOL_SIZE = 100;
47
+ private static poolIndex = 0;
48
+
49
+ // String builder for efficient concatenation
50
+ private static stringBuilder: string[] = [];
51
+ private static stringBuilderIndex = 0;
52
+
53
+ // Buffered output for performance
45
54
  private outputBuffer: string[] = [];
46
55
  private bufferSize = 0;
47
- private maxBufferSize = 1024; // 1KB buffer
56
+ private maxBufferSize = 1000;
48
57
  private flushTimeout: NodeJS.Timeout | null = null;
49
58
  private flushInterval = 1; // 1ms micro-batching
50
59
 
60
+ // Buffer overflow protection
61
+ private bufferOverflowThreshold: number;
62
+ private emergencyFlushInProgress = false;
63
+ private isDestroyed = false;
64
+
51
65
  // High-performance output methods
52
66
 
53
67
  private static readonly LEVELS: Record<LogLevel, number> = {
@@ -58,84 +72,6 @@ export class MoroLogger implements Logger {
58
72
  fatal: 4,
59
73
  };
60
74
 
61
- // Static pre-allocated strings for maximum performance
62
- private static readonly LEVEL_STRINGS: Record<LogLevel, string> = {
63
- debug: 'DEBUG',
64
- info: 'INFO',
65
- warn: 'WARN',
66
- error: 'ERROR',
67
- fatal: 'FATAL',
68
- };
69
-
70
- // Pre-allocated ANSI color codes
71
- private static readonly ANSI_COLORS = {
72
- reset: '\x1b[0m',
73
- bold: '\x1b[1m',
74
- dim: '\x1b[2m',
75
- red: '\x1b[31m',
76
- green: '\x1b[32m',
77
- yellow: '\x1b[33m',
78
- blue: '\x1b[34m',
79
- magenta: '\x1b[35m',
80
- cyan: '\x1b[36m',
81
- white: '\x1b[37m',
82
- gray: '\x1b[90m',
83
- };
84
-
85
- // Object pool for LogEntry reuse
86
- private static readonly ENTRY_POOL: LogEntry[] = [];
87
- private static readonly MAX_POOL_SIZE = 100;
88
- private static poolIndex = 0;
89
-
90
- // Object pool management
91
- private static getPooledEntry(): LogEntry {
92
- if (MoroLogger.poolIndex > 0) {
93
- return MoroLogger.ENTRY_POOL[--MoroLogger.poolIndex];
94
- }
95
- return {
96
- timestamp: new Date(),
97
- level: 'info',
98
- message: '',
99
- context: undefined,
100
- metadata: undefined,
101
- };
102
- }
103
-
104
- private static returnPooledEntry(entry: LogEntry): void {
105
- if (MoroLogger.poolIndex < MoroLogger.MAX_POOL_SIZE) {
106
- // Reset the entry
107
- entry.timestamp = new Date();
108
- entry.level = 'info';
109
- entry.message = '';
110
- entry.context = undefined;
111
- entry.metadata = undefined;
112
- MoroLogger.ENTRY_POOL[MoroLogger.poolIndex++] = entry;
113
- }
114
- }
115
-
116
- // String builder for efficient concatenation
117
- private static stringBuilder: string[] = [];
118
- private static stringBuilderIndex = 0;
119
-
120
- private static resetStringBuilder(): void {
121
- MoroLogger.stringBuilderIndex = 0;
122
- }
123
-
124
- private static appendToBuilder(str: string): void {
125
- if (MoroLogger.stringBuilderIndex < MoroLogger.stringBuilder.length) {
126
- MoroLogger.stringBuilder[MoroLogger.stringBuilderIndex++] = str;
127
- } else {
128
- MoroLogger.stringBuilder.push(str);
129
- MoroLogger.stringBuilderIndex++;
130
- }
131
- }
132
-
133
- private static buildString(): string {
134
- const result = MoroLogger.stringBuilder.slice(0, MoroLogger.stringBuilderIndex).join('');
135
- MoroLogger.resetStringBuilder();
136
- return result;
137
- }
138
-
139
75
  private static readonly COLORS: ColorScheme = {
140
76
  debug: '\x1b[36m', // Cyan
141
77
  info: '\x1b[32m', // Green
@@ -146,13 +82,23 @@ export class MoroLogger implements Logger {
146
82
  context: '\x1b[34m', // Blue
147
83
  metadata: '\x1b[37m', // White
148
84
  performance: '\x1b[36m', // Cyan
85
+ reset: '\x1b[0m', // Reset
149
86
  };
150
87
 
151
88
  private static readonly RESET = '\x1b[0m';
152
89
  private static readonly BOLD = '\x1b[1m';
153
90
 
91
+ // Static pre-allocated strings for performance
92
+ private static readonly LEVEL_STRINGS: Record<LogLevel, string> = {
93
+ debug: 'DEBUG',
94
+ info: 'INFO ',
95
+ warn: 'WARN ',
96
+ error: 'ERROR',
97
+ fatal: 'FATAL',
98
+ };
99
+
154
100
  constructor(options: LoggerOptions = {}) {
155
- this.options = {
101
+ this.options = this.validateOptions({
156
102
  level: 'info',
157
103
  enableColors: true,
158
104
  enableTimestamp: true,
@@ -163,11 +109,18 @@ export class MoroLogger implements Logger {
163
109
  outputs: [],
164
110
  filters: [],
165
111
  maxEntries: 1000,
112
+ maxBufferSize: 1000,
166
113
  ...options,
167
- };
114
+ });
168
115
 
169
116
  this.level = this.options.level || 'info';
170
117
 
118
+ // Initialize buffer size from options
119
+ this.maxBufferSize = this.options.maxBufferSize || 1000;
120
+
121
+ // Initialize buffer overflow protection
122
+ this.bufferOverflowThreshold = this.maxBufferSize * 2;
123
+
171
124
  // Add default console output
172
125
  this.addOutput({
173
126
  name: 'console',
@@ -180,6 +133,58 @@ export class MoroLogger implements Logger {
180
133
  this.options.filters?.forEach(filter => this.addFilter(filter));
181
134
  }
182
135
 
136
+ // Object pooling methods
137
+ private static getPooledEntry(): LogEntry {
138
+ if (MoroLogger.ENTRY_POOL.length > 0) {
139
+ const entry = MoroLogger.ENTRY_POOL.pop()!;
140
+ // Properly reset ALL properties to prevent memory leaks
141
+ entry.timestamp = new Date();
142
+ entry.level = 'info';
143
+ entry.message = '';
144
+ entry.context = undefined;
145
+ entry.metadata = undefined;
146
+ entry.performance = undefined;
147
+ entry.moduleId = undefined;
148
+ return entry;
149
+ }
150
+ return MoroLogger.createFreshEntry();
151
+ }
152
+
153
+ // ADD this new method:
154
+ private static createFreshEntry(): LogEntry {
155
+ return {
156
+ timestamp: new Date(),
157
+ level: 'info',
158
+ message: '',
159
+ context: undefined,
160
+ metadata: undefined,
161
+ performance: undefined,
162
+ moduleId: undefined,
163
+ };
164
+ }
165
+
166
+ private static returnPooledEntry(entry: LogEntry): void {
167
+ if (MoroLogger.ENTRY_POOL.length < MoroLogger.MAX_POOL_SIZE) {
168
+ MoroLogger.ENTRY_POOL.push(entry);
169
+ }
170
+ }
171
+
172
+ // String builder methods
173
+ private static resetStringBuilder(): void {
174
+ MoroLogger.stringBuilder.length = 0;
175
+ MoroLogger.stringBuilderIndex = 0;
176
+ }
177
+
178
+ private static appendToBuilder(str: string): void {
179
+ MoroLogger.stringBuilder[MoroLogger.stringBuilderIndex++] = str;
180
+ }
181
+
182
+ private static buildString(): string {
183
+ const result = MoroLogger.stringBuilder.join('');
184
+ MoroLogger.resetStringBuilder();
185
+ return result;
186
+ }
187
+
183
188
  debug(message: string, context?: string, metadata?: Record<string, any>): void {
184
189
  this.log('debug', message, context, metadata);
185
190
  }
@@ -222,7 +227,9 @@ export class MoroLogger implements Logger {
222
227
  }
223
228
 
224
229
  child(context: string, metadata?: Record<string, any>): Logger {
225
- const childLogger = new MoroLogger(this.options);
230
+ // Create child logger with current parent level (not original options level)
231
+ const childOptions = { ...this.options, level: this.level };
232
+ const childLogger = new MoroLogger(childOptions);
226
233
  childLogger.contextPrefix = this.contextPrefix ? `${this.contextPrefix}:${context}` : context;
227
234
  childLogger.contextMetadata = { ...this.contextMetadata, ...metadata };
228
235
  childLogger.outputs = this.outputs;
@@ -238,6 +245,10 @@ export class MoroLogger implements Logger {
238
245
  this.level = level;
239
246
  }
240
247
 
248
+ getLevel(): LogLevel {
249
+ return this.level;
250
+ }
251
+
241
252
  addOutput(output: LogOutput): void {
242
253
  this.outputs.set(output.name, output);
243
254
  }
@@ -287,6 +298,17 @@ export class MoroLogger implements Logger {
287
298
  return this.cachedTimestamp;
288
299
  }
289
300
 
301
+ // Cached timestamp generation (updates once per second)
302
+ private getFastCachedTimestamp(): string {
303
+ const now = Date.now();
304
+ if (now - this.lastTimestamp > 1000) {
305
+ // Update every second
306
+ this.lastTimestamp = now;
307
+ this.cachedTimestamp = new Date(now).toISOString().slice(0, 19).replace('T', ' ');
308
+ }
309
+ return this.cachedTimestamp;
310
+ }
311
+
290
312
  getMetrics(): LogMetrics {
291
313
  const now = Date.now();
292
314
  const uptime = (now - this.startTime) / 1000; // seconds
@@ -314,62 +336,54 @@ export class MoroLogger implements Logger {
314
336
  };
315
337
  }
316
338
 
317
- // Optimized logging method with aggressive level checking
339
+ // Optimized logging method
318
340
  private log(
319
341
  level: LogLevel,
320
342
  message: string,
321
343
  context?: string,
322
344
  metadata?: Record<string, any>
323
345
  ): void {
324
- // AGGRESSIVE LEVEL CHECK - numeric comparison for maximum speed
325
- const levelNum = MoroLogger.LEVELS[level];
326
- const effectiveLevelNum = this.parent
327
- ? MoroLogger.LEVELS[this.parent.level]
328
- : MoroLogger.LEVELS[this.level];
346
+ // Prevent logging after destroy() is called (important for test cleanup)
347
+ if (this.isDestroyed) {
348
+ return;
349
+ }
329
350
 
330
- if (levelNum < effectiveLevelNum) {
331
- return; // Exit immediately if level is too low
351
+ // Quick level check - use parent level if available (for child loggers)
352
+ const effectiveLevel = this.parent ? this.parent.level : this.level;
353
+ if (MoroLogger.LEVELS[level] < MoroLogger.LEVELS[effectiveLevel as LogLevel]) {
354
+ return;
332
355
  }
333
356
 
334
- // ULTRA-FAST PATH: Just message, no context, no metadata
357
+ // Absolute minimal path for simple logs - pure speed
335
358
  if (!metadata && !context && !this.contextPrefix && !this.contextMetadata) {
336
- const levelStr = MoroLogger.LEVEL_STRINGS[level];
337
- this.output(`${levelStr} ${message}\n`, level);
359
+ this.writeSimpleLog(level, message);
338
360
  return;
339
361
  }
340
362
 
341
- // FAST PATH: Message + context, no metadata
363
+ // Minimal path for logs with context but no metadata
342
364
  if (!metadata && !this.contextMetadata) {
343
- const levelStr = MoroLogger.LEVEL_STRINGS[level];
344
- if (context) {
345
- this.output(`${levelStr} [${context}] ${message}\n`, level);
346
- } else {
347
- this.output(`${levelStr} ${message}\n`, level);
348
- }
365
+ this.writeSimpleLog(level, message, context);
349
366
  return;
350
367
  }
351
368
 
352
- // MEDIUM PATH: Message + context + simple metadata
353
- if (metadata && Object.keys(metadata).length <= 3 && !this.contextMetadata) {
354
- const levelStr = MoroLogger.LEVEL_STRINGS[level];
355
- const contextStr = context ? `[${context}] ` : '';
356
- const metaStr = this.stringify(metadata);
357
- this.output(`${levelStr} ${contextStr}${message} ${metaStr}\n`, level);
369
+ // Path for complex logs
370
+ if (metadata && Object.keys(metadata).length > 0) {
371
+ this.complexLog(level, message, context, metadata);
358
372
  return;
359
373
  }
360
374
 
361
- // FULL PATH: All features enabled
375
+ // Full logging path for complex logs
362
376
  this.fullLog(level, message, context, metadata);
363
377
  }
364
378
 
365
- // Full logging with all features using object pooling
379
+ // Full logging with all features
366
380
  private fullLog(
367
381
  level: LogLevel,
368
382
  message: string,
369
383
  context?: string,
370
384
  metadata?: Record<string, any>
371
385
  ): void {
372
- // Get pooled entry to avoid allocation
386
+ // Use object pooling for LogEntry (Pino's technique)
373
387
  const entry = MoroLogger.getPooledEntry();
374
388
  const now = Date.now();
375
389
 
@@ -388,6 +402,7 @@ export class MoroLogger implements Logger {
388
402
  if (this.filters.size > 0) {
389
403
  for (const filter of this.filters.values()) {
390
404
  if (!filter.filter(entry)) {
405
+ MoroLogger.returnPooledEntry(entry);
391
406
  return;
392
407
  }
393
408
  }
@@ -402,8 +417,89 @@ export class MoroLogger implements Logger {
402
417
  // Write to outputs with batched processing
403
418
  this.writeToOutputs(entry, level);
404
419
 
405
- // Return entry to pool after a short delay to allow async operations
406
- setTimeout(() => MoroLogger.returnPooledEntry(entry), 0);
420
+ // Return entry to pool
421
+ MoroLogger.returnPooledEntry(entry);
422
+ }
423
+
424
+ // Absolute minimal logging - pure speed, no overhead
425
+ private complexLog(
426
+ level: LogLevel,
427
+ message: string,
428
+ context?: string,
429
+ metadata?: Record<string, any>
430
+ ): void {
431
+ // Use object pooling for LogEntry (Pino's technique)
432
+ const entry = MoroLogger.getPooledEntry();
433
+ const now = Date.now();
434
+
435
+ entry.timestamp = new Date(now);
436
+ entry.level = level;
437
+ entry.message = message;
438
+ entry.context = this.contextPrefix
439
+ ? context
440
+ ? `${this.contextPrefix}:${context}`
441
+ : this.contextPrefix
442
+ : context;
443
+ entry.metadata = this.createMetadata(metadata);
444
+ entry.performance = this.options.enablePerformance ? this.getPerformanceData(now) : undefined;
445
+
446
+ // Write to outputs with batched processing
447
+ this.writeToOutputs(entry, level);
448
+
449
+ // Return entry to pool
450
+ MoroLogger.returnPooledEntry(entry);
451
+ }
452
+
453
+ // Simple log writer with colors for minimal overhead cases
454
+ private writeSimpleLog(level: LogLevel, message: string, context?: string): void {
455
+ const colors = this.options.enableColors !== false;
456
+ const levelReset = colors ? MoroLogger.RESET : '';
457
+
458
+ MoroLogger.resetStringBuilder();
459
+
460
+ // Timestamp with caching optimization
461
+ if (this.options.enableTimestamp !== false) {
462
+ const timestamp = this.getFastCachedTimestamp();
463
+ if (colors) {
464
+ MoroLogger.appendToBuilder(MoroLogger.COLORS.timestamp);
465
+ MoroLogger.appendToBuilder(timestamp);
466
+ MoroLogger.appendToBuilder(levelReset);
467
+ } else {
468
+ MoroLogger.appendToBuilder(timestamp);
469
+ }
470
+ MoroLogger.appendToBuilder(' ');
471
+ }
472
+
473
+ // Level with pre-allocated strings
474
+ const levelStr = MoroLogger.LEVEL_STRINGS[level];
475
+ if (colors) {
476
+ MoroLogger.appendToBuilder(MoroLogger.COLORS[level]);
477
+ MoroLogger.appendToBuilder(MoroLogger.BOLD);
478
+ MoroLogger.appendToBuilder(levelStr);
479
+ MoroLogger.appendToBuilder(levelReset);
480
+ } else {
481
+ MoroLogger.appendToBuilder(levelStr);
482
+ }
483
+
484
+ // Context
485
+ if (context && this.options.enableContext !== false) {
486
+ MoroLogger.appendToBuilder(' ');
487
+ if (colors) {
488
+ MoroLogger.appendToBuilder(MoroLogger.COLORS.context);
489
+ MoroLogger.appendToBuilder(`[${context}]`);
490
+ MoroLogger.appendToBuilder(levelReset);
491
+ } else {
492
+ MoroLogger.appendToBuilder(`[${context}]`);
493
+ }
494
+ }
495
+
496
+ // Message
497
+ MoroLogger.appendToBuilder(' ');
498
+ MoroLogger.appendToBuilder(message);
499
+
500
+ // Output main log line with high-performance method
501
+ const finalMessage = MoroLogger.buildString();
502
+ this.output(`${finalMessage}\n`, level);
407
503
  }
408
504
 
409
505
  private updateMetrics(entry: LogEntry): void {
@@ -457,24 +553,39 @@ export class MoroLogger implements Logger {
457
553
  private writeToOutputs(entry: LogEntry, level: LogLevel): void {
458
554
  if (this.outputs.size === 0) return;
459
555
 
556
+ let successCount = 0;
557
+ const errors: Array<{ outputName: string; error: any }> = [];
558
+
460
559
  for (const output of this.outputs.values()) {
461
560
  if (!output.level || MoroLogger.LEVELS[level] >= MoroLogger.LEVELS[output.level]) {
462
561
  try {
463
562
  output.write(entry);
563
+ successCount++;
464
564
  } catch (error) {
465
- // Fallback to console.error for logger errors
466
- // eslint-disable-next-line no-console
467
- console.error('Logger output error:', error);
565
+ errors.push({ outputName: output.name, error });
566
+ this.handleOutputError(output.name, error);
468
567
  }
469
568
  }
470
569
  }
570
+
571
+ // If all outputs fail, use emergency console
572
+ if (successCount === 0 && this.outputs.size > 0) {
573
+ this.emergencyConsoleWrite(entry);
574
+ }
575
+
576
+ // Log output errors (but avoid infinite loops)
577
+ if (errors.length > 0 && level !== 'error') {
578
+ this.error(`Logger output errors: ${errors.length} failed`, 'MoroLogger', {
579
+ errors: errors.map(e => e.outputName),
580
+ });
581
+ }
471
582
  }
472
583
 
473
584
  private writeToConsole(entry: LogEntry): void {
474
585
  const format = this.options.format || 'pretty';
475
586
 
476
587
  if (format === 'json') {
477
- this.output(JSON.stringify(entry) + '\n', entry.level);
588
+ this.output(`${this.safeStringify(entry)}\n`, entry.level);
478
589
  return;
479
590
  }
480
591
 
@@ -491,6 +602,8 @@ export class MoroLogger implements Logger {
491
602
 
492
603
  private writePrettyLog(entry: LogEntry): void {
493
604
  const colors = this.options.enableColors !== false;
605
+ const levelReset = colors ? MoroLogger.RESET : '';
606
+
494
607
  MoroLogger.resetStringBuilder();
495
608
 
496
609
  // Timestamp with caching optimization
@@ -499,37 +612,29 @@ export class MoroLogger implements Logger {
499
612
  if (colors) {
500
613
  MoroLogger.appendToBuilder(MoroLogger.COLORS.timestamp);
501
614
  MoroLogger.appendToBuilder(timestamp);
502
- MoroLogger.appendToBuilder(MoroLogger.RESET);
615
+ MoroLogger.appendToBuilder(levelReset);
503
616
  } else {
504
617
  MoroLogger.appendToBuilder(timestamp);
505
618
  }
506
- }
507
-
508
- // Level with color using pre-allocated strings
509
- const levelColor = colors ? MoroLogger.COLORS[entry.level] : '';
510
- const levelReset = colors ? MoroLogger.RESET : '';
511
- const levelText = MoroLogger.LEVEL_STRINGS[entry.level];
512
-
513
- // Add space after timestamp if present
514
- if (this.options.enableTimestamp !== false) {
515
619
  MoroLogger.appendToBuilder(' ');
516
620
  }
517
621
 
622
+ // Level with pre-allocated strings
623
+ const levelStr = MoroLogger.LEVEL_STRINGS[entry.level];
518
624
  if (colors) {
519
- MoroLogger.appendToBuilder(levelColor);
625
+ MoroLogger.appendToBuilder(MoroLogger.COLORS[entry.level]);
520
626
  MoroLogger.appendToBuilder(MoroLogger.BOLD);
521
- MoroLogger.appendToBuilder(levelText);
627
+ MoroLogger.appendToBuilder(levelStr);
522
628
  MoroLogger.appendToBuilder(levelReset);
523
629
  } else {
524
- MoroLogger.appendToBuilder(levelText);
630
+ MoroLogger.appendToBuilder(levelStr);
525
631
  }
526
632
 
527
633
  // Context
528
634
  if (entry.context && this.options.enableContext !== false) {
529
- const contextColor = colors ? MoroLogger.COLORS.context : '';
530
- MoroLogger.appendToBuilder(' '); // Space before context
635
+ MoroLogger.appendToBuilder(' ');
531
636
  if (colors) {
532
- MoroLogger.appendToBuilder(contextColor);
637
+ MoroLogger.appendToBuilder(MoroLogger.COLORS.context);
533
638
  MoroLogger.appendToBuilder(`[${entry.context}]`);
534
639
  MoroLogger.appendToBuilder(levelReset);
535
640
  } else {
@@ -538,7 +643,7 @@ export class MoroLogger implements Logger {
538
643
  }
539
644
 
540
645
  // Message
541
- MoroLogger.appendToBuilder(' '); // Space before message
646
+ MoroLogger.appendToBuilder(' ');
542
647
  MoroLogger.appendToBuilder(entry.message);
543
648
 
544
649
  // Performance info
@@ -554,7 +659,7 @@ export class MoroLogger implements Logger {
554
659
  }
555
660
 
556
661
  if (perfParts.length > 0) {
557
- MoroLogger.appendToBuilder(' '); // Space before performance info
662
+ MoroLogger.appendToBuilder(' ');
558
663
  if (colors) {
559
664
  MoroLogger.appendToBuilder(perfColor);
560
665
  MoroLogger.appendToBuilder(`(${perfParts.join(', ')})`);
@@ -575,19 +680,20 @@ export class MoroLogger implements Logger {
575
680
  const cleanMetadata = this.cleanMetadata(entry.metadata);
576
681
 
577
682
  if (Object.keys(cleanMetadata).length > 0) {
683
+ MoroLogger.appendToBuilder(' ');
578
684
  if (colors) {
579
685
  MoroLogger.appendToBuilder(metaColor);
580
- MoroLogger.appendToBuilder(this.stringify(cleanMetadata));
686
+ MoroLogger.appendToBuilder(this.safeStringify(cleanMetadata));
581
687
  MoroLogger.appendToBuilder(levelReset);
582
688
  } else {
583
- MoroLogger.appendToBuilder(this.stringify(cleanMetadata));
689
+ MoroLogger.appendToBuilder(this.safeStringify(cleanMetadata));
584
690
  }
585
691
  }
586
692
  }
587
693
 
588
694
  // Output main log line with high-performance method
589
695
  const finalMessage = MoroLogger.buildString();
590
- this.output(finalMessage + '\n', entry.level);
696
+ this.output(`${finalMessage}\n`, entry.level);
591
697
 
592
698
  // Stack trace for errors
593
699
  if (entry.metadata?.stack && (entry.level === 'error' || entry.level === 'fatal')) {
@@ -607,79 +713,199 @@ export class MoroLogger implements Logger {
607
713
  return clean;
608
714
  }
609
715
 
610
- // Fast JSON stringify with error handling
611
- private stringify(obj: any): string {
612
- try {
613
- return JSON.stringify(obj);
614
- } catch {
615
- return '[Circular Reference]';
716
+ // High-performance output with buffering
717
+ private output(message: string, level: LogLevel = 'info'): void {
718
+ // Prevent memory exhaustion
719
+ if (
720
+ this.outputBuffer.length >= this.bufferOverflowThreshold &&
721
+ !this.emergencyFlushInProgress
722
+ ) {
723
+ this.emergencyFlushInProgress = true;
724
+ this.forceFlushBuffer();
725
+ this.emergencyFlushInProgress = false;
616
726
  }
617
- }
618
727
 
619
- // High-performance output with micro-batching
620
- private output(message: string, level: LogLevel = 'info'): void {
621
- // Add to buffer
622
728
  this.outputBuffer.push(message);
623
- this.bufferSize += message.length;
729
+ this.bufferSize++;
624
730
 
625
- // Flush immediately if buffer is full or for errors
626
- if (this.bufferSize >= this.maxBufferSize || level === 'error' || level === 'fatal') {
731
+ // Immediate flush for critical levels or full buffer
732
+ if (level === 'fatal' || level === 'error' || this.bufferSize >= this.maxBufferSize) {
627
733
  this.flushBuffer();
628
734
  } else {
629
- // Schedule flush with micro-batching
630
735
  this.scheduleFlush();
631
736
  }
632
737
  }
633
738
 
634
739
  private scheduleFlush(): void {
635
- if (this.flushTimeout) return; // Already scheduled
740
+ if (this.flushTimeout || this.isDestroyed) {
741
+ return; // Already scheduled or destroyed
742
+ }
636
743
 
637
744
  this.flushTimeout = setTimeout(() => {
638
745
  this.flushBuffer();
639
- this.flushTimeout = null;
640
746
  }, this.flushInterval);
747
+
748
+ // Unref the timeout so it doesn't prevent process exit (important for tests)
749
+ this.flushTimeout.unref();
641
750
  }
642
751
 
643
- private flushBuffer(): void {
644
- if (this.outputBuffer.length === 0) return;
752
+ public flushBuffer(): void {
753
+ if (this.outputBuffer.length === 0) {
754
+ return;
755
+ }
645
756
 
646
- try {
647
- // Group by stream type for efficiency
648
- const stdoutMessages: string[] = [];
649
- const stderrMessages: string[] = [];
650
-
651
- for (const message of this.outputBuffer) {
652
- // Determine stream based on message content (simple heuristic)
653
- if (message.includes('ERROR') || message.includes('FATAL')) {
654
- stderrMessages.push(message);
655
- } else {
656
- stdoutMessages.push(message);
657
- }
757
+ // Group messages by stream type
758
+ const stdoutMessages: string[] = [];
759
+ const stderrMessages: string[] = [];
760
+
761
+ for (const message of this.outputBuffer) {
762
+ // Determine stream based on message content or level
763
+ if (message.includes('ERROR') || message.includes('FATAL')) {
764
+ stderrMessages.push(message);
765
+ } else {
766
+ stdoutMessages.push(message);
658
767
  }
768
+ }
659
769
 
660
- // Write to streams
661
- if (stdoutMessages.length > 0) {
770
+ // Write to appropriate streams with error handling
771
+ try {
772
+ if (stdoutMessages.length > 0 && process.stdout.writable) {
662
773
  process.stdout.write(stdoutMessages.join(''));
663
774
  }
664
- if (stderrMessages.length > 0) {
775
+ if (stderrMessages.length > 0 && process.stderr.writable) {
665
776
  process.stderr.write(stderrMessages.join(''));
666
777
  }
667
778
  } catch {
668
- // Fallback to console methods if stream write fails
669
- for (const message of this.outputBuffer) {
670
- if (message.includes('ERROR') || message.includes('FATAL')) {
671
- // eslint-disable-next-line no-console
672
- console.error(message.trim());
673
- } else {
674
- // eslint-disable-next-line no-console
675
- console.log(message.trim());
676
- }
779
+ // Fallback to console if streams fail
780
+ try {
781
+ // eslint-disable-next-line no-console
782
+ console.log(this.outputBuffer.join(''));
783
+ } catch {
784
+ // If even console.log fails, just ignore
677
785
  }
678
786
  }
679
787
 
680
- // Reset buffer
788
+ // Clear buffer
681
789
  this.outputBuffer.length = 0;
682
790
  this.bufferSize = 0;
791
+
792
+ // Clear timeout
793
+ if (this.flushTimeout) {
794
+ clearTimeout(this.flushTimeout);
795
+ this.flushTimeout = null;
796
+ }
797
+ }
798
+
799
+ // Emergency flush for buffer overflow protection
800
+ private forceFlushBuffer(): void {
801
+ if (this.outputBuffer.length === 0) return;
802
+
803
+ try {
804
+ const message = this.outputBuffer.join('');
805
+ process.stdout.write(message);
806
+ } catch (error) {
807
+ // Emergency fallback - write individual messages
808
+ for (const msg of this.outputBuffer) {
809
+ try {
810
+ process.stdout.write(msg);
811
+ } catch {
812
+ // If even this fails, give up on this batch
813
+ break;
814
+ }
815
+ }
816
+ } finally {
817
+ this.outputBuffer.length = 0;
818
+ this.bufferSize = 0;
819
+ }
820
+ }
821
+
822
+ // Safe stringify with circular reference detection
823
+ private safeStringify(obj: any, maxDepth = 3): string {
824
+ const seen = new WeakSet();
825
+
826
+ const stringify = (value: any, depth: number): any => {
827
+ if (depth > maxDepth) return '[Max Depth Reached]';
828
+ if (value === null || typeof value !== 'object') return value;
829
+ if (seen.has(value)) return '[Circular Reference]';
830
+
831
+ seen.add(value);
832
+
833
+ if (Array.isArray(value)) {
834
+ return value.map(item => stringify(item, depth + 1));
835
+ }
836
+
837
+ const result: any = {};
838
+ for (const [key, val] of Object.entries(value)) {
839
+ if (typeof val !== 'function') {
840
+ // Skip functions
841
+ result[key] = stringify(val, depth + 1);
842
+ }
843
+ }
844
+ return result;
845
+ };
846
+
847
+ try {
848
+ return JSON.stringify(stringify(obj, 0));
849
+ } catch (error) {
850
+ return '[Stringify Error]';
851
+ }
852
+ }
853
+
854
+ // Configuration validation
855
+ private validateOptions(options: LoggerOptions): LoggerOptions {
856
+ const validated = { ...options };
857
+
858
+ // Validate log level
859
+ const validLevels = ['debug', 'info', 'warn', 'error', 'fatal'];
860
+ if (validated.level && !validLevels.includes(validated.level)) {
861
+ console.warn(`[MoroLogger] Invalid log level: ${validated.level}, defaulting to 'info'`);
862
+ validated.level = 'info';
863
+ }
864
+
865
+ // Validate max entries
866
+ if (validated.maxEntries !== undefined) {
867
+ if (validated.maxEntries < 1 || validated.maxEntries > 100000) {
868
+ console.warn(
869
+ `[MoroLogger] Invalid maxEntries: ${validated.maxEntries}, defaulting to 1000`
870
+ );
871
+ validated.maxEntries = 1000;
872
+ }
873
+ }
874
+
875
+ // Validate buffer size
876
+ if (validated.maxBufferSize !== undefined) {
877
+ if (validated.maxBufferSize < 10 || validated.maxBufferSize > 10000) {
878
+ console.warn(
879
+ `[MoroLogger] Invalid maxBufferSize: ${validated.maxBufferSize}, defaulting to 1000`
880
+ );
881
+ validated.maxBufferSize = 1000;
882
+ }
883
+ }
884
+
885
+ return validated;
886
+ }
887
+
888
+ // Error handling methods
889
+ private handleOutputError(outputName: string, error: any): void {
890
+ // Could implement output retry logic, circuit breaker, etc.
891
+ // For now, just track the error
892
+ if (!this.metrics.outputErrors) {
893
+ this.metrics.outputErrors = {};
894
+ }
895
+ this.metrics.outputErrors[outputName] = (this.metrics.outputErrors[outputName] || 0) + 1;
896
+ }
897
+
898
+ private emergencyConsoleWrite(entry: LogEntry): void {
899
+ const message = `${entry.timestamp.toISOString()} ${entry.level.toUpperCase()} ${entry.message}`;
900
+ try {
901
+ if (entry.level === 'error' || entry.level === 'fatal') {
902
+ process.stderr.write(`[EMERGENCY] ${message}\n`);
903
+ } else {
904
+ process.stdout.write(`[EMERGENCY] ${message}\n`);
905
+ }
906
+ } catch {
907
+ // If even emergency write fails, there's nothing more we can do
908
+ }
683
909
  }
684
910
 
685
911
  // Force flush streams (useful for shutdown)
@@ -694,28 +920,40 @@ export class MoroLogger implements Logger {
694
920
  this.flushBuffer();
695
921
 
696
922
  try {
697
- // Force flush streams
923
+ // Force flush streams without ending them
698
924
  if (process.stdout.writable) {
699
- process.stdout.end();
925
+ process.stdout.write(''); // Force flush without ending
700
926
  }
701
927
  if (process.stderr.writable) {
702
- process.stderr.end();
928
+ process.stderr.write(''); // Force flush without ending
703
929
  }
704
930
  } catch {
705
931
  // Ignore flush errors
706
932
  }
707
933
  }
708
934
 
709
- // Cleanup method to clear all timeouts and handles
710
- public cleanup(): void {
711
- // Clear any pending flush timeout
935
+ // Destroy logger and clean up all resources (for testing)
936
+ public destroy(): void {
937
+ // Mark as destroyed to prevent new timeouts
938
+ this.isDestroyed = true;
939
+
940
+ // Clear any remaining timeouts
712
941
  if (this.flushTimeout) {
713
942
  clearTimeout(this.flushTimeout);
714
943
  this.flushTimeout = null;
715
944
  }
716
945
 
717
- // Flush any remaining output
946
+ // Flush any remaining buffer
718
947
  this.flushBuffer();
948
+
949
+ // Clear outputs and filters
950
+ this.outputs.clear();
951
+ this.filters.clear();
952
+
953
+ // Clear history
954
+ this.history.length = 0;
955
+ this.historyIndex = 0;
956
+ this.historySize = 0;
719
957
  }
720
958
  }
721
959
 
@@ -731,33 +969,6 @@ export const logger = new MoroLogger({
731
969
  format: (process.env.LOG_FORMAT as any) || 'pretty',
732
970
  });
733
971
 
734
- // Add cleanup handlers for Jest and other test runners
735
- if (typeof process !== 'undefined') {
736
- // Cleanup on process exit
737
- process.on('beforeExit', () => {
738
- logger.cleanup();
739
- });
740
-
741
- process.on('SIGINT', () => {
742
- logger.cleanup();
743
- process.exit(0);
744
- });
745
-
746
- process.on('SIGTERM', () => {
747
- logger.cleanup();
748
- process.exit(0);
749
- });
750
-
751
- // For Jest and other test runners - cleanup on uncaught exceptions
752
- process.on('uncaughtException', () => {
753
- logger.cleanup();
754
- });
755
-
756
- process.on('unhandledRejection', () => {
757
- logger.cleanup();
758
- });
759
- }
760
-
761
972
  /**
762
973
  * Configure the global logger with new settings
763
974
  * This allows runtime configuration of the logger
@@ -770,6 +981,14 @@ export function configureGlobalLogger(options: Partial<LoggerOptions>): void {
770
981
  // For now, focusing on level which is the most critical
771
982
  }
772
983
 
984
+ /**
985
+ * Destroy the global logger and clean up resources (for testing)
986
+ * @internal
987
+ */
988
+ export function destroyGlobalLogger(): void {
989
+ logger.destroy();
990
+ }
991
+
773
992
  /**
774
993
  * Apply logging configuration from the config system and/or createApp options
775
994
  */