@morojs/moro 1.6.6 → 1.7.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 (432) hide show
  1. package/README.md +22 -4
  2. package/dist/core/auth/morojs-adapter.js +33 -20
  3. package/dist/core/auth/morojs-adapter.js.map +1 -1
  4. package/dist/core/config/config-sources.js +71 -15
  5. package/dist/core/config/config-sources.js.map +1 -1
  6. package/dist/core/config/config-validator.js +201 -6
  7. package/dist/core/config/config-validator.js.map +1 -1
  8. package/dist/core/database/adapters/drizzle.js +5 -5
  9. package/dist/core/database/adapters/drizzle.js.map +1 -1
  10. package/dist/core/database/adapters/mongodb.js +5 -1
  11. package/dist/core/database/adapters/mongodb.js.map +1 -1
  12. package/dist/core/database/adapters/mysql.js +5 -1
  13. package/dist/core/database/adapters/mysql.js.map +1 -1
  14. package/dist/core/database/adapters/postgresql.js +1 -1
  15. package/dist/core/database/adapters/postgresql.js.map +1 -1
  16. package/dist/core/database/adapters/redis.js +2 -2
  17. package/dist/core/database/adapters/redis.js.map +1 -1
  18. package/dist/core/database/adapters/sqlite.js +5 -1
  19. package/dist/core/database/adapters/sqlite.js.map +1 -1
  20. package/dist/core/docs/index.js.map +1 -1
  21. package/dist/core/docs/openapi-generator.js +8 -9
  22. package/dist/core/docs/openapi-generator.js.map +1 -1
  23. package/dist/core/docs/simple-docs.js +2 -1
  24. package/dist/core/docs/simple-docs.js.map +1 -1
  25. package/dist/core/docs/swagger-ui.js +1 -0
  26. package/dist/core/docs/swagger-ui.js.map +1 -1
  27. package/dist/core/docs/zod-to-openapi.js +4 -0
  28. package/dist/core/docs/zod-to-openapi.js.map +1 -1
  29. package/dist/core/events/event-bus.d.ts +1 -1
  30. package/dist/core/events/event-bus.js +2 -1
  31. package/dist/core/events/event-bus.js.map +1 -1
  32. package/dist/core/framework.d.ts +5 -3
  33. package/dist/core/framework.js +28 -25
  34. package/dist/core/framework.js.map +1 -1
  35. package/dist/core/graphql/adapter.d.ts +73 -0
  36. package/dist/core/graphql/adapter.js +2 -0
  37. package/dist/core/graphql/adapter.js.map +1 -0
  38. package/dist/core/graphql/adapters/graphql-js-adapter.d.ts +26 -0
  39. package/dist/core/graphql/adapters/graphql-js-adapter.js +229 -0
  40. package/dist/core/graphql/adapters/graphql-js-adapter.js.map +1 -0
  41. package/dist/core/graphql/core.d.ts +60 -0
  42. package/dist/core/graphql/core.js +191 -0
  43. package/dist/core/graphql/core.js.map +1 -0
  44. package/dist/core/graphql/index.d.ts +4 -0
  45. package/dist/core/graphql/index.js +4 -0
  46. package/dist/core/graphql/index.js.map +1 -0
  47. package/dist/core/graphql/loader.d.ts +9 -0
  48. package/dist/core/graphql/loader.js +32 -0
  49. package/dist/core/graphql/loader.js.map +1 -0
  50. package/dist/core/graphql/types.d.ts +211 -0
  51. package/dist/core/graphql/types.js +2 -0
  52. package/dist/core/graphql/types.js.map +1 -0
  53. package/dist/core/grpc/adapters/grpc-js-adapter.d.ts +28 -0
  54. package/dist/core/grpc/adapters/grpc-js-adapter.js +449 -0
  55. package/dist/core/grpc/adapters/grpc-js-adapter.js.map +1 -0
  56. package/dist/core/grpc/adapters/index.d.ts +1 -0
  57. package/dist/core/grpc/adapters/index.js +6 -0
  58. package/dist/core/grpc/adapters/index.js.map +1 -0
  59. package/dist/core/grpc/grpc-adapter.d.ts +47 -0
  60. package/dist/core/grpc/grpc-adapter.js +4 -0
  61. package/dist/core/grpc/grpc-adapter.js.map +1 -0
  62. package/dist/core/grpc/grpc-manager.d.ts +59 -0
  63. package/dist/core/grpc/grpc-manager.js +218 -0
  64. package/dist/core/grpc/grpc-manager.js.map +1 -0
  65. package/dist/core/grpc/index.d.ts +7 -0
  66. package/dist/core/grpc/index.js +10 -0
  67. package/dist/core/grpc/index.js.map +1 -0
  68. package/dist/core/grpc/middleware/auth.d.ts +22 -0
  69. package/dist/core/grpc/middleware/auth.js +126 -0
  70. package/dist/core/grpc/middleware/auth.js.map +1 -0
  71. package/dist/core/grpc/middleware/logging.d.ts +19 -0
  72. package/dist/core/grpc/middleware/logging.js +57 -0
  73. package/dist/core/grpc/middleware/logging.js.map +1 -0
  74. package/dist/core/grpc/middleware/validation.d.ts +18 -0
  75. package/dist/core/grpc/middleware/validation.js +126 -0
  76. package/dist/core/grpc/middleware/validation.js.map +1 -0
  77. package/dist/core/grpc/types.d.ts +233 -0
  78. package/dist/core/grpc/types.js +36 -0
  79. package/dist/core/grpc/types.js.map +1 -0
  80. package/dist/core/http/http-server.d.ts +13 -84
  81. package/dist/core/http/http-server.js +216 -781
  82. package/dist/core/http/http-server.js.map +1 -1
  83. package/dist/core/http/http2-server.d.ts +131 -0
  84. package/dist/core/http/http2-server.js +803 -0
  85. package/dist/core/http/http2-server.js.map +1 -0
  86. package/dist/core/http/index.d.ts +3 -1
  87. package/dist/core/http/index.js +2 -1
  88. package/dist/core/http/index.js.map +1 -1
  89. package/dist/core/http/utils/uws-worker-clustering.d.ts +28 -0
  90. package/dist/core/http/utils/uws-worker-clustering.js +313 -0
  91. package/dist/core/http/utils/uws-worker-clustering.js.map +1 -0
  92. package/dist/core/http/uws-http-server.d.ts +3 -1
  93. package/dist/core/http/uws-http-server.js +58 -34
  94. package/dist/core/http/uws-http-server.js.map +1 -1
  95. package/dist/core/jobs/cron-parser.d.ts +62 -0
  96. package/dist/core/jobs/cron-parser.js +239 -0
  97. package/dist/core/jobs/cron-parser.js.map +1 -0
  98. package/dist/core/jobs/index.d.ts +12 -0
  99. package/dist/core/jobs/index.js +9 -0
  100. package/dist/core/jobs/index.js.map +1 -0
  101. package/dist/core/jobs/job-executor.d.ts +134 -0
  102. package/dist/core/jobs/job-executor.js +418 -0
  103. package/dist/core/jobs/job-executor.js.map +1 -0
  104. package/dist/core/jobs/job-scheduler.d.ts +214 -0
  105. package/dist/core/jobs/job-scheduler.js +554 -0
  106. package/dist/core/jobs/job-scheduler.js.map +1 -0
  107. package/dist/core/jobs/job-state-manager.d.ts +158 -0
  108. package/dist/core/jobs/job-state-manager.js +444 -0
  109. package/dist/core/jobs/job-state-manager.js.map +1 -0
  110. package/dist/core/jobs/leader-election.d.ts +124 -0
  111. package/dist/core/jobs/leader-election.js +482 -0
  112. package/dist/core/jobs/leader-election.js.map +1 -0
  113. package/dist/core/jobs/types.d.ts +151 -0
  114. package/dist/core/jobs/types.js +4 -0
  115. package/dist/core/jobs/types.js.map +1 -0
  116. package/dist/core/jobs/utils.d.ts +95 -0
  117. package/dist/core/jobs/utils.js +258 -0
  118. package/dist/core/jobs/utils.js.map +1 -0
  119. package/dist/core/logger/filters.js +2 -0
  120. package/dist/core/logger/filters.js.map +1 -1
  121. package/dist/core/logger/logger.js +48 -21
  122. package/dist/core/logger/logger.js.map +1 -1
  123. package/dist/core/logger/outputs.js +11 -3
  124. package/dist/core/logger/outputs.js.map +1 -1
  125. package/dist/core/mail/adapters/console-adapter.d.ts +14 -0
  126. package/dist/core/mail/adapters/console-adapter.js +89 -0
  127. package/dist/core/mail/adapters/console-adapter.js.map +1 -0
  128. package/dist/core/mail/adapters/index.d.ts +5 -0
  129. package/dist/core/mail/adapters/index.js +8 -0
  130. package/dist/core/mail/adapters/index.js.map +1 -0
  131. package/dist/core/mail/adapters/nodemailer-adapter.d.ts +18 -0
  132. package/dist/core/mail/adapters/nodemailer-adapter.js +188 -0
  133. package/dist/core/mail/adapters/nodemailer-adapter.js.map +1 -0
  134. package/dist/core/mail/adapters/resend-adapter.d.ts +18 -0
  135. package/dist/core/mail/adapters/resend-adapter.js +169 -0
  136. package/dist/core/mail/adapters/resend-adapter.js.map +1 -0
  137. package/dist/core/mail/adapters/sendgrid-adapter.d.ts +19 -0
  138. package/dist/core/mail/adapters/sendgrid-adapter.js +186 -0
  139. package/dist/core/mail/adapters/sendgrid-adapter.js.map +1 -0
  140. package/dist/core/mail/adapters/ses-adapter.d.ts +18 -0
  141. package/dist/core/mail/adapters/ses-adapter.js +167 -0
  142. package/dist/core/mail/adapters/ses-adapter.js.map +1 -0
  143. package/dist/core/mail/index.d.ts +5 -0
  144. package/dist/core/mail/index.js +8 -0
  145. package/dist/core/mail/index.js.map +1 -0
  146. package/dist/core/mail/mail-adapter.d.ts +62 -0
  147. package/dist/core/mail/mail-adapter.js +83 -0
  148. package/dist/core/mail/mail-adapter.js.map +1 -0
  149. package/dist/core/mail/mail-manager.d.ts +63 -0
  150. package/dist/core/mail/mail-manager.js +302 -0
  151. package/dist/core/mail/mail-manager.js.map +1 -0
  152. package/dist/core/mail/template-engine.d.ts +43 -0
  153. package/dist/core/mail/template-engine.js +239 -0
  154. package/dist/core/mail/template-engine.js.map +1 -0
  155. package/dist/core/mail/types.d.ts +237 -0
  156. package/dist/core/mail/types.js +4 -0
  157. package/dist/core/mail/types.js.map +1 -0
  158. package/dist/core/middleware/built-in/auth/helpers.js +1 -1
  159. package/dist/core/middleware/built-in/auth/helpers.js.map +1 -1
  160. package/dist/core/middleware/built-in/auth/jwt-helpers.js +1 -1
  161. package/dist/core/middleware/built-in/auth/jwt-helpers.js.map +1 -1
  162. package/dist/core/middleware/built-in/auth/providers.js +1 -1
  163. package/dist/core/middleware/built-in/auth/providers.js.map +1 -1
  164. package/dist/core/middleware/built-in/body-size/core.d.ts +12 -0
  165. package/dist/core/middleware/built-in/body-size/core.js +52 -0
  166. package/dist/core/middleware/built-in/body-size/core.js.map +1 -0
  167. package/dist/core/middleware/built-in/body-size/hook.d.ts +2 -0
  168. package/dist/core/middleware/built-in/body-size/hook.js +12 -0
  169. package/dist/core/middleware/built-in/body-size/hook.js.map +1 -0
  170. package/dist/core/middleware/built-in/body-size/index.d.ts +6 -0
  171. package/dist/core/middleware/built-in/body-size/index.js +7 -0
  172. package/dist/core/middleware/built-in/body-size/index.js.map +1 -0
  173. package/dist/core/middleware/built-in/body-size/middleware.d.ts +14 -0
  174. package/dist/core/middleware/built-in/body-size/middleware.js +22 -0
  175. package/dist/core/middleware/built-in/body-size/middleware.js.map +1 -0
  176. package/dist/core/middleware/built-in/cache/adapters/cache/file.js +3 -3
  177. package/dist/core/middleware/built-in/cache/adapters/cache/file.js.map +1 -1
  178. package/dist/core/middleware/built-in/cache/adapters/cache/memory.js +1 -0
  179. package/dist/core/middleware/built-in/cache/adapters/cache/memory.js.map +1 -1
  180. package/dist/core/middleware/built-in/cache/adapters/cache/redis.js +1 -1
  181. package/dist/core/middleware/built-in/cache/adapters/cache/redis.js.map +1 -1
  182. package/dist/core/middleware/built-in/cache/core.d.ts +20 -1
  183. package/dist/core/middleware/built-in/cache/core.js.map +1 -1
  184. package/dist/core/middleware/built-in/cache/hook.d.ts +38 -1
  185. package/dist/core/middleware/built-in/cache/hook.js +202 -16
  186. package/dist/core/middleware/built-in/cache/hook.js.map +1 -1
  187. package/dist/core/middleware/built-in/cache/index.js +1 -1
  188. package/dist/core/middleware/built-in/cache/index.js.map +1 -1
  189. package/dist/core/middleware/built-in/cdn/adapters/cdn/azure.d.ts +8 -0
  190. package/dist/core/middleware/built-in/cdn/adapters/cdn/azure.js +100 -7
  191. package/dist/core/middleware/built-in/cdn/adapters/cdn/azure.js.map +1 -1
  192. package/dist/core/middleware/built-in/cdn/adapters/cdn/cloudflare.d.ts +6 -0
  193. package/dist/core/middleware/built-in/cdn/adapters/cdn/cloudflare.js +97 -13
  194. package/dist/core/middleware/built-in/cdn/adapters/cdn/cloudflare.js.map +1 -1
  195. package/dist/core/middleware/built-in/cdn/adapters/cdn/cloudfront.js +1 -1
  196. package/dist/core/middleware/built-in/cdn/adapters/cdn/cloudfront.js.map +1 -1
  197. package/dist/core/middleware/built-in/compression/core.d.ts +16 -0
  198. package/dist/core/middleware/built-in/compression/core.js +75 -0
  199. package/dist/core/middleware/built-in/compression/core.js.map +1 -0
  200. package/dist/core/middleware/built-in/compression/hook.d.ts +2 -0
  201. package/dist/core/middleware/built-in/compression/hook.js +14 -0
  202. package/dist/core/middleware/built-in/compression/hook.js.map +1 -0
  203. package/dist/core/middleware/built-in/compression/index.d.ts +6 -0
  204. package/dist/core/middleware/built-in/compression/index.js +7 -0
  205. package/dist/core/middleware/built-in/compression/index.js.map +1 -0
  206. package/dist/core/middleware/built-in/compression/middleware.d.ts +20 -0
  207. package/dist/core/middleware/built-in/compression/middleware.js +28 -0
  208. package/dist/core/middleware/built-in/compression/middleware.js.map +1 -0
  209. package/dist/core/middleware/built-in/cookie/core.js +37 -9
  210. package/dist/core/middleware/built-in/cookie/core.js.map +1 -1
  211. package/dist/core/middleware/built-in/cookie/hook.d.ts +1 -1
  212. package/dist/core/middleware/built-in/cookie/hook.js +2 -2
  213. package/dist/core/middleware/built-in/cookie/hook.js.map +1 -1
  214. package/dist/core/middleware/built-in/csrf/core.js +1 -0
  215. package/dist/core/middleware/built-in/csrf/core.js.map +1 -1
  216. package/dist/core/middleware/built-in/graphql/core.d.ts +11 -0
  217. package/dist/core/middleware/built-in/graphql/core.js +24 -0
  218. package/dist/core/middleware/built-in/graphql/core.js.map +1 -0
  219. package/dist/core/middleware/built-in/graphql/helpers.d.ts +69 -0
  220. package/dist/core/middleware/built-in/graphql/helpers.js +187 -0
  221. package/dist/core/middleware/built-in/graphql/helpers.js.map +1 -0
  222. package/dist/core/middleware/built-in/graphql/hook.d.ts +7 -0
  223. package/dist/core/middleware/built-in/graphql/hook.js +78 -0
  224. package/dist/core/middleware/built-in/graphql/hook.js.map +1 -0
  225. package/dist/core/middleware/built-in/graphql/index.d.ts +5 -0
  226. package/dist/core/middleware/built-in/graphql/index.js +5 -0
  227. package/dist/core/middleware/built-in/graphql/index.js.map +1 -0
  228. package/dist/core/middleware/built-in/graphql/middleware.d.ts +7 -0
  229. package/dist/core/middleware/built-in/graphql/middleware.js +54 -0
  230. package/dist/core/middleware/built-in/graphql/middleware.js.map +1 -0
  231. package/dist/core/middleware/built-in/graphql/subscriptions.d.ts +20 -0
  232. package/dist/core/middleware/built-in/graphql/subscriptions.js +37 -0
  233. package/dist/core/middleware/built-in/graphql/subscriptions.js.map +1 -0
  234. package/dist/core/middleware/built-in/helmet/core.d.ts +19 -0
  235. package/dist/core/middleware/built-in/helmet/core.js +70 -0
  236. package/dist/core/middleware/built-in/helmet/core.js.map +1 -0
  237. package/dist/core/middleware/built-in/helmet/hook.d.ts +2 -0
  238. package/dist/core/middleware/built-in/helmet/hook.js +12 -0
  239. package/dist/core/middleware/built-in/helmet/hook.js.map +1 -0
  240. package/dist/core/middleware/built-in/helmet/index.d.ts +6 -0
  241. package/dist/core/middleware/built-in/helmet/index.js +7 -0
  242. package/dist/core/middleware/built-in/helmet/index.js.map +1 -0
  243. package/dist/core/middleware/built-in/helmet/middleware.d.ts +22 -0
  244. package/dist/core/middleware/built-in/helmet/middleware.js +28 -0
  245. package/dist/core/middleware/built-in/helmet/middleware.js.map +1 -0
  246. package/dist/core/middleware/built-in/http2/core.d.ts +35 -0
  247. package/dist/core/middleware/built-in/http2/core.js +128 -0
  248. package/dist/core/middleware/built-in/http2/core.js.map +1 -0
  249. package/dist/core/middleware/built-in/http2/hook.d.ts +5 -0
  250. package/dist/core/middleware/built-in/http2/hook.js +34 -0
  251. package/dist/core/middleware/built-in/http2/hook.js.map +1 -0
  252. package/dist/core/middleware/built-in/http2/index.d.ts +8 -0
  253. package/dist/core/middleware/built-in/http2/index.js +10 -0
  254. package/dist/core/middleware/built-in/http2/index.js.map +1 -0
  255. package/dist/core/middleware/built-in/http2/middleware.d.ts +20 -0
  256. package/dist/core/middleware/built-in/http2/middleware.js +31 -0
  257. package/dist/core/middleware/built-in/http2/middleware.js.map +1 -0
  258. package/dist/core/middleware/built-in/index.d.ts +20 -1
  259. package/dist/core/middleware/built-in/index.js +31 -0
  260. package/dist/core/middleware/built-in/index.js.map +1 -1
  261. package/dist/core/middleware/built-in/range/core.d.ts +16 -0
  262. package/dist/core/middleware/built-in/range/core.js +112 -0
  263. package/dist/core/middleware/built-in/range/core.js.map +1 -0
  264. package/dist/core/middleware/built-in/range/hook.d.ts +2 -0
  265. package/dist/core/middleware/built-in/range/hook.js +12 -0
  266. package/dist/core/middleware/built-in/range/hook.js.map +1 -0
  267. package/dist/core/middleware/built-in/range/index.d.ts +6 -0
  268. package/dist/core/middleware/built-in/range/index.js +7 -0
  269. package/dist/core/middleware/built-in/range/index.js.map +1 -0
  270. package/dist/core/middleware/built-in/range/middleware.d.ts +21 -0
  271. package/dist/core/middleware/built-in/range/middleware.js +27 -0
  272. package/dist/core/middleware/built-in/range/middleware.js.map +1 -0
  273. package/dist/core/middleware/built-in/session/core.js +14 -1
  274. package/dist/core/middleware/built-in/session/core.js.map +1 -1
  275. package/dist/core/middleware/built-in/static/core.d.ts +20 -0
  276. package/dist/core/middleware/built-in/static/core.js +143 -0
  277. package/dist/core/middleware/built-in/static/core.js.map +1 -0
  278. package/dist/core/middleware/built-in/static/hook.d.ts +2 -0
  279. package/dist/core/middleware/built-in/static/hook.js +12 -0
  280. package/dist/core/middleware/built-in/static/hook.js.map +1 -0
  281. package/dist/core/middleware/built-in/static/index.d.ts +6 -0
  282. package/dist/core/middleware/built-in/static/index.js +7 -0
  283. package/dist/core/middleware/built-in/static/index.js.map +1 -0
  284. package/dist/core/middleware/built-in/static/middleware.d.ts +18 -0
  285. package/dist/core/middleware/built-in/static/middleware.js +26 -0
  286. package/dist/core/middleware/built-in/static/middleware.js.map +1 -0
  287. package/dist/core/middleware/built-in/template/core.d.ts +19 -0
  288. package/dist/core/middleware/built-in/template/core.js +108 -0
  289. package/dist/core/middleware/built-in/template/core.js.map +1 -0
  290. package/dist/core/middleware/built-in/template/hook.d.ts +2 -0
  291. package/dist/core/middleware/built-in/template/hook.js +12 -0
  292. package/dist/core/middleware/built-in/template/hook.js.map +1 -0
  293. package/dist/core/middleware/built-in/template/index.d.ts +6 -0
  294. package/dist/core/middleware/built-in/template/index.js +7 -0
  295. package/dist/core/middleware/built-in/template/index.js.map +1 -0
  296. package/dist/core/middleware/built-in/template/middleware.d.ts +21 -0
  297. package/dist/core/middleware/built-in/template/middleware.js +27 -0
  298. package/dist/core/middleware/built-in/template/middleware.js.map +1 -0
  299. package/dist/core/middleware/built-in/upload/core.d.ts +29 -0
  300. package/dist/core/middleware/built-in/upload/core.js +66 -0
  301. package/dist/core/middleware/built-in/upload/core.js.map +1 -0
  302. package/dist/core/middleware/built-in/upload/hook.d.ts +2 -0
  303. package/dist/core/middleware/built-in/upload/hook.js +25 -0
  304. package/dist/core/middleware/built-in/upload/hook.js.map +1 -0
  305. package/dist/core/middleware/built-in/upload/index.d.ts +6 -0
  306. package/dist/core/middleware/built-in/upload/index.js +7 -0
  307. package/dist/core/middleware/built-in/upload/index.js.map +1 -0
  308. package/dist/core/middleware/built-in/upload/middleware.d.ts +18 -0
  309. package/dist/core/middleware/built-in/upload/middleware.js +41 -0
  310. package/dist/core/middleware/built-in/upload/middleware.js.map +1 -0
  311. package/dist/core/middleware/built-in/validation/core.js +4 -2
  312. package/dist/core/middleware/built-in/validation/core.js.map +1 -1
  313. package/dist/core/middleware/built-in/validation/middleware.js +2 -1
  314. package/dist/core/middleware/built-in/validation/middleware.js.map +1 -1
  315. package/dist/core/middleware/index.js +1 -0
  316. package/dist/core/middleware/index.js.map +1 -1
  317. package/dist/core/modules/auto-discovery.js +5 -4
  318. package/dist/core/modules/auto-discovery.js.map +1 -1
  319. package/dist/core/modules/modules.js.map +1 -1
  320. package/dist/core/networking/adapters/socketio-adapter.js +1 -1
  321. package/dist/core/networking/adapters/socketio-adapter.js.map +1 -1
  322. package/dist/core/networking/adapters/uws-adapter.js +61 -8
  323. package/dist/core/networking/adapters/uws-adapter.js.map +1 -1
  324. package/dist/core/networking/adapters/ws-adapter.js +61 -19
  325. package/dist/core/networking/adapters/ws-adapter.js.map +1 -1
  326. package/dist/core/networking/websocket-manager.js +2 -0
  327. package/dist/core/networking/websocket-manager.js.map +1 -1
  328. package/dist/core/pooling/object-pool-manager.js +12 -1
  329. package/dist/core/pooling/object-pool-manager.js.map +1 -1
  330. package/dist/core/queue/adapters/bull-adapter.d.ts +86 -0
  331. package/dist/core/queue/adapters/bull-adapter.js +330 -0
  332. package/dist/core/queue/adapters/bull-adapter.js.map +1 -0
  333. package/dist/core/queue/adapters/index.d.ts +9 -0
  334. package/dist/core/queue/adapters/index.js +10 -0
  335. package/dist/core/queue/adapters/index.js.map +1 -0
  336. package/dist/core/queue/adapters/kafka-adapter.d.ts +86 -0
  337. package/dist/core/queue/adapters/kafka-adapter.js +462 -0
  338. package/dist/core/queue/adapters/kafka-adapter.js.map +1 -0
  339. package/dist/core/queue/adapters/memory-adapter.d.ts +87 -0
  340. package/dist/core/queue/adapters/memory-adapter.js +415 -0
  341. package/dist/core/queue/adapters/memory-adapter.js.map +1 -0
  342. package/dist/core/queue/adapters/rabbitmq-adapter.d.ts +86 -0
  343. package/dist/core/queue/adapters/rabbitmq-adapter.js +436 -0
  344. package/dist/core/queue/adapters/rabbitmq-adapter.js.map +1 -0
  345. package/dist/core/queue/adapters/sqs-adapter.d.ts +102 -0
  346. package/dist/core/queue/adapters/sqs-adapter.js +522 -0
  347. package/dist/core/queue/adapters/sqs-adapter.js.map +1 -0
  348. package/dist/core/queue/index.d.ts +11 -0
  349. package/dist/core/queue/index.js +14 -0
  350. package/dist/core/queue/index.js.map +1 -0
  351. package/dist/core/queue/middleware/index.d.ts +7 -0
  352. package/dist/core/queue/middleware/index.js +8 -0
  353. package/dist/core/queue/middleware/index.js.map +1 -0
  354. package/dist/core/queue/middleware/monitoring.d.ts +84 -0
  355. package/dist/core/queue/middleware/monitoring.js +145 -0
  356. package/dist/core/queue/middleware/monitoring.js.map +1 -0
  357. package/dist/core/queue/middleware/priority.d.ts +61 -0
  358. package/dist/core/queue/middleware/priority.js +90 -0
  359. package/dist/core/queue/middleware/priority.js.map +1 -0
  360. package/dist/core/queue/middleware/rate-limit.d.ts +34 -0
  361. package/dist/core/queue/middleware/rate-limit.js +109 -0
  362. package/dist/core/queue/middleware/rate-limit.js.map +1 -0
  363. package/dist/core/queue/queue-adapter.d.ts +73 -0
  364. package/dist/core/queue/queue-adapter.js +20 -0
  365. package/dist/core/queue/queue-adapter.js.map +1 -0
  366. package/dist/core/queue/queue-manager.d.ts +92 -0
  367. package/dist/core/queue/queue-manager.js +327 -0
  368. package/dist/core/queue/queue-manager.js.map +1 -0
  369. package/dist/core/queue/types.d.ts +205 -0
  370. package/dist/core/queue/types.js +6 -0
  371. package/dist/core/queue/types.js.map +1 -0
  372. package/dist/core/routing/app-integration.d.ts +3 -3
  373. package/dist/core/routing/app-integration.js +1 -1
  374. package/dist/core/routing/app-integration.js.map +1 -1
  375. package/dist/core/routing/index.d.ts +1 -1
  376. package/dist/core/routing/index.js +42 -11
  377. package/dist/core/routing/index.js.map +1 -1
  378. package/dist/core/routing/radix-tree.d.ts +48 -0
  379. package/dist/core/routing/radix-tree.js +211 -0
  380. package/dist/core/routing/radix-tree.js.map +1 -0
  381. package/dist/core/routing/router.d.ts +10 -9
  382. package/dist/core/routing/router.js +3 -1
  383. package/dist/core/routing/router.js.map +1 -1
  384. package/dist/core/routing/unified-router.d.ts +18 -12
  385. package/dist/core/routing/unified-router.js +220 -163
  386. package/dist/core/routing/unified-router.js.map +1 -1
  387. package/dist/core/runtime/aws-lambda-adapter.js +21 -10
  388. package/dist/core/runtime/aws-lambda-adapter.js.map +1 -1
  389. package/dist/core/runtime/base-adapter.js +18 -8
  390. package/dist/core/runtime/base-adapter.js.map +1 -1
  391. package/dist/core/runtime/cloudflare-workers-adapter.js +36 -13
  392. package/dist/core/runtime/cloudflare-workers-adapter.js.map +1 -1
  393. package/dist/core/runtime/node-adapter.d.ts +1 -1
  394. package/dist/core/runtime/node-adapter.js +7 -4
  395. package/dist/core/runtime/node-adapter.js.map +1 -1
  396. package/dist/core/runtime/vercel-edge-adapter.js +17 -6
  397. package/dist/core/runtime/vercel-edge-adapter.js.map +1 -1
  398. package/dist/core/utilities/circuit-breaker.d.ts +9 -2
  399. package/dist/core/utilities/circuit-breaker.js +32 -3
  400. package/dist/core/utilities/circuit-breaker.js.map +1 -1
  401. package/dist/core/utilities/container.js +9 -1
  402. package/dist/core/utilities/container.js.map +1 -1
  403. package/dist/core/utilities/hooks.js +4 -0
  404. package/dist/core/utilities/hooks.js.map +1 -1
  405. package/dist/core/validation/index.js +6 -1
  406. package/dist/core/validation/index.js.map +1 -1
  407. package/dist/core/workers/facade.d.ts +74 -0
  408. package/dist/core/workers/facade.js +98 -0
  409. package/dist/core/workers/facade.js.map +1 -0
  410. package/dist/core/workers/index.d.ts +2 -0
  411. package/dist/core/workers/index.js +6 -0
  412. package/dist/core/workers/index.js.map +1 -0
  413. package/dist/core/workers/worker-manager.d.ts +124 -0
  414. package/dist/core/workers/worker-manager.js +299 -0
  415. package/dist/core/workers/worker-manager.js.map +1 -0
  416. package/dist/core/workers/worker.d.ts +1 -0
  417. package/dist/core/workers/worker.js +225 -0
  418. package/dist/core/workers/worker.js.map +1 -0
  419. package/dist/index.d.ts +14 -1
  420. package/dist/index.js +11 -1
  421. package/dist/index.js.map +1 -1
  422. package/dist/moro.d.ts +486 -1
  423. package/dist/moro.js +1194 -28
  424. package/dist/moro.js.map +1 -1
  425. package/dist/types/cache.d.ts +4 -0
  426. package/dist/types/config.d.ts +70 -0
  427. package/dist/types/core.d.ts +19 -1
  428. package/dist/types/events.d.ts +1 -1
  429. package/dist/types/events.js +1 -0
  430. package/dist/types/events.js.map +1 -1
  431. package/dist/types/module.d.ts +2 -2
  432. package/package.json +110 -16
package/dist/moro.js CHANGED
@@ -2,7 +2,6 @@
2
2
  // Built for developers who demand performance, elegance, and zero compromises
3
3
  // Event-driven • Modular • Enterprise-ready • Developer-first
4
4
  import { Moro as MoroCore } from './core/framework.js';
5
- import { middleware } from './core/http/index.js';
6
5
  import { createFrameworkLogger, applyLoggingConfiguration } from './core/logger/index.js';
7
6
  import { MiddlewareManager } from './core/middleware/index.js';
8
7
  import { IntelligentRoutingManager } from './core/routing/app-integration.js';
@@ -17,6 +16,17 @@ import { normalizeValidationError } from './core/validation/schema-interface.js'
17
16
  import { initializeConfig } from './core/config/index.js';
18
17
  // Runtime System Integration
19
18
  import { createRuntimeAdapter } from './core/runtime/index.js';
19
+ // Job System Integration
20
+ import { JobScheduler, JobHealthChecker, everyInterval, cronSchedule, } from './core/jobs/index.js';
21
+ // Worker Threads Integration (optional - lazy loaded when needed)
22
+ import { WorkerThreadsFacade } from './core/workers/index.js';
23
+ // Built-in middleware integration
24
+ import { cors, helmet, compression, bodySize } from './core/middleware/built-in/index.js';
25
+ // Lazy imports for GraphQL to avoid crashes when not installed
26
+ let GraphQLCore;
27
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
28
+ let GraphQLSubscriptionManager;
29
+ let setupGraphQLSubscriptions;
20
30
  export class Moro extends EventEmitter {
21
31
  coreFramework;
22
32
  routes = [];
@@ -49,6 +59,31 @@ export class Moro extends EventEmitter {
49
59
  middlewareManager;
50
60
  // Queued WebSocket registrations (for async adapter detection)
51
61
  queuedWebSocketRegistrations = [];
62
+ // Job scheduling system
63
+ jobScheduler;
64
+ jobHealthChecker;
65
+ jobsStarted = false;
66
+ // GraphQL system
67
+ graphqlCore; // Use any to avoid import dependency
68
+ graphqlSubscriptionManager;
69
+ graphqlInitPromise;
70
+ graphqlConfig; // Store config for lazy initialization
71
+ // gRPC system (lazy loaded)
72
+ grpcManager; // Use any to avoid import dependency
73
+ grpcInitPromise;
74
+ grpcStarted = false;
75
+ grpcConfig; // Store config for lazy initialization
76
+ // Queue system (lazy loaded)
77
+ queueManager; // Use any to avoid import dependency
78
+ queueInitialized = false;
79
+ queueInitPromise; // Track initialization promise
80
+ queueConfigs = new Map(); // Store queue configs for lazy initialization
81
+ // Worker threads system (lazy loaded facade)
82
+ workerFacade;
83
+ // Mail system (lazy loaded)
84
+ mailManager; // Use any to avoid import dependency
85
+ mailInitialized = false;
86
+ mailConfig; // Store config for lazy initialization
52
87
  constructor(options = {}) {
53
88
  super(); // Call EventEmitter constructor
54
89
  // Track if user explicitly set logger/logging options
@@ -110,6 +145,35 @@ export class Moro extends EventEmitter {
110
145
  }
111
146
  // Access enterprise event bus from core framework
112
147
  this.eventBus = this.coreFramework.eventBus;
148
+ // Initialize job scheduler if enabled in config
149
+ // Default to enabled (true) unless explicitly disabled
150
+ const jobsEnabled = this.config.jobs?.enabled !== false && options.jobs?.enabled !== false;
151
+ if (jobsEnabled) {
152
+ const leaderElectionOptions = this.config.jobs?.leaderElection?.enabled !== false
153
+ ? {
154
+ strategy: this.config.jobs?.leaderElection?.strategy ?? 'file',
155
+ lockPath: this.config.jobs?.leaderElection?.lockPath,
156
+ lockTimeout: this.config.jobs?.leaderElection?.lockTimeout,
157
+ heartbeatInterval: this.config.jobs?.leaderElection?.heartbeatInterval,
158
+ }
159
+ : undefined;
160
+ const jobSchedulerOptions = {
161
+ maxConcurrentJobs: this.config.jobs?.maxConcurrentJobs,
162
+ enableLeaderElection: this.config.jobs?.leaderElection?.enabled !== false,
163
+ leaderElection: leaderElectionOptions,
164
+ executor: this.config.jobs?.executor,
165
+ stateManager: this.config.jobs?.stateManager,
166
+ gracefulShutdownTimeout: this.config.jobs?.gracefulShutdownTimeout,
167
+ };
168
+ this.jobScheduler = new JobScheduler(createFrameworkLogger('Jobs'), jobSchedulerOptions);
169
+ this.jobHealthChecker = new JobHealthChecker(this.jobScheduler, createFrameworkLogger('JobHealth'));
170
+ this.logger.info('Job scheduler initialized', 'Jobs', {
171
+ maxConcurrentJobs: jobSchedulerOptions.maxConcurrentJobs,
172
+ leaderElection: jobSchedulerOptions.enableLeaderElection,
173
+ });
174
+ }
175
+ // Initialize worker threads facade (optional - lazy loaded)
176
+ this.workerFacade = new WorkerThreadsFacade();
113
177
  // Setup default middleware if enabled - use config defaults with options override
114
178
  this.setupDefaultMiddleware({
115
179
  ...this.getDefaultOptionsFromConfig(),
@@ -412,18 +476,10 @@ export class Moro extends EventEmitter {
412
476
  throw new Error('Port not specified and not found in configuration. Please provide a port number or configure it in moro.config.js/ts');
413
477
  }
414
478
  // Check if clustering is enabled for massive performance gains
415
- // NOTE: uWebSockets.js does NOT support Node.js clustering - it's single-threaded only
416
- const usingUWebSockets = this.config.server?.useUWebSockets || false;
417
479
  if (this.config.performance?.clustering?.enabled) {
418
- if (usingUWebSockets) {
419
- this.logger.warn('Clustering is not supported with uWebSockets.js - running in single-threaded mode. ' +
420
- 'uWebSockets is so fast that single-threaded performance often exceeds multi-threaded Node.js!', 'Cluster');
421
- // Continue without clustering
422
- }
423
- else {
424
- this.startWithClustering(port, host, callback);
425
- return;
426
- }
480
+ this.logger.info('Clustering enabled - using Node.js cluster', 'Cluster');
481
+ this.startWithClustering(port, host, callback);
482
+ return;
427
483
  }
428
484
  this.eventBus.emit('server:starting', { port, runtime: this.runtimeType });
429
485
  // Add documentation middleware first (if enabled)
@@ -432,12 +488,12 @@ export class Moro extends EventEmitter {
432
488
  this.coreFramework.addMiddleware(docsMiddleware);
433
489
  this.logger.debug('Documentation middleware added', 'Documentation');
434
490
  }
435
- catch (error) {
491
+ catch {
436
492
  // Documentation not enabled, that's fine
437
493
  this.logger.debug('Documentation not enabled', 'Documentation');
438
494
  }
439
495
  // Add unified routing middleware (handles both chainable and direct routes)
440
- // Optimized: call router without extra async wrapper when possible
496
+ // Call router without extra async wrapper when possible
441
497
  this.coreFramework.addMiddleware(async (req, res, next) => {
442
498
  // Try unified router first (handles all route types)
443
499
  const handled = this.unifiedRouter.handleRequest(req, res);
@@ -478,6 +534,20 @@ export class Moro extends EventEmitter {
478
534
  this.unifiedRouter.logPerformanceStats();
479
535
  }
480
536
  this.eventBus.emit('server:started', { port, runtime: this.runtimeType });
537
+ // Start job scheduler after server starts
538
+ this.startJobScheduler().catch(err => {
539
+ this.logger.error(`Failed to start job scheduler: ${String(err)}`);
540
+ });
541
+ // Initialize GraphQL if configured
542
+ this.ensureGraphQLInitialized().catch(error => {
543
+ this.logger.error(`Failed to initialize GraphQL: ${error}`, 'GraphQL');
544
+ });
545
+ // Start gRPC server if initialized
546
+ if (this.grpcManager && !this.grpcStarted) {
547
+ this.startGrpc().catch(error => {
548
+ this.logger.error(`Failed to start gRPC server: ${error}`, 'GRPC');
549
+ });
550
+ }
481
551
  if (callback)
482
552
  callback();
483
553
  };
@@ -604,7 +674,7 @@ export class Moro extends EventEmitter {
604
674
  if (res.headersSent)
605
675
  return;
606
676
  }
607
- catch (error) {
677
+ catch {
608
678
  // Documentation not enabled, that's fine
609
679
  }
610
680
  // Try unified router first (handles all routes)
@@ -622,6 +692,7 @@ export class Moro extends EventEmitter {
622
692
  // Handle direct routes for runtime adapters
623
693
  async handleDirectRoutes(req, res) {
624
694
  // Find matching route
695
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
625
696
  const route = this.findMatchingRoute(req.method, req.path);
626
697
  if (!route) {
627
698
  res.status(404).json({ success: false, error: 'Not found' });
@@ -697,7 +768,7 @@ export class Moro extends EventEmitter {
697
768
  staticRouteMap = new Map();
698
769
  dynamicRoutesBySegments = new Map();
699
770
  findMatchingRoute(method, path) {
700
- // Phase 1: O(1) static route lookup
771
+ // O(1) static route lookup
701
772
  const staticKey = `${method}:${path}`;
702
773
  const staticRoute = this.staticRouteMap.get(staticKey);
703
774
  if (staticRoute) {
@@ -707,7 +778,7 @@ export class Moro extends EventEmitter {
707
778
  paramNames: [],
708
779
  };
709
780
  }
710
- // Phase 2: Optimized dynamic route matching by segment count
781
+ // Dynamic route matching by segment count
711
782
  const segmentCount = PathMatcher.countSegments(path);
712
783
  const candidateRoutes = this.dynamicRoutesBySegments.get(segmentCount) || [];
713
784
  for (const route of candidateRoutes) {
@@ -790,6 +861,7 @@ export class Moro extends EventEmitter {
790
861
  if (!this.dynamicRoutesBySegments.has(segmentCount)) {
791
862
  this.dynamicRoutesBySegments.set(segmentCount, []);
792
863
  }
864
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
793
865
  this.dynamicRoutesBySegments.get(segmentCount).push(route);
794
866
  }
795
867
  }
@@ -889,11 +961,11 @@ export class Moro extends EventEmitter {
889
961
  : this.config.security.cors
890
962
  ? this.config.security.cors
891
963
  : {};
892
- this.use(middleware.cors(corsOptions));
964
+ this.use(cors(corsOptions));
893
965
  }
894
966
  // Helmet - check config enabled property OR options.security.helmet.enabled === true
895
967
  if (this.config.security.helmet.enabled || options.security?.helmet?.enabled === true) {
896
- this.use(middleware.helmet());
968
+ this.use(helmet());
897
969
  }
898
970
  // Compression - check config enabled property OR options.performance.compression.enabled === true
899
971
  if (this.config.performance.compression.enabled ||
@@ -903,10 +975,10 @@ export class Moro extends EventEmitter {
903
975
  : this.config.performance.compression
904
976
  ? this.config.performance.compression
905
977
  : {};
906
- this.use(middleware.compression(compressionOptions));
978
+ this.use(compression(compressionOptions));
907
979
  }
908
980
  // Body size limiting
909
- this.use(middleware.bodySize({ limit: '10mb' }));
981
+ this.use(bodySize({ limit: '10mb' }));
910
982
  }
911
983
  // Enhanced auto-discovery initialization
912
984
  async initializeAutoDiscovery(options) {
@@ -1146,6 +1218,7 @@ export class Moro extends EventEmitter {
1146
1218
  const gracefulShutdown = () => {
1147
1219
  this.logger.info('Gracefully shutting down cluster...', 'Cluster');
1148
1220
  // Clean up all workers
1221
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1149
1222
  for (const [pid, worker] of this.clusterWorkers) {
1150
1223
  worker.removeAllListeners();
1151
1224
  worker.kill('SIGTERM');
@@ -1160,6 +1233,7 @@ export class Moro extends EventEmitter {
1160
1233
  // Fork workers with basic tracking
1161
1234
  for (let i = 0; i < workerCount; i++) {
1162
1235
  const worker = cluster.fork();
1236
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1163
1237
  this.clusterWorkers.set(worker.process.pid, worker);
1164
1238
  this.logger.info(`Worker ${worker.process.pid} started`, 'Cluster');
1165
1239
  // Handle individual worker messages
@@ -1173,6 +1247,7 @@ export class Moro extends EventEmitter {
1173
1247
  this.logger.warn(`Worker ${pid} died unexpectedly (${signal || code}). Restarting...`, 'Cluster');
1174
1248
  // Simple restart
1175
1249
  const newWorker = cluster.fork();
1250
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1176
1251
  this.clusterWorkers.set(newWorker.process.pid, newWorker);
1177
1252
  this.logger.info(`Worker ${newWorker.process.pid} restarted`, 'Cluster');
1178
1253
  }
@@ -1254,11 +1329,11 @@ export class Moro extends EventEmitter {
1254
1329
  const docsMiddleware = this.documentation.getDocsMiddleware();
1255
1330
  this.coreFramework.addMiddleware(docsMiddleware);
1256
1331
  }
1257
- catch (error) {
1332
+ catch {
1258
1333
  // Documentation not enabled, that's fine
1259
1334
  }
1260
1335
  // Add unified routing middleware (handles both chainable and direct routes)
1261
- // Optimized: call router without extra async wrapper when possible
1336
+ // Call router without extra async wrapper when possible
1262
1337
  this.coreFramework.addMiddleware(async (req, res, next) => {
1263
1338
  // Try unified router first (handles all route types)
1264
1339
  const handled = this.unifiedRouter.handleRequest(req, res);
@@ -1335,12 +1410,51 @@ export class Moro extends EventEmitter {
1335
1410
  */
1336
1411
  async close() {
1337
1412
  this.logger.debug('Closing Moro application...');
1413
+ // Shutdown worker threads first (fastest)
1414
+ try {
1415
+ this.logger.info('Shutting down worker threads...');
1416
+ await this.workerFacade.shutdown();
1417
+ }
1418
+ catch {
1419
+ // Workers might not be initialized or available
1420
+ this.logger.debug('Worker threads not available for shutdown');
1421
+ }
1422
+ // Shutdown job scheduler
1423
+ if (this.jobScheduler) {
1424
+ try {
1425
+ this.logger.info('Shutting down job scheduler...');
1426
+ await this.jobScheduler.shutdown();
1427
+ this.jobsStarted = false;
1428
+ }
1429
+ catch (err) {
1430
+ this.logger.error(`Error shutting down job scheduler: ${String(err)}`);
1431
+ }
1432
+ }
1433
+ // Shutdown gRPC server
1434
+ if (this.grpcManager && this.grpcStarted) {
1435
+ try {
1436
+ this.logger.info('Shutting down gRPC server...');
1437
+ await this.stopGrpc();
1438
+ }
1439
+ catch (err) {
1440
+ this.logger.error(`Error shutting down gRPC server: ${String(err)}`);
1441
+ }
1442
+ }
1443
+ // Cleanup GraphQL adapter resources
1444
+ if (this.graphqlCore) {
1445
+ try {
1446
+ await this.graphqlCore.cleanup();
1447
+ }
1448
+ catch (err) {
1449
+ this.logger.error(`Error cleaning up GraphQL: ${String(err)}`);
1450
+ }
1451
+ }
1338
1452
  // Flush logger buffer before shutdown
1339
1453
  try {
1340
1454
  // Use flushBuffer for immediate synchronous flush
1341
1455
  this.logger.flushBuffer();
1342
1456
  }
1343
- catch (error) {
1457
+ catch {
1344
1458
  // Ignore flush errors during shutdown
1345
1459
  }
1346
1460
  // Close the core framework with timeout
@@ -1352,10 +1466,13 @@ export class Moro extends EventEmitter {
1352
1466
  resolve();
1353
1467
  });
1354
1468
  }),
1355
- new Promise(resolve => setTimeout(resolve, 2000)), // 2 second timeout
1469
+ new Promise(resolve => {
1470
+ const timer = setTimeout(resolve, 2000); // 2 second timeout
1471
+ timer.unref(); // Don't keep process alive
1472
+ }),
1356
1473
  ]);
1357
1474
  }
1358
- catch (error) {
1475
+ catch {
1359
1476
  // Force close if graceful close fails
1360
1477
  this.logger.warn('Force closing HTTP server due to timeout');
1361
1478
  }
@@ -1365,20 +1482,1069 @@ export class Moro extends EventEmitter {
1365
1482
  try {
1366
1483
  this.moduleDiscovery.cleanup();
1367
1484
  }
1368
- catch (error) {
1485
+ catch {
1369
1486
  // Ignore cleanup errors
1370
1487
  }
1371
1488
  }
1489
+ // Shutdown queue manager
1490
+ if (this.queueManager) {
1491
+ try {
1492
+ await this.queueManager.shutdown();
1493
+ this.logger.debug('Queue system shutdown complete');
1494
+ }
1495
+ catch (error) {
1496
+ this.logger.warn(`Error shutting down queue system: ${error}`);
1497
+ }
1498
+ }
1499
+ // Clear queue state on close
1500
+ this.queueConfigs.clear();
1501
+ this.queueInitialized = false;
1502
+ this.queueInitPromise = undefined;
1503
+ this.queueManager = undefined;
1504
+ // Shutdown mail system
1505
+ if (this.mailManager) {
1506
+ try {
1507
+ await this.mailManager.close();
1508
+ this.logger.debug('Mail system shutdown complete');
1509
+ }
1510
+ catch (error) {
1511
+ this.logger.warn(`Error shutting down mail system: ${error}`);
1512
+ }
1513
+ }
1372
1514
  // Clean up event listeners
1373
1515
  try {
1374
1516
  this.eventBus.removeAllListeners();
1375
1517
  this.removeAllListeners();
1376
1518
  }
1377
- catch (error) {
1519
+ catch {
1378
1520
  // Ignore cleanup errors
1379
1521
  }
1380
1522
  this.logger.debug('Moro application closed successfully');
1381
1523
  }
1524
+ // ========================================
1525
+ // Job Scheduling API
1526
+ // ========================================
1527
+ /**
1528
+ * Register a background job with cron or interval schedule
1529
+ * @param name - Job name (used for identification)
1530
+ * @param schedule - Cron expression, interval string ('5m', '1h'), or schedule object
1531
+ * @param handler - Job function to execute
1532
+ * @param options - Job configuration options
1533
+ * @returns Job ID for management
1534
+ *
1535
+ * @example
1536
+ * // Cron schedule
1537
+ * app.job('cleanup', '0 2 * * *', async () => {
1538
+ * await cleanupOldData();
1539
+ * });
1540
+ *
1541
+ * // Interval schedule
1542
+ * app.job('health-check', '5m', async (ctx) => {
1543
+ * console.log('Health check', ctx.executionId);
1544
+ * });
1545
+ *
1546
+ * // Advanced options
1547
+ * app.job('report', '@daily', generateReport, {
1548
+ * timeout: 60000,
1549
+ * maxRetries: 3,
1550
+ * onError: (ctx, error) => console.error('Job failed', error)
1551
+ * });
1552
+ */
1553
+ job(name, schedule, handler, options = {}) {
1554
+ if (!this.jobScheduler) {
1555
+ throw new Error('Job scheduler is not enabled. Set config.jobs.enabled = true');
1556
+ }
1557
+ let jobSchedule;
1558
+ // Parse schedule input
1559
+ if (typeof schedule === 'string') {
1560
+ // Check if it's a cron expression or interval
1561
+ if (schedule.match(/^(\d+[smhd]|\d+\s*(seconds?|minutes?|hours?|days?))$/i)) {
1562
+ // Interval format
1563
+ jobSchedule = everyInterval(schedule);
1564
+ }
1565
+ else {
1566
+ // Cron format
1567
+ jobSchedule = cronSchedule(schedule, options.timezone);
1568
+ }
1569
+ }
1570
+ else {
1571
+ jobSchedule = schedule;
1572
+ }
1573
+ const jobOptions = {
1574
+ name: options.name || name,
1575
+ enabled: options.enabled,
1576
+ priority: options.priority,
1577
+ timezone: options.timezone,
1578
+ maxConcurrent: options.maxConcurrent,
1579
+ timeout: options.timeout,
1580
+ maxRetries: options.maxRetries,
1581
+ retryDelay: options.retryDelay,
1582
+ retryBackoff: options.retryBackoff,
1583
+ enableCircuitBreaker: options.enableCircuitBreaker,
1584
+ metadata: options.metadata,
1585
+ onStart: options.onStart,
1586
+ onComplete: options.onComplete,
1587
+ onError: options.onError,
1588
+ };
1589
+ const jobId = this.jobScheduler.registerJob(name, jobSchedule, handler, jobOptions);
1590
+ this.logger.info(`Job registered: ${name} (${jobId})`);
1591
+ return jobId;
1592
+ }
1593
+ /**
1594
+ * Enable or disable a registered job
1595
+ */
1596
+ setJobEnabled(jobId, enabled) {
1597
+ if (!this.jobScheduler) {
1598
+ return false;
1599
+ }
1600
+ return this.jobScheduler.setJobEnabled(jobId, enabled);
1601
+ }
1602
+ /**
1603
+ * Manually trigger a job execution
1604
+ */
1605
+ async triggerJob(jobId, metadata) {
1606
+ if (!this.jobScheduler) {
1607
+ throw new Error('Job scheduler is not enabled');
1608
+ }
1609
+ return this.jobScheduler.triggerJob(jobId, metadata);
1610
+ }
1611
+ /**
1612
+ * Unregister a job
1613
+ */
1614
+ unregisterJob(jobId) {
1615
+ if (!this.jobScheduler) {
1616
+ throw new Error('Job scheduler is not enabled');
1617
+ }
1618
+ return this.jobScheduler.unregisterJob(jobId);
1619
+ }
1620
+ /**
1621
+ * Get job metrics
1622
+ */
1623
+ getJobMetrics(jobId) {
1624
+ if (!this.jobScheduler) {
1625
+ return null;
1626
+ }
1627
+ return this.jobScheduler.getJobMetrics(jobId);
1628
+ }
1629
+ /**
1630
+ * Get job health status
1631
+ */
1632
+ getJobHealth(jobId) {
1633
+ if (!this.jobHealthChecker) {
1634
+ if (jobId) {
1635
+ return {
1636
+ jobId,
1637
+ name: 'Unknown',
1638
+ status: 'unknown',
1639
+ enabled: false,
1640
+ consecutiveFailures: 0,
1641
+ message: 'Job scheduler not enabled',
1642
+ };
1643
+ }
1644
+ return [];
1645
+ }
1646
+ if (jobId) {
1647
+ return this.jobHealthChecker.checkJobHealth(jobId);
1648
+ }
1649
+ return this.jobHealthChecker.checkAllJobs();
1650
+ }
1651
+ /**
1652
+ * Get scheduler statistics
1653
+ */
1654
+ getJobStats() {
1655
+ if (!this.jobScheduler) {
1656
+ return null;
1657
+ }
1658
+ return this.jobScheduler.getStats();
1659
+ }
1660
+ /**
1661
+ * Get overall scheduler health
1662
+ */
1663
+ getSchedulerHealth() {
1664
+ if (!this.jobHealthChecker) {
1665
+ return {
1666
+ status: 'unknown',
1667
+ message: 'Job scheduler not enabled',
1668
+ stats: null,
1669
+ jobs: [],
1670
+ unhealthyJobCount: 0,
1671
+ };
1672
+ }
1673
+ return this.jobHealthChecker.getSchedulerHealth();
1674
+ }
1675
+ /**
1676
+ * Start the job scheduler (called automatically on listen)
1677
+ */
1678
+ async startJobScheduler() {
1679
+ if (!this.jobScheduler || this.jobsStarted) {
1680
+ return;
1681
+ }
1682
+ try {
1683
+ await this.jobScheduler.start();
1684
+ this.jobsStarted = true;
1685
+ this.logger.info('Job scheduler started');
1686
+ }
1687
+ catch (err) {
1688
+ this.logger.error(`Failed to start job scheduler: ${String(err)}`);
1689
+ }
1690
+ }
1691
+ // ========================================
1692
+ // GraphQL API
1693
+ // ========================================
1694
+ /**
1695
+ * Configure GraphQL endpoint (synchronous, lazy initialization)
1696
+ *
1697
+ * @param options - GraphQL configuration options
1698
+ *
1699
+ * @example
1700
+ * ```ts
1701
+ * // Using type definitions and resolvers
1702
+ * app.graphqlInit({
1703
+ * typeDefs: `
1704
+ * type Query {
1705
+ * hello: String
1706
+ * users: [User]
1707
+ * }
1708
+ * type User {
1709
+ * id: ID!
1710
+ * name: String!
1711
+ * }
1712
+ * `,
1713
+ * resolvers: {
1714
+ * Query: {
1715
+ * hello: () => 'Hello World!',
1716
+ * users: () => [{ id: '1', name: 'Alice' }]
1717
+ * }
1718
+ * }
1719
+ * });
1720
+ *
1721
+ * // Using Pothos schema builder
1722
+ * import SchemaBuilder from '@pothos/core';
1723
+ *
1724
+ * const builder = new SchemaBuilder();
1725
+ * builder.queryType({
1726
+ * fields: (t) => ({
1727
+ * hello: t.string({ resolve: () => 'Hello World!' })
1728
+ * })
1729
+ * });
1730
+ *
1731
+ * app.graphqlInit({
1732
+ * pothosSchema: builder
1733
+ * });
1734
+ * ```
1735
+ */
1736
+ graphqlInit(options) {
1737
+ if (this.graphqlCore || this.graphqlInitPromise) {
1738
+ throw new Error('GraphQL has already been configured. Call graphqlInit() only once.');
1739
+ }
1740
+ // Check if graphql package is available
1741
+ if (!this.isGraphQLAvailable()) {
1742
+ throw new Error('GraphQL support requires the graphql package to be installed.\n' +
1743
+ 'Install it with: npm install graphql\n' +
1744
+ 'For TypeScript-first GraphQL, also consider: npm install @pothos/core\n' +
1745
+ 'For performance boost: npm install graphql-jit');
1746
+ }
1747
+ this.logger.info('Configuring GraphQL (will initialize on server start)', 'GraphQL', {
1748
+ path: options.path || '/graphql',
1749
+ jit: options.enableJIT !== false,
1750
+ playground: options.enablePlayground !== false,
1751
+ });
1752
+ // Store config and trigger initialization immediately
1753
+ this.graphqlConfig = options;
1754
+ this.graphqlInitPromise = this.initializeGraphQL(options);
1755
+ this.eventBus.emit('graphql:configured', { options });
1756
+ return this;
1757
+ }
1758
+ /**
1759
+ * Lazy initialize GraphQL system
1760
+ */
1761
+ async ensureGraphQLInitialized() {
1762
+ if (this.graphqlCore || this.graphqlInitPromise) {
1763
+ await this.graphqlInitPromise;
1764
+ return;
1765
+ }
1766
+ if (!this.graphqlConfig) {
1767
+ return; // GraphQL not configured, skip
1768
+ }
1769
+ this.graphqlInitPromise = this.initializeGraphQL(this.graphqlConfig);
1770
+ await this.graphqlInitPromise;
1771
+ }
1772
+ /**
1773
+ * Initialize GraphQL system asynchronously
1774
+ */
1775
+ async initializeGraphQL(options) {
1776
+ try {
1777
+ // Lazy load GraphQL modules
1778
+ await this.loadGraphQLModules();
1779
+ // Create GraphQL core
1780
+ this.graphqlCore = new GraphQLCore(options);
1781
+ // Initialize GraphQL
1782
+ await this.graphqlCore.initialize();
1783
+ this.logger.info('GraphQL initialized successfully', 'GraphQL');
1784
+ // Setup subscriptions if enabled
1785
+ if (options.enableSubscriptions !== false && this.config.websocket.enabled) {
1786
+ this.setupGraphQLSubscriptions(options);
1787
+ }
1788
+ }
1789
+ catch (error) {
1790
+ this.logger.error('Failed to initialize GraphQL', 'GraphQL', { error });
1791
+ throw error;
1792
+ }
1793
+ }
1794
+ /**
1795
+ * Check if GraphQL package is available
1796
+ */
1797
+ isGraphQLAvailable() {
1798
+ try {
1799
+ require.resolve('graphql');
1800
+ return true;
1801
+ }
1802
+ catch {
1803
+ return false;
1804
+ }
1805
+ }
1806
+ /**
1807
+ * Lazy load GraphQL modules
1808
+ */
1809
+ async loadGraphQLModules() {
1810
+ if (GraphQLCore) {
1811
+ return; // Already loaded
1812
+ }
1813
+ try {
1814
+ // GraphQL core now uses adapters with no static imports from 'graphql'
1815
+ const coreModule = await import('./core/graphql/core.js');
1816
+ GraphQLCore = coreModule.GraphQLCore;
1817
+ const subsModule = await import('./core/middleware/built-in/graphql/subscriptions.js');
1818
+ GraphQLSubscriptionManager = subsModule.GraphQLSubscriptionManager;
1819
+ setupGraphQLSubscriptions = subsModule.setupGraphQLSubscriptions;
1820
+ }
1821
+ catch (error) {
1822
+ this.logger.error('Failed to load GraphQL modules', 'GraphQL', { error });
1823
+ throw new Error('Failed to load GraphQL modules. Please ensure graphql is installed.');
1824
+ }
1825
+ }
1826
+ /**
1827
+ * Setup GraphQL subscriptions
1828
+ */
1829
+ setupGraphQLSubscriptions(options) {
1830
+ const websocketAdapter = this.coreFramework.getWebSocketAdapter();
1831
+ if (!websocketAdapter) {
1832
+ this.logger.warn('GraphQL subscriptions require WebSocket to be enabled', 'GraphQL');
1833
+ return;
1834
+ }
1835
+ if (!this.graphqlCore) {
1836
+ return;
1837
+ }
1838
+ const schema = this.graphqlCore.getSchema();
1839
+ this.graphqlSubscriptionManager = setupGraphQLSubscriptions(websocketAdapter, schema, {
1840
+ path: options.path ? `${options.path}/subscriptions` : '/graphql/subscriptions',
1841
+ contextFactory: options.context,
1842
+ });
1843
+ this.logger.info('GraphQL subscriptions enabled', 'GraphQL', {
1844
+ path: options.path ? `${options.path}/subscriptions` : '/graphql/subscriptions',
1845
+ });
1846
+ }
1847
+ /**
1848
+ * Get GraphQL schema (if configured)
1849
+ */
1850
+ async getGraphQLSchema() {
1851
+ await this.ensureGraphQLInitialized();
1852
+ return this.graphqlCore?.getSchema();
1853
+ }
1854
+ // ========================================
1855
+ // Worker Threads API
1856
+ // ========================================
1857
+ /**
1858
+ * Execute a task on worker threads (CPU-intensive operations)
1859
+ * @param task - Task to execute
1860
+ * @returns Promise resolving to task result
1861
+ *
1862
+ * @example
1863
+ * ```ts
1864
+ * // JWT verification (CPU-intensive)
1865
+ * const payload = await app.executeOnWorker({
1866
+ * id: 'jwt-verify-123',
1867
+ * type: 'jwt:verify',
1868
+ * data: { token, secret }
1869
+ * });
1870
+ *
1871
+ * // Heavy computation
1872
+ * const result = await app.executeOnWorker({
1873
+ * id: 'compute-456',
1874
+ * type: 'computation:heavy',
1875
+ * data: { iterations: 1000000 }
1876
+ * });
1877
+ * ```
1878
+ */
1879
+ async executeOnWorker(task) {
1880
+ return this.workerFacade.executeTask(task);
1881
+ }
1882
+ /**
1883
+ * Get worker manager instance for advanced usage
1884
+ */
1885
+ async getWorkerManager() {
1886
+ await this.workerFacade.ensureInitialized?.(); // Trigger initialization if needed
1887
+ return this.workerFacade;
1888
+ }
1889
+ /**
1890
+ * Get worker thread statistics
1891
+ */
1892
+ async getWorkerStats() {
1893
+ return this.workerFacade.getStats();
1894
+ }
1895
+ /**
1896
+ * JWT operations using worker threads (prevents event loop blocking)
1897
+ */
1898
+ async getJwtWorker() {
1899
+ return this.workerFacade.getJwtWorker();
1900
+ }
1901
+ /**
1902
+ * Crypto operations using worker threads
1903
+ */
1904
+ async getCryptoWorker() {
1905
+ return this.workerFacade.getCryptoWorker();
1906
+ }
1907
+ /**
1908
+ * Heavy computation operations using worker threads
1909
+ */
1910
+ async getComputeWorker() {
1911
+ return this.workerFacade.getComputeWorker();
1912
+ }
1913
+ /**
1914
+ * Get GraphQL stats
1915
+ */
1916
+ async getGraphQLStats() {
1917
+ await this.ensureGraphQLInitialized();
1918
+ if (!this.graphqlCore) {
1919
+ return null;
1920
+ }
1921
+ return {
1922
+ ...this.graphqlCore.getStats(),
1923
+ subscriptions: this.graphqlSubscriptionManager?.getSubscriptionCount() || 0,
1924
+ };
1925
+ }
1926
+ // =====================
1927
+ // gRPC Methods
1928
+ // =====================
1929
+ /**
1930
+ * Configure gRPC server (synchronous, lazy initialization)
1931
+ *
1932
+ * @example
1933
+ * ```typescript
1934
+ * app.grpcInit({
1935
+ * port: 50051,
1936
+ * host: '0.0.0.0',
1937
+ * adapter: 'grpc-js',
1938
+ * enableHealthCheck: true,
1939
+ * enableReflection: true
1940
+ * });
1941
+ * ```
1942
+ */
1943
+ grpcInit(options = {}) {
1944
+ if (this.grpcInitPromise) {
1945
+ this.logger.warn('gRPC already configured', 'GRPC');
1946
+ return this;
1947
+ }
1948
+ this.logger.info('Configuring gRPC (will initialize on server start)', 'GRPC');
1949
+ // Store config for lazy initialization
1950
+ this.grpcConfig = {
1951
+ port: 50051,
1952
+ host: '0.0.0.0',
1953
+ adapter: 'grpc-js',
1954
+ enableHealthCheck: true,
1955
+ enableReflection: false,
1956
+ ...options,
1957
+ };
1958
+ return this;
1959
+ }
1960
+ /**
1961
+ * Lazy initialize gRPC system
1962
+ */
1963
+ async ensureGrpcInitialized() {
1964
+ if (this.grpcManager || this.grpcInitPromise) {
1965
+ await this.grpcInitPromise;
1966
+ return;
1967
+ }
1968
+ if (!this.grpcConfig) {
1969
+ return; // gRPC not configured, skip
1970
+ }
1971
+ this.grpcInitPromise = (async () => {
1972
+ try {
1973
+ this.logger.info('Initializing gRPC system', 'GRPC');
1974
+ // Lazy load gRPC manager
1975
+ const { GrpcManager } = await import('./core/grpc/grpc-manager.js');
1976
+ // Create gRPC manager
1977
+ this.grpcManager = new GrpcManager(this.grpcConfig);
1978
+ // Initialize gRPC
1979
+ await this.grpcManager.initialize();
1980
+ this.logger.info('gRPC system initialized', 'GRPC');
1981
+ }
1982
+ catch (error) {
1983
+ this.logger.error(`Failed to initialize gRPC: ${error}`, 'GRPC');
1984
+ throw error;
1985
+ }
1986
+ })();
1987
+ await this.grpcInitPromise;
1988
+ }
1989
+ /**
1990
+ * Register a gRPC service from a proto file
1991
+ *
1992
+ * @example
1993
+ * ```typescript
1994
+ * app.grpcService('./proto/users.proto', 'UserService', {
1995
+ * getUser: async (call, callback) => {
1996
+ * const user = await db.users.findById(call.request.id);
1997
+ * callback(null, user);
1998
+ * },
1999
+ * listUsers: async (call) => {
2000
+ * for (const user of users) {
2001
+ * call.write(user);
2002
+ * }
2003
+ * call.end();
2004
+ * }
2005
+ * });
2006
+ * ```
2007
+ */
2008
+ async grpcService(protoPath, serviceName, implementation, packageName) {
2009
+ if (!this.grpcConfig && !this.grpcManager) {
2010
+ throw new Error('gRPC not initialized. Call app.grpcInit() first.\n' +
2011
+ 'Example: app.grpcInit({ port: 50051 });');
2012
+ }
2013
+ // Lazy initialize gRPC if not already done
2014
+ await this.ensureGrpcInitialized();
2015
+ if (!this.grpcManager) {
2016
+ throw new Error('gRPC not initialized. Call app.grpcInit() first.\n' +
2017
+ 'Example: app.grpcInit({ port: 50051 });');
2018
+ }
2019
+ try {
2020
+ await this.grpcManager.registerService(protoPath, serviceName, implementation, packageName);
2021
+ this.logger.info(`gRPC service registered: ${serviceName}`, 'GRPC');
2022
+ }
2023
+ catch (error) {
2024
+ this.logger.error(`Failed to register gRPC service ${serviceName}: ${error}`, 'GRPC');
2025
+ throw error;
2026
+ }
2027
+ }
2028
+ /**
2029
+ * Start gRPC server
2030
+ * Called automatically by listen() if gRPC is configured
2031
+ */
2032
+ async startGrpc() {
2033
+ // Lazy initialize if needed
2034
+ await this.ensureGrpcInitialized();
2035
+ if (!this.grpcManager) {
2036
+ return;
2037
+ }
2038
+ if (this.grpcStarted) {
2039
+ this.logger.warn('gRPC server already started', 'GRPC');
2040
+ return;
2041
+ }
2042
+ try {
2043
+ await this.grpcManager.start();
2044
+ this.grpcStarted = true;
2045
+ const stats = this.grpcManager.getStats();
2046
+ if (stats) {
2047
+ this.logger.info('gRPC server started successfully', 'GRPC');
2048
+ }
2049
+ }
2050
+ catch (error) {
2051
+ this.logger.error(`Failed to start gRPC server: ${error}`, 'GRPC');
2052
+ throw error;
2053
+ }
2054
+ }
2055
+ /**
2056
+ * Stop gRPC server gracefully
2057
+ */
2058
+ async stopGrpc() {
2059
+ if (!this.grpcManager || !this.grpcStarted) {
2060
+ return;
2061
+ }
2062
+ try {
2063
+ await this.grpcManager.stop();
2064
+ this.grpcStarted = false;
2065
+ this.logger.info('gRPC server stopped', 'GRPC');
2066
+ }
2067
+ catch (error) {
2068
+ this.logger.error(`Error stopping gRPC server: ${error}`, 'GRPC');
2069
+ throw error;
2070
+ }
2071
+ }
2072
+ /**
2073
+ * Create a gRPC client for calling remote services
2074
+ *
2075
+ * @example
2076
+ * ```typescript
2077
+ * const client = await app.createGrpcClient(
2078
+ * './proto/users.proto',
2079
+ * 'UserService',
2080
+ * 'localhost:50051'
2081
+ * );
2082
+ *
2083
+ * const user = await client.getUser({ id: '123' });
2084
+ * ```
2085
+ */
2086
+ async createGrpcClient(protoPath, serviceName, address, options) {
2087
+ if (!this.grpcConfig && !this.grpcManager) {
2088
+ throw new Error('gRPC not initialized. Call app.grpcInit() first.\n' +
2089
+ 'Example: app.grpcInit({ port: 50051 });');
2090
+ }
2091
+ // Lazy initialize gRPC if not already done
2092
+ await this.ensureGrpcInitialized();
2093
+ if (!this.grpcManager) {
2094
+ throw new Error('gRPC not initialized. Call app.grpcInit() first.\n' +
2095
+ 'Example: app.grpcInit({ port: 50051 });');
2096
+ }
2097
+ try {
2098
+ const client = await this.grpcManager.createClient(protoPath, serviceName, address, options);
2099
+ this.logger.info(`gRPC client created for ${serviceName} at ${address}`, 'GRPC');
2100
+ return client;
2101
+ }
2102
+ catch (error) {
2103
+ this.logger.error(`Failed to create gRPC client: ${error}`, 'GRPC');
2104
+ throw error;
2105
+ }
2106
+ }
2107
+ /**
2108
+ * Get gRPC statistics
2109
+ */
2110
+ getGrpcStats() {
2111
+ if (!this.grpcManager) {
2112
+ return null;
2113
+ }
2114
+ return this.grpcManager.getStats();
2115
+ }
2116
+ /**
2117
+ * Get list of registered gRPC services
2118
+ */
2119
+ getGrpcServices() {
2120
+ if (!this.grpcManager) {
2121
+ return [];
2122
+ }
2123
+ return this.grpcManager.getServices();
2124
+ }
2125
+ /**
2126
+ * Initialize queue system (synchronous for first queue, subsequent queues added immediately)
2127
+ *
2128
+ * @example
2129
+ * ```typescript
2130
+ * app.queueInit('emails', {
2131
+ * adapter: 'bull',
2132
+ * connection: {
2133
+ * host: 'localhost',
2134
+ * port: 6379
2135
+ * },
2136
+ * concurrency: 5
2137
+ * });
2138
+ * ```
2139
+ */
2140
+ queueInit(name, options) {
2141
+ // Initialize queue manager on first call
2142
+ if (!this.queueInitialized && !this.queueInitPromise) {
2143
+ this.queueInitPromise = (async () => {
2144
+ try {
2145
+ this.logger.info('Initializing queue system', 'QUEUE');
2146
+ const { QueueManager } = await import('./core/queue/index.js');
2147
+ this.queueManager = new QueueManager(this.eventBus);
2148
+ this.queueInitialized = true;
2149
+ this.logger.info('Queue system initialized', 'QUEUE');
2150
+ }
2151
+ catch (error) {
2152
+ this.logger.error(`Failed to initialize queue system: ${error}`, 'QUEUE');
2153
+ throw error;
2154
+ }
2155
+ })();
2156
+ }
2157
+ // Store config to register after initialization
2158
+ this.queueConfigs.set(name, options);
2159
+ this.logger.debug(`Queue "${name}" configured`, 'QUEUE');
2160
+ // Register queue async (manager will be ready)
2161
+ if (this.queueInitPromise) {
2162
+ this.queueInitPromise
2163
+ .then(async () => {
2164
+ if (this.queueManager) {
2165
+ await this.queueManager.registerQueue(name, options);
2166
+ this.logger.info(`Queue "${name}" registered with ${options.adapter} adapter`, 'QUEUE');
2167
+ }
2168
+ })
2169
+ .catch(error => {
2170
+ this.logger.error(`Failed to register queue "${name}": ${error}`, 'QUEUE');
2171
+ });
2172
+ }
2173
+ return this;
2174
+ }
2175
+ /**
2176
+ * Ensure queue system is initialized
2177
+ */
2178
+ async ensureQueueInitialized() {
2179
+ if (this.queueInitPromise) {
2180
+ await this.queueInitPromise;
2181
+ }
2182
+ }
2183
+ /**
2184
+ * @deprecated Use queueInit() instead
2185
+ */
2186
+ async queue(name, options) {
2187
+ if (!this.queueInitialized) {
2188
+ try {
2189
+ this.logger.info('Initializing queue system', 'QUEUE');
2190
+ const { QueueManager } = await import('./core/queue/index.js');
2191
+ this.queueManager = new QueueManager(this.eventBus);
2192
+ this.queueInitialized = true;
2193
+ this.logger.info('Queue system initialized', 'QUEUE');
2194
+ }
2195
+ catch (error) {
2196
+ this.logger.error(`Failed to initialize queue system: ${error}`, 'QUEUE');
2197
+ throw error;
2198
+ }
2199
+ }
2200
+ try {
2201
+ await this.queueManager.registerQueue(name, options);
2202
+ this.logger.info(`Queue "${name}" registered with ${options.adapter} adapter`, 'QUEUE');
2203
+ }
2204
+ catch (error) {
2205
+ this.logger.error(`Failed to register queue "${name}": ${error}`, 'QUEUE');
2206
+ throw error;
2207
+ }
2208
+ }
2209
+ /**
2210
+ * Add a job to a queue
2211
+ *
2212
+ * @example
2213
+ * ```typescript
2214
+ * await app.addToQueue('emails', {
2215
+ * to: 'user@example.com',
2216
+ * subject: 'Welcome'
2217
+ * }, {
2218
+ * priority: 10,
2219
+ * delay: 5000
2220
+ * });
2221
+ * ```
2222
+ */
2223
+ async addToQueue(queueName, data, options) {
2224
+ // Ensure queue system is initialized
2225
+ await this.ensureQueueInitialized();
2226
+ if (!this.queueManager) {
2227
+ throw new Error(`Queue "${queueName}" not initialized. Call app.queueInit('${queueName}', options) first.`);
2228
+ }
2229
+ return await this.queueManager.addToQueue(queueName, data, options);
2230
+ }
2231
+ /**
2232
+ * Add multiple jobs to a queue in bulk
2233
+ *
2234
+ * @example
2235
+ * ```typescript
2236
+ * await app.addBulkToQueue('emails', [
2237
+ * { data: { to: 'user1@example.com' }, options: { priority: 1 } },
2238
+ * { data: { to: 'user2@example.com' }, options: { priority: 2 } }
2239
+ * ]);
2240
+ * ```
2241
+ */
2242
+ async addBulkToQueue(queueName, jobs) {
2243
+ // Ensure queue system is initialized
2244
+ await this.ensureQueueInitialized();
2245
+ if (!this.queueManager) {
2246
+ throw new Error(`Queue "${queueName}" not initialized. Call app.queue('${queueName}', options) first.`);
2247
+ }
2248
+ return await this.queueManager.addBulkToQueue(queueName, jobs);
2249
+ }
2250
+ /**
2251
+ * Register a processor for a queue
2252
+ *
2253
+ * @example
2254
+ * ```typescript
2255
+ * // Simple processor
2256
+ * app.processQueue('emails', async (job) => {
2257
+ * await sendEmail(job.data);
2258
+ * });
2259
+ *
2260
+ * // With concurrency
2261
+ * app.processQueue('images', 3, async (job) => {
2262
+ * await processImage(job.data);
2263
+ * });
2264
+ * ```
2265
+ */
2266
+ async processQueue(queueName, concurrencyOrHandler, handler) {
2267
+ // Ensure queue system is initialized
2268
+ await this.ensureQueueInitialized();
2269
+ if (!this.queueManager) {
2270
+ throw new Error(`Queue "${queueName}" not initialized. Call app.queueInit('${queueName}', options) first.`);
2271
+ }
2272
+ return await this.queueManager.processQueue(queueName, concurrencyOrHandler, handler);
2273
+ }
2274
+ /**
2275
+ * Get queue status
2276
+ */
2277
+ async getQueueStatus(queueName) {
2278
+ if (!this.queueManager) {
2279
+ throw new Error(`Queue system not initialized.`);
2280
+ }
2281
+ return await this.queueManager.getQueueStatus(queueName);
2282
+ }
2283
+ /**
2284
+ * Get a specific job from a queue
2285
+ */
2286
+ async getJob(queueName, jobId) {
2287
+ if (!this.queueManager) {
2288
+ throw new Error(`Queue system not initialized.`);
2289
+ }
2290
+ return await this.queueManager.getJob(queueName, jobId);
2291
+ }
2292
+ /**
2293
+ * Get jobs from a queue by status
2294
+ */
2295
+ async getJobs(queueName, status, start = 0, end = -1) {
2296
+ if (!this.queueManager) {
2297
+ throw new Error(`Queue system not initialized.`);
2298
+ }
2299
+ return await this.queueManager.getJobs(queueName, status, start, end);
2300
+ }
2301
+ /**
2302
+ * Remove a job from a queue
2303
+ */
2304
+ async removeJob(queueName, jobId) {
2305
+ if (!this.queueManager) {
2306
+ throw new Error(`Queue system not initialized.`);
2307
+ }
2308
+ return await this.queueManager.removeJob(queueName, jobId);
2309
+ }
2310
+ /**
2311
+ * Retry a failed job
2312
+ */
2313
+ async retryJob(queueName, jobId) {
2314
+ if (!this.queueManager) {
2315
+ throw new Error(`Queue system not initialized.`);
2316
+ }
2317
+ return await this.queueManager.retryJob(queueName, jobId);
2318
+ }
2319
+ /**
2320
+ * Pause a queue
2321
+ */
2322
+ async pauseQueue(queueName) {
2323
+ if (!this.queueManager) {
2324
+ throw new Error(`Queue system not initialized.`);
2325
+ }
2326
+ return await this.queueManager.pauseQueue(queueName);
2327
+ }
2328
+ /**
2329
+ * Resume a paused queue
2330
+ */
2331
+ async resumeQueue(queueName) {
2332
+ if (!this.queueManager) {
2333
+ throw new Error(`Queue system not initialized.`);
2334
+ }
2335
+ return await this.queueManager.resumeQueue(queueName);
2336
+ }
2337
+ /**
2338
+ * Clean old jobs from a queue
2339
+ */
2340
+ async cleanQueue(queueName, gracePeriod, status) {
2341
+ if (!this.queueManager) {
2342
+ throw new Error(`Queue system not initialized.`);
2343
+ }
2344
+ return await this.queueManager.cleanQueue(queueName, gracePeriod, status);
2345
+ }
2346
+ /**
2347
+ * Get all registered queue names
2348
+ */
2349
+ getQueueNames() {
2350
+ // Return configured queues (includes both initialized and pending)
2351
+ const configuredQueues = Array.from(this.queueConfigs.keys());
2352
+ if (!this.queueManager) {
2353
+ return configuredQueues;
2354
+ }
2355
+ // Merge with manager's queues (in case some were added directly)
2356
+ const managerQueues = this.queueManager.getQueueNames();
2357
+ const allQueues = new Set([...configuredQueues, ...managerQueues]);
2358
+ return Array.from(allQueues);
2359
+ }
2360
+ /**
2361
+ * Check if a queue is registered
2362
+ */
2363
+ hasQueue(queueName) {
2364
+ // Check if it's configured (includes both initialized and pending)
2365
+ if (this.queueConfigs.has(queueName)) {
2366
+ return true;
2367
+ }
2368
+ if (!this.queueManager) {
2369
+ return false;
2370
+ }
2371
+ return this.queueManager.hasQueue(queueName);
2372
+ }
2373
+ // =====================
2374
+ // Mail System Methods
2375
+ // =====================
2376
+ /**
2377
+ * Configure mail system (synchronous, lazy initialization)
2378
+ *
2379
+ * @example
2380
+ * ```typescript
2381
+ * // Using Nodemailer (SMTP) - chainable, no await needed!
2382
+ * app.mailInit({
2383
+ * adapter: 'nodemailer',
2384
+ * from: { name: 'My App', email: 'noreply@myapp.com' },
2385
+ * connection: {
2386
+ * host: 'smtp.gmail.com',
2387
+ * port: 587,
2388
+ * secure: false,
2389
+ * auth: { user: process.env.EMAIL_USER, pass: process.env.EMAIL_PASSWORD }
2390
+ * },
2391
+ * templates: { path: './emails', engine: 'moro', cache: true }
2392
+ * });
2393
+ *
2394
+ * // Using SendGrid
2395
+ * app.mailInit({
2396
+ * adapter: 'sendgrid',
2397
+ * from: 'noreply@myapp.com',
2398
+ * connection: { apiKey: process.env.SENDGRID_API_KEY }
2399
+ * });
2400
+ * ```
2401
+ */
2402
+ mailInit(config) {
2403
+ if (this.mailInitialized) {
2404
+ this.logger.warn('Mail system already configured', 'Mail');
2405
+ return this;
2406
+ }
2407
+ // Store config for lazy initialization
2408
+ this.mailConfig = config;
2409
+ this.logger.debug('Mail system configured (will initialize on first use)', 'Mail');
2410
+ this.eventBus.emit('mail:configured', { config });
2411
+ return this;
2412
+ }
2413
+ /**
2414
+ * Lazy initialize mail system on first use
2415
+ */
2416
+ async ensureMailInitialized() {
2417
+ if (this.mailInitialized) {
2418
+ return;
2419
+ }
2420
+ if (!this.mailConfig) {
2421
+ throw new Error('Mail system not configured. Call app.mailInit(config) first.\n' +
2422
+ "Example: app.mailInit({ adapter: 'console', from: 'noreply@myapp.com' });");
2423
+ }
2424
+ try {
2425
+ this.logger.info('Initializing mail system', 'Mail');
2426
+ const { MailManager } = await import('./core/mail/index.js');
2427
+ this.mailManager = new MailManager(this.mailConfig);
2428
+ await this.mailManager.initialize();
2429
+ if (this.mailConfig.queue?.enabled && this.queueManager) {
2430
+ this.mailManager.setQueueManager(this.queueManager);
2431
+ const queueName = this.mailConfig.queue.name || 'emails';
2432
+ if (!this.queueManager.hasQueue(queueName)) {
2433
+ this.queueConfigs.set(queueName, {
2434
+ adapter: 'memory',
2435
+ concurrency: this.mailConfig.queue.attempts || 3,
2436
+ });
2437
+ await this.ensureQueueInitialized();
2438
+ await this.processQueue(queueName, async (job) => {
2439
+ if (this.mailManager) {
2440
+ return await this.mailManager.send(job.data);
2441
+ }
2442
+ throw new Error('Mail manager not initialized');
2443
+ });
2444
+ }
2445
+ this.logger.info(`Mail queue "${queueName}" configured`, 'Mail');
2446
+ }
2447
+ this.mailInitialized = true;
2448
+ this.logger.info('Mail system initialized successfully', 'Mail');
2449
+ }
2450
+ catch (error) {
2451
+ this.logger.error(`Failed to initialize mail system: ${error}`, 'Mail');
2452
+ throw error;
2453
+ }
2454
+ }
2455
+ /**
2456
+ * Send an email
2457
+ *
2458
+ * @example
2459
+ * ```typescript
2460
+ * // Simple email
2461
+ * await app.sendMail({
2462
+ * to: 'user@example.com',
2463
+ * subject: 'Welcome',
2464
+ * text: 'Welcome to our app!'
2465
+ * });
2466
+ *
2467
+ * // With template
2468
+ * await app.sendMail({
2469
+ * to: 'user@example.com',
2470
+ * subject: 'Password Reset',
2471
+ * template: 'password-reset',
2472
+ * data: { name: 'John', resetUrl: 'https://myapp.com/reset/token123' }
2473
+ * });
2474
+ *
2475
+ * // With attachments
2476
+ * await app.sendMail({
2477
+ * to: 'user@example.com',
2478
+ * subject: 'Invoice',
2479
+ * template: 'invoice',
2480
+ * data: { invoice },
2481
+ * attachments: [{ filename: 'invoice.pdf', content: pdfBuffer }]
2482
+ * });
2483
+ * ```
2484
+ */
2485
+ async sendMail(options) {
2486
+ // Lazy initialize on first use
2487
+ await this.ensureMailInitialized();
2488
+ this.eventBus.emit('mail:sending', { options });
2489
+ try {
2490
+ const result = await this.mailManager.send(options);
2491
+ if (result.success) {
2492
+ this.eventBus.emit('mail:sent', { result, options });
2493
+ }
2494
+ else {
2495
+ this.eventBus.emit('mail:failed', { error: new Error(result.error), options });
2496
+ }
2497
+ return result;
2498
+ }
2499
+ catch (error) {
2500
+ this.eventBus.emit('mail:failed', { error, options });
2501
+ throw error;
2502
+ }
2503
+ }
2504
+ /**
2505
+ * Send multiple emails in bulk
2506
+ *
2507
+ * @example
2508
+ * ```typescript
2509
+ * await app.sendBulkMail([
2510
+ * { to: 'user1@example.com', subject: 'Hello', text: 'Hi!' },
2511
+ * { to: 'user2@example.com', subject: 'Hello', text: 'Hi!' }
2512
+ * ]);
2513
+ * ```
2514
+ */
2515
+ async sendBulkMail(options) {
2516
+ // Lazy initialize on first use
2517
+ await this.ensureMailInitialized();
2518
+ return await this.mailManager.sendBulk(options);
2519
+ }
2520
+ /**
2521
+ * Verify mail adapter connection
2522
+ */
2523
+ async verifyMail() {
2524
+ // Lazy initialize on first use
2525
+ try {
2526
+ await this.ensureMailInitialized();
2527
+ return await this.mailManager.verify();
2528
+ }
2529
+ catch {
2530
+ return false;
2531
+ }
2532
+ }
2533
+ /**
2534
+ * Get mail template engine for advanced usage
2535
+ */
2536
+ getMailTemplateEngine() {
2537
+ if (!this.mailManager) {
2538
+ return undefined;
2539
+ }
2540
+ return this.mailManager.getTemplateEngine();
2541
+ }
2542
+ /**
2543
+ * Check if mail system is configured
2544
+ */
2545
+ hasMailSystem() {
2546
+ return !!this.mailConfig || this.mailInitialized;
2547
+ }
1382
2548
  }
1383
2549
  // Export convenience function
1384
2550
  export function createApp(options) {