@morojs/moro 1.6.8 → 1.7.1

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 (307) hide show
  1. package/README.md +3 -1
  2. package/dist/core/auth/morojs-adapter.js +16 -6
  3. package/dist/core/auth/morojs-adapter.js.map +1 -1
  4. package/dist/core/config/config-sources.js +27 -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/docs/openapi-generator.js +8 -9
  9. package/dist/core/docs/openapi-generator.js.map +1 -1
  10. package/dist/core/events/event-bus.js +1 -1
  11. package/dist/core/events/event-bus.js.map +1 -1
  12. package/dist/core/framework.d.ts +4 -2
  13. package/dist/core/framework.js +25 -24
  14. package/dist/core/framework.js.map +1 -1
  15. package/dist/core/graphql/core.js +34 -8
  16. package/dist/core/graphql/core.js.map +1 -1
  17. package/dist/core/grpc/adapters/grpc-js-adapter.d.ts +28 -0
  18. package/dist/core/grpc/adapters/grpc-js-adapter.js +449 -0
  19. package/dist/core/grpc/adapters/grpc-js-adapter.js.map +1 -0
  20. package/dist/core/grpc/adapters/index.d.ts +1 -0
  21. package/dist/core/grpc/adapters/index.js +6 -0
  22. package/dist/core/grpc/adapters/index.js.map +1 -0
  23. package/dist/core/grpc/grpc-adapter.d.ts +47 -0
  24. package/dist/core/grpc/grpc-adapter.js +4 -0
  25. package/dist/core/grpc/grpc-adapter.js.map +1 -0
  26. package/dist/core/grpc/grpc-manager.d.ts +59 -0
  27. package/dist/core/grpc/grpc-manager.js +218 -0
  28. package/dist/core/grpc/grpc-manager.js.map +1 -0
  29. package/dist/core/grpc/index.d.ts +7 -0
  30. package/dist/core/grpc/index.js +10 -0
  31. package/dist/core/grpc/index.js.map +1 -0
  32. package/dist/core/grpc/middleware/auth.d.ts +22 -0
  33. package/dist/core/grpc/middleware/auth.js +126 -0
  34. package/dist/core/grpc/middleware/auth.js.map +1 -0
  35. package/dist/core/grpc/middleware/logging.d.ts +19 -0
  36. package/dist/core/grpc/middleware/logging.js +57 -0
  37. package/dist/core/grpc/middleware/logging.js.map +1 -0
  38. package/dist/core/grpc/middleware/validation.d.ts +18 -0
  39. package/dist/core/grpc/middleware/validation.js +126 -0
  40. package/dist/core/grpc/middleware/validation.js.map +1 -0
  41. package/dist/core/grpc/types.d.ts +233 -0
  42. package/dist/core/grpc/types.js +36 -0
  43. package/dist/core/grpc/types.js.map +1 -0
  44. package/dist/core/http/http-server.d.ts +13 -84
  45. package/dist/core/http/http-server.js +338 -792
  46. package/dist/core/http/http-server.js.map +1 -1
  47. package/dist/core/http/http2-server.d.ts +131 -0
  48. package/dist/core/http/http2-server.js +936 -0
  49. package/dist/core/http/http2-server.js.map +1 -0
  50. package/dist/core/http/index.d.ts +3 -1
  51. package/dist/core/http/index.js +2 -1
  52. package/dist/core/http/index.js.map +1 -1
  53. package/dist/core/http/uws-http-server.js +154 -26
  54. package/dist/core/http/uws-http-server.js.map +1 -1
  55. package/dist/core/jobs/job-executor.js +6 -1
  56. package/dist/core/jobs/job-executor.js.map +1 -1
  57. package/dist/core/jobs/job-scheduler.js +4 -1
  58. package/dist/core/jobs/job-scheduler.js.map +1 -1
  59. package/dist/core/jobs/leader-election.js +2 -1
  60. package/dist/core/jobs/leader-election.js.map +1 -1
  61. package/dist/core/logger/logger.js +41 -18
  62. package/dist/core/logger/logger.js.map +1 -1
  63. package/dist/core/logger/outputs.js +9 -3
  64. package/dist/core/logger/outputs.js.map +1 -1
  65. package/dist/core/mail/adapters/console-adapter.d.ts +14 -0
  66. package/dist/core/mail/adapters/console-adapter.js +89 -0
  67. package/dist/core/mail/adapters/console-adapter.js.map +1 -0
  68. package/dist/core/mail/adapters/index.d.ts +5 -0
  69. package/dist/core/mail/adapters/index.js +8 -0
  70. package/dist/core/mail/adapters/index.js.map +1 -0
  71. package/dist/core/mail/adapters/nodemailer-adapter.d.ts +18 -0
  72. package/dist/core/mail/adapters/nodemailer-adapter.js +188 -0
  73. package/dist/core/mail/adapters/nodemailer-adapter.js.map +1 -0
  74. package/dist/core/mail/adapters/resend-adapter.d.ts +18 -0
  75. package/dist/core/mail/adapters/resend-adapter.js +169 -0
  76. package/dist/core/mail/adapters/resend-adapter.js.map +1 -0
  77. package/dist/core/mail/adapters/sendgrid-adapter.d.ts +19 -0
  78. package/dist/core/mail/adapters/sendgrid-adapter.js +186 -0
  79. package/dist/core/mail/adapters/sendgrid-adapter.js.map +1 -0
  80. package/dist/core/mail/adapters/ses-adapter.d.ts +18 -0
  81. package/dist/core/mail/adapters/ses-adapter.js +167 -0
  82. package/dist/core/mail/adapters/ses-adapter.js.map +1 -0
  83. package/dist/core/mail/index.d.ts +5 -0
  84. package/dist/core/mail/index.js +8 -0
  85. package/dist/core/mail/index.js.map +1 -0
  86. package/dist/core/mail/mail-adapter.d.ts +62 -0
  87. package/dist/core/mail/mail-adapter.js +83 -0
  88. package/dist/core/mail/mail-adapter.js.map +1 -0
  89. package/dist/core/mail/mail-manager.d.ts +63 -0
  90. package/dist/core/mail/mail-manager.js +302 -0
  91. package/dist/core/mail/mail-manager.js.map +1 -0
  92. package/dist/core/mail/template-engine.d.ts +43 -0
  93. package/dist/core/mail/template-engine.js +239 -0
  94. package/dist/core/mail/template-engine.js.map +1 -0
  95. package/dist/core/mail/types.d.ts +237 -0
  96. package/dist/core/mail/types.js +4 -0
  97. package/dist/core/mail/types.js.map +1 -0
  98. package/dist/core/middleware/built-in/body-size/core.d.ts +12 -0
  99. package/dist/core/middleware/built-in/body-size/core.js +52 -0
  100. package/dist/core/middleware/built-in/body-size/core.js.map +1 -0
  101. package/dist/core/middleware/built-in/body-size/hook.d.ts +2 -0
  102. package/dist/core/middleware/built-in/body-size/hook.js +12 -0
  103. package/dist/core/middleware/built-in/body-size/hook.js.map +1 -0
  104. package/dist/core/middleware/built-in/body-size/index.d.ts +6 -0
  105. package/dist/core/middleware/built-in/body-size/index.js +7 -0
  106. package/dist/core/middleware/built-in/body-size/index.js.map +1 -0
  107. package/dist/core/middleware/built-in/body-size/middleware.d.ts +14 -0
  108. package/dist/core/middleware/built-in/body-size/middleware.js +22 -0
  109. package/dist/core/middleware/built-in/body-size/middleware.js.map +1 -0
  110. package/dist/core/middleware/built-in/cache/core.d.ts +20 -1
  111. package/dist/core/middleware/built-in/cache/core.js.map +1 -1
  112. package/dist/core/middleware/built-in/cache/hook.d.ts +38 -1
  113. package/dist/core/middleware/built-in/cache/hook.js +202 -16
  114. package/dist/core/middleware/built-in/cache/hook.js.map +1 -1
  115. package/dist/core/middleware/built-in/cache/index.js +1 -1
  116. package/dist/core/middleware/built-in/cache/index.js.map +1 -1
  117. package/dist/core/middleware/built-in/compression/core.d.ts +16 -0
  118. package/dist/core/middleware/built-in/compression/core.js +75 -0
  119. package/dist/core/middleware/built-in/compression/core.js.map +1 -0
  120. package/dist/core/middleware/built-in/compression/hook.d.ts +2 -0
  121. package/dist/core/middleware/built-in/compression/hook.js +14 -0
  122. package/dist/core/middleware/built-in/compression/hook.js.map +1 -0
  123. package/dist/core/middleware/built-in/compression/index.d.ts +6 -0
  124. package/dist/core/middleware/built-in/compression/index.js +7 -0
  125. package/dist/core/middleware/built-in/compression/index.js.map +1 -0
  126. package/dist/core/middleware/built-in/compression/middleware.d.ts +20 -0
  127. package/dist/core/middleware/built-in/compression/middleware.js +28 -0
  128. package/dist/core/middleware/built-in/compression/middleware.js.map +1 -0
  129. package/dist/core/middleware/built-in/cookie/core.js +37 -9
  130. package/dist/core/middleware/built-in/cookie/core.js.map +1 -1
  131. package/dist/core/middleware/built-in/helmet/core.d.ts +19 -0
  132. package/dist/core/middleware/built-in/helmet/core.js +70 -0
  133. package/dist/core/middleware/built-in/helmet/core.js.map +1 -0
  134. package/dist/core/middleware/built-in/helmet/hook.d.ts +2 -0
  135. package/dist/core/middleware/built-in/helmet/hook.js +12 -0
  136. package/dist/core/middleware/built-in/helmet/hook.js.map +1 -0
  137. package/dist/core/middleware/built-in/helmet/index.d.ts +6 -0
  138. package/dist/core/middleware/built-in/helmet/index.js +7 -0
  139. package/dist/core/middleware/built-in/helmet/index.js.map +1 -0
  140. package/dist/core/middleware/built-in/helmet/middleware.d.ts +22 -0
  141. package/dist/core/middleware/built-in/helmet/middleware.js +28 -0
  142. package/dist/core/middleware/built-in/helmet/middleware.js.map +1 -0
  143. package/dist/core/middleware/built-in/http2/core.d.ts +35 -0
  144. package/dist/core/middleware/built-in/http2/core.js +128 -0
  145. package/dist/core/middleware/built-in/http2/core.js.map +1 -0
  146. package/dist/core/middleware/built-in/http2/hook.d.ts +5 -0
  147. package/dist/core/middleware/built-in/http2/hook.js +34 -0
  148. package/dist/core/middleware/built-in/http2/hook.js.map +1 -0
  149. package/dist/core/middleware/built-in/http2/index.d.ts +8 -0
  150. package/dist/core/middleware/built-in/http2/index.js +10 -0
  151. package/dist/core/middleware/built-in/http2/index.js.map +1 -0
  152. package/dist/core/middleware/built-in/http2/middleware.d.ts +20 -0
  153. package/dist/core/middleware/built-in/http2/middleware.js +31 -0
  154. package/dist/core/middleware/built-in/http2/middleware.js.map +1 -0
  155. package/dist/core/middleware/built-in/index.d.ts +18 -0
  156. package/dist/core/middleware/built-in/index.js +28 -0
  157. package/dist/core/middleware/built-in/index.js.map +1 -1
  158. package/dist/core/middleware/built-in/range/core.d.ts +16 -0
  159. package/dist/core/middleware/built-in/range/core.js +112 -0
  160. package/dist/core/middleware/built-in/range/core.js.map +1 -0
  161. package/dist/core/middleware/built-in/range/hook.d.ts +2 -0
  162. package/dist/core/middleware/built-in/range/hook.js +12 -0
  163. package/dist/core/middleware/built-in/range/hook.js.map +1 -0
  164. package/dist/core/middleware/built-in/range/index.d.ts +6 -0
  165. package/dist/core/middleware/built-in/range/index.js +7 -0
  166. package/dist/core/middleware/built-in/range/index.js.map +1 -0
  167. package/dist/core/middleware/built-in/range/middleware.d.ts +21 -0
  168. package/dist/core/middleware/built-in/range/middleware.js +27 -0
  169. package/dist/core/middleware/built-in/range/middleware.js.map +1 -0
  170. package/dist/core/middleware/built-in/session/core.js +14 -1
  171. package/dist/core/middleware/built-in/session/core.js.map +1 -1
  172. package/dist/core/middleware/built-in/static/core.d.ts +20 -0
  173. package/dist/core/middleware/built-in/static/core.js +143 -0
  174. package/dist/core/middleware/built-in/static/core.js.map +1 -0
  175. package/dist/core/middleware/built-in/static/hook.d.ts +2 -0
  176. package/dist/core/middleware/built-in/static/hook.js +12 -0
  177. package/dist/core/middleware/built-in/static/hook.js.map +1 -0
  178. package/dist/core/middleware/built-in/static/index.d.ts +6 -0
  179. package/dist/core/middleware/built-in/static/index.js +7 -0
  180. package/dist/core/middleware/built-in/static/index.js.map +1 -0
  181. package/dist/core/middleware/built-in/static/middleware.d.ts +18 -0
  182. package/dist/core/middleware/built-in/static/middleware.js +26 -0
  183. package/dist/core/middleware/built-in/static/middleware.js.map +1 -0
  184. package/dist/core/middleware/built-in/template/core.d.ts +19 -0
  185. package/dist/core/middleware/built-in/template/core.js +108 -0
  186. package/dist/core/middleware/built-in/template/core.js.map +1 -0
  187. package/dist/core/middleware/built-in/template/hook.d.ts +2 -0
  188. package/dist/core/middleware/built-in/template/hook.js +12 -0
  189. package/dist/core/middleware/built-in/template/hook.js.map +1 -0
  190. package/dist/core/middleware/built-in/template/index.d.ts +6 -0
  191. package/dist/core/middleware/built-in/template/index.js +7 -0
  192. package/dist/core/middleware/built-in/template/index.js.map +1 -0
  193. package/dist/core/middleware/built-in/template/middleware.d.ts +21 -0
  194. package/dist/core/middleware/built-in/template/middleware.js +27 -0
  195. package/dist/core/middleware/built-in/template/middleware.js.map +1 -0
  196. package/dist/core/middleware/built-in/upload/core.d.ts +29 -0
  197. package/dist/core/middleware/built-in/upload/core.js +66 -0
  198. package/dist/core/middleware/built-in/upload/core.js.map +1 -0
  199. package/dist/core/middleware/built-in/upload/hook.d.ts +2 -0
  200. package/dist/core/middleware/built-in/upload/hook.js +25 -0
  201. package/dist/core/middleware/built-in/upload/hook.js.map +1 -0
  202. package/dist/core/middleware/built-in/upload/index.d.ts +6 -0
  203. package/dist/core/middleware/built-in/upload/index.js +7 -0
  204. package/dist/core/middleware/built-in/upload/index.js.map +1 -0
  205. package/dist/core/middleware/built-in/upload/middleware.d.ts +18 -0
  206. package/dist/core/middleware/built-in/upload/middleware.js +41 -0
  207. package/dist/core/middleware/built-in/upload/middleware.js.map +1 -0
  208. package/dist/core/middleware/built-in/validation/middleware.js +2 -1
  209. package/dist/core/middleware/built-in/validation/middleware.js.map +1 -1
  210. package/dist/core/networking/adapters/uws-adapter.js +54 -6
  211. package/dist/core/networking/adapters/uws-adapter.js.map +1 -1
  212. package/dist/core/networking/adapters/ws-adapter.js +56 -17
  213. package/dist/core/networking/adapters/ws-adapter.js.map +1 -1
  214. package/dist/core/pooling/object-pool-manager.js +9 -1
  215. package/dist/core/pooling/object-pool-manager.js.map +1 -1
  216. package/dist/core/queue/adapters/bull-adapter.d.ts +86 -0
  217. package/dist/core/queue/adapters/bull-adapter.js +330 -0
  218. package/dist/core/queue/adapters/bull-adapter.js.map +1 -0
  219. package/dist/core/queue/adapters/index.d.ts +9 -0
  220. package/dist/core/queue/adapters/index.js +10 -0
  221. package/dist/core/queue/adapters/index.js.map +1 -0
  222. package/dist/core/queue/adapters/kafka-adapter.d.ts +86 -0
  223. package/dist/core/queue/adapters/kafka-adapter.js +462 -0
  224. package/dist/core/queue/adapters/kafka-adapter.js.map +1 -0
  225. package/dist/core/queue/adapters/memory-adapter.d.ts +87 -0
  226. package/dist/core/queue/adapters/memory-adapter.js +419 -0
  227. package/dist/core/queue/adapters/memory-adapter.js.map +1 -0
  228. package/dist/core/queue/adapters/rabbitmq-adapter.d.ts +86 -0
  229. package/dist/core/queue/adapters/rabbitmq-adapter.js +436 -0
  230. package/dist/core/queue/adapters/rabbitmq-adapter.js.map +1 -0
  231. package/dist/core/queue/adapters/sqs-adapter.d.ts +102 -0
  232. package/dist/core/queue/adapters/sqs-adapter.js +522 -0
  233. package/dist/core/queue/adapters/sqs-adapter.js.map +1 -0
  234. package/dist/core/queue/index.d.ts +11 -0
  235. package/dist/core/queue/index.js +14 -0
  236. package/dist/core/queue/index.js.map +1 -0
  237. package/dist/core/queue/middleware/index.d.ts +7 -0
  238. package/dist/core/queue/middleware/index.js +8 -0
  239. package/dist/core/queue/middleware/index.js.map +1 -0
  240. package/dist/core/queue/middleware/monitoring.d.ts +84 -0
  241. package/dist/core/queue/middleware/monitoring.js +145 -0
  242. package/dist/core/queue/middleware/monitoring.js.map +1 -0
  243. package/dist/core/queue/middleware/priority.d.ts +61 -0
  244. package/dist/core/queue/middleware/priority.js +90 -0
  245. package/dist/core/queue/middleware/priority.js.map +1 -0
  246. package/dist/core/queue/middleware/rate-limit.d.ts +34 -0
  247. package/dist/core/queue/middleware/rate-limit.js +109 -0
  248. package/dist/core/queue/middleware/rate-limit.js.map +1 -0
  249. package/dist/core/queue/queue-adapter.d.ts +73 -0
  250. package/dist/core/queue/queue-adapter.js +20 -0
  251. package/dist/core/queue/queue-adapter.js.map +1 -0
  252. package/dist/core/queue/queue-manager.d.ts +92 -0
  253. package/dist/core/queue/queue-manager.js +327 -0
  254. package/dist/core/queue/queue-manager.js.map +1 -0
  255. package/dist/core/queue/types.d.ts +205 -0
  256. package/dist/core/queue/types.js +6 -0
  257. package/dist/core/queue/types.js.map +1 -0
  258. package/dist/core/routing/index.js +41 -10
  259. package/dist/core/routing/index.js.map +1 -1
  260. package/dist/core/routing/radix-tree.d.ts +48 -0
  261. package/dist/core/routing/radix-tree.js +211 -0
  262. package/dist/core/routing/radix-tree.js.map +1 -0
  263. package/dist/core/routing/router.d.ts +10 -9
  264. package/dist/core/routing/router.js +3 -1
  265. package/dist/core/routing/router.js.map +1 -1
  266. package/dist/core/routing/unified-router.d.ts +18 -12
  267. package/dist/core/routing/unified-router.js +220 -163
  268. package/dist/core/routing/unified-router.js.map +1 -1
  269. package/dist/core/runtime/aws-lambda-adapter.js +21 -10
  270. package/dist/core/runtime/aws-lambda-adapter.js.map +1 -1
  271. package/dist/core/runtime/base-adapter.js +15 -5
  272. package/dist/core/runtime/base-adapter.js.map +1 -1
  273. package/dist/core/runtime/cloudflare-workers-adapter.js +35 -12
  274. package/dist/core/runtime/cloudflare-workers-adapter.js.map +1 -1
  275. package/dist/core/runtime/vercel-edge-adapter.js +16 -6
  276. package/dist/core/runtime/vercel-edge-adapter.js.map +1 -1
  277. package/dist/core/utilities/container.js +3 -1
  278. package/dist/core/utilities/container.js.map +1 -1
  279. package/dist/core/utilities/index.d.ts +2 -0
  280. package/dist/core/utilities/index.js +2 -0
  281. package/dist/core/utilities/index.js.map +1 -1
  282. package/dist/core/utilities/response-helpers.d.ts +280 -0
  283. package/dist/core/utilities/response-helpers.js +359 -0
  284. package/dist/core/utilities/response-helpers.js.map +1 -0
  285. package/dist/core/workers/facade.d.ts +74 -0
  286. package/dist/core/workers/facade.js +98 -0
  287. package/dist/core/workers/facade.js.map +1 -0
  288. package/dist/core/workers/index.d.ts +2 -0
  289. package/dist/core/workers/index.js +6 -0
  290. package/dist/core/workers/index.js.map +1 -0
  291. package/dist/core/workers/worker-manager.d.ts +124 -0
  292. package/dist/core/workers/worker-manager.js +299 -0
  293. package/dist/core/workers/worker-manager.js.map +1 -0
  294. package/dist/core/workers/worker.d.ts +1 -0
  295. package/dist/core/workers/worker.js +225 -0
  296. package/dist/core/workers/worker.js.map +1 -0
  297. package/dist/index.d.ts +10 -2
  298. package/dist/index.js +9 -2
  299. package/dist/index.js.map +1 -1
  300. package/dist/moro.d.ts +345 -13
  301. package/dist/moro.js +820 -221
  302. package/dist/moro.js.map +1 -1
  303. package/dist/types/cache.d.ts +4 -0
  304. package/dist/types/config.d.ts +42 -0
  305. package/dist/types/core.d.ts +18 -1
  306. package/dist/types/http.d.ts +21 -0
  307. package/package.json +98 -24
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,11 +16,12 @@ 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';
20
- // uWebSockets Worker Thread Clustering
21
- import { UWSWorkerClusterManager } from './core/http/utils/uws-worker-clustering.js';
22
- import { isMainThread } from 'worker_threads';
23
19
  // Job System Integration
24
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
25
  // Lazy imports for GraphQL to avoid crashes when not installed
26
26
  let GraphQLCore;
27
27
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -67,6 +67,23 @@ export class Moro extends EventEmitter {
67
67
  graphqlCore; // Use any to avoid import dependency
68
68
  graphqlSubscriptionManager;
69
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
70
87
  constructor(options = {}) {
71
88
  super(); // Call EventEmitter constructor
72
89
  // Track if user explicitly set logger/logging options
@@ -155,6 +172,8 @@ export class Moro extends EventEmitter {
155
172
  leaderElection: jobSchedulerOptions.enableLeaderElection,
156
173
  });
157
174
  }
175
+ // Initialize worker threads facade (optional - lazy loaded)
176
+ this.workerFacade = new WorkerThreadsFacade();
158
177
  // Setup default middleware if enabled - use config defaults with options override
159
178
  this.setupDefaultMiddleware({
160
179
  ...this.getDefaultOptionsFromConfig(),
@@ -457,19 +476,10 @@ export class Moro extends EventEmitter {
457
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');
458
477
  }
459
478
  // Check if clustering is enabled for massive performance gains
460
- const usingUWebSockets = this.config.server?.useUWebSockets || false;
461
479
  if (this.config.performance?.clustering?.enabled) {
462
- if (usingUWebSockets) {
463
- // Use worker thread clustering for uWebSockets
464
- this.logger.info('uWebSockets clustering enabled - using worker threads with acceptor pattern', 'Cluster');
465
- this.startWithUWSClustering(port, host, callback);
466
- return;
467
- }
468
- else {
469
- // Use traditional Node.js cluster module for standard HTTP
470
- this.startWithClustering(port, host, callback);
471
- return;
472
- }
480
+ this.logger.info('Clustering enabled - using Node.js cluster', 'Cluster');
481
+ this.startWithClustering(port, host, callback);
482
+ return;
473
483
  }
474
484
  this.eventBus.emit('server:starting', { port, runtime: this.runtimeType });
475
485
  // Add documentation middleware first (if enabled)
@@ -483,7 +493,7 @@ export class Moro extends EventEmitter {
483
493
  this.logger.debug('Documentation not enabled', 'Documentation');
484
494
  }
485
495
  // Add unified routing middleware (handles both chainable and direct routes)
486
- // Optimized: call router without extra async wrapper when possible
496
+ // Call router without extra async wrapper when possible
487
497
  this.coreFramework.addMiddleware(async (req, res, next) => {
488
498
  // Try unified router first (handles all route types)
489
499
  const handled = this.unifiedRouter.handleRequest(req, res);
@@ -528,6 +538,16 @@ export class Moro extends EventEmitter {
528
538
  this.startJobScheduler().catch(err => {
529
539
  this.logger.error(`Failed to start job scheduler: ${String(err)}`);
530
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
+ }
531
551
  if (callback)
532
552
  callback();
533
553
  };
@@ -748,7 +768,7 @@ export class Moro extends EventEmitter {
748
768
  staticRouteMap = new Map();
749
769
  dynamicRoutesBySegments = new Map();
750
770
  findMatchingRoute(method, path) {
751
- // Phase 1: O(1) static route lookup
771
+ // O(1) static route lookup
752
772
  const staticKey = `${method}:${path}`;
753
773
  const staticRoute = this.staticRouteMap.get(staticKey);
754
774
  if (staticRoute) {
@@ -758,7 +778,7 @@ export class Moro extends EventEmitter {
758
778
  paramNames: [],
759
779
  };
760
780
  }
761
- // Phase 2: Optimized dynamic route matching by segment count
781
+ // Dynamic route matching by segment count
762
782
  const segmentCount = PathMatcher.countSegments(path);
763
783
  const candidateRoutes = this.dynamicRoutesBySegments.get(segmentCount) || [];
764
784
  for (const route of candidateRoutes) {
@@ -941,11 +961,11 @@ export class Moro extends EventEmitter {
941
961
  : this.config.security.cors
942
962
  ? this.config.security.cors
943
963
  : {};
944
- this.use(middleware.cors(corsOptions));
964
+ this.use(cors(corsOptions));
945
965
  }
946
966
  // Helmet - check config enabled property OR options.security.helmet.enabled === true
947
967
  if (this.config.security.helmet.enabled || options.security?.helmet?.enabled === true) {
948
- this.use(middleware.helmet());
968
+ this.use(helmet());
949
969
  }
950
970
  // Compression - check config enabled property OR options.performance.compression.enabled === true
951
971
  if (this.config.performance.compression.enabled ||
@@ -955,10 +975,10 @@ export class Moro extends EventEmitter {
955
975
  : this.config.performance.compression
956
976
  ? this.config.performance.compression
957
977
  : {};
958
- this.use(middleware.compression(compressionOptions));
978
+ this.use(compression(compressionOptions));
959
979
  }
960
980
  // Body size limiting
961
- this.use(middleware.bodySize({ limit: '10mb' }));
981
+ this.use(bodySize({ limit: '10mb' }));
962
982
  }
963
983
  // Enhanced auto-discovery initialization
964
984
  async initializeAutoDiscovery(options) {
@@ -1313,7 +1333,7 @@ export class Moro extends EventEmitter {
1313
1333
  // Documentation not enabled, that's fine
1314
1334
  }
1315
1335
  // Add unified routing middleware (handles both chainable and direct routes)
1316
- // Optimized: call router without extra async wrapper when possible
1336
+ // Call router without extra async wrapper when possible
1317
1337
  this.coreFramework.addMiddleware(async (req, res, next) => {
1318
1338
  // Try unified router first (handles all route types)
1319
1339
  const handled = this.unifiedRouter.handleRequest(req, res);
@@ -1384,181 +1404,22 @@ export class Moro extends EventEmitter {
1384
1404
  // Log other worker messages
1385
1405
  this.logger.debug(`Worker message: ${JSON.stringify(message)}`, 'Cluster');
1386
1406
  }
1387
- /**
1388
- * uWebSockets Worker Thread Clustering Implementation
1389
- * Uses worker threads with acceptor pattern for maximum performance
1390
- */
1391
- async startWithUWSClustering(port, host, callback) {
1392
- // Check if we're in a worker thread spawned by UWSWorkerClusterManager
1393
- if (UWSWorkerClusterManager.isUWSWorker()) {
1394
- // Worker thread mode - setup the app and send descriptor to acceptor
1395
- await this.startUWSWorker(port, host, callback);
1396
- return;
1397
- }
1398
- // Main thread mode - create acceptor and spawn workers
1399
- if (isMainThread) {
1400
- await this.startUWSAcceptor(port, host, callback);
1401
- return;
1402
- }
1403
- }
1404
- async startUWSAcceptor(port, host, callback) {
1405
- const clusterManager = new UWSWorkerClusterManager({
1406
- workers: this.config.performance?.clustering?.workers,
1407
- memoryPerWorkerGB: this.config.performance?.clustering?.memoryPerWorkerGB,
1408
- port,
1409
- host,
1410
- ssl: this.config.server?.ssl,
1411
- });
1412
- try {
1413
- await clusterManager.startAcceptorAndWorkers(() => {
1414
- // This factory function is not used in our implementation
1415
- // as we're using process.argv[1] to spawn workers
1416
- return null;
1417
- });
1418
- if (callback) {
1419
- callback();
1420
- }
1421
- }
1422
- catch (error) {
1423
- this.logger.error('Failed to start uWebSockets cluster', 'UWSCluster', {
1424
- error: error instanceof Error ? error.message : String(error),
1425
- });
1426
- throw error;
1427
- }
1428
- }
1429
- async startUWSWorker(port, host, callback) {
1430
- this.logger.info(`UWS Worker thread ${process.pid} initializing`, 'UWSWorker');
1431
- // Reduce logging contention in workers
1432
- if (!this.userSetLogger) {
1433
- applyLoggingConfiguration(undefined, { level: 'warn' });
1434
- }
1435
- // Worker-specific optimizations
1436
- process.env.UV_THREADPOOL_SIZE = '64';
1437
- // Setup graceful shutdown for worker
1438
- let isShuttingDown = false;
1439
- const shutdownWorker = async () => {
1440
- if (isShuttingDown)
1441
- return;
1442
- isShuttingDown = true;
1443
- this.logger.info(`UWS Worker thread ${process.pid} shutting down...`, 'UWSWorker');
1444
- // Close the server to clean up handles
1445
- const httpServer = this.coreFramework.httpServer;
1446
- if (httpServer && typeof httpServer.close === 'function') {
1447
- // Convert callback-based close to Promise
1448
- await new Promise(resolve => {
1449
- httpServer.close(() => {
1450
- resolve();
1451
- });
1452
- // Timeout after 1.5 seconds
1453
- setTimeout(() => {
1454
- this.logger.warn('HTTP server close timeout', 'UWSWorker');
1455
- resolve();
1456
- }, 1500);
1457
- });
1458
- }
1459
- // Clean up ALL event listeners
1460
- try {
1461
- this.eventBus.removeAllListeners();
1462
- }
1463
- catch {
1464
- // Ignore cleanup errors
1465
- }
1466
- try {
1467
- this.removeAllListeners();
1468
- }
1469
- catch {
1470
- // Ignore cleanup errors
1471
- }
1472
- // Remove all signal handlers
1473
- process.removeAllListeners('SIGINT');
1474
- process.removeAllListeners('SIGTERM');
1475
- this.logger.info(`UWS Worker thread ${process.pid} cleanup complete`, 'UWSWorker');
1476
- };
1477
- // Handle shutdown messages from parent
1478
- UWSWorkerClusterManager.setupWorkerShutdownHandler(shutdownWorker);
1479
- // Also handle direct signals
1480
- process.once('SIGINT', shutdownWorker);
1481
- process.once('SIGTERM', shutdownWorker);
1482
- // Emit worker starting event
1483
- this.eventBus.emit('server:starting', {
1484
- port,
1485
- runtime: this.runtimeType,
1486
- worker: process.pid,
1487
- workerType: 'thread',
1488
- });
1489
- // Add documentation middleware first (if enabled)
1490
- try {
1491
- const docsMiddleware = this.documentation.getDocsMiddleware();
1492
- this.coreFramework.addMiddleware(docsMiddleware);
1493
- }
1494
- catch {
1495
- // Documentation not enabled, that's fine
1496
- }
1497
- // Add unified routing middleware
1498
- this.coreFramework.addMiddleware(async (req, res, next) => {
1499
- const handled = this.unifiedRouter.handleRequest(req, res);
1500
- if (handled && typeof handled.then === 'function') {
1501
- const isHandled = await handled;
1502
- if (!isHandled) {
1503
- next();
1504
- }
1505
- }
1506
- else {
1507
- if (!handled) {
1508
- next();
1509
- }
1510
- }
1511
- });
1512
- // Register legacy direct routes with the HTTP server
1513
- if (this.routes.length > 0) {
1514
- this.registerDirectRoutes();
1515
- }
1516
- const workerCallback = () => {
1517
- const displayHost = host || 'localhost';
1518
- this.logger.info(`UWS Worker thread ${process.pid} ready on ${displayHost}:${port}`, 'UWSWorker');
1519
- this.eventBus.emit('server:started', {
1520
- port,
1521
- runtime: this.runtimeType,
1522
- worker: process.pid,
1523
- workerType: 'thread',
1524
- });
1525
- // Send descriptor to acceptor
1526
- const httpServer = this.coreFramework.httpServer;
1527
- if (httpServer && typeof httpServer.getDescriptor === 'function') {
1528
- UWSWorkerClusterManager.sendDescriptorToAcceptor(httpServer.getApp())
1529
- .then(() => {
1530
- if (callback) {
1531
- callback();
1532
- }
1533
- })
1534
- .catch((error) => {
1535
- this.logger.error('Failed to send descriptor to acceptor', 'UWSWorker', {
1536
- error: error.message,
1537
- });
1538
- });
1539
- }
1540
- else {
1541
- this.logger.error('HTTP server does not support getDescriptor()', 'UWSWorker');
1542
- }
1543
- };
1544
- // Ensure WebSocket setup is complete before starting worker
1545
- await this.processQueuedWebSocketRegistrations();
1546
- // Start listening on worker-specific port (4000 range)
1547
- const workerPort = 4000 + parseInt(process.env.UWS_WORKER_INDEX || '0', 10);
1548
- if (host) {
1549
- this.coreFramework.listen(workerPort, host, workerCallback);
1550
- }
1551
- else {
1552
- this.coreFramework.listen(workerPort, workerCallback);
1553
- }
1554
- }
1555
1407
  /**
1556
1408
  * Gracefully close the application and clean up resources
1557
1409
  * This should be called in tests and during shutdown
1558
1410
  */
1559
1411
  async close() {
1560
1412
  this.logger.debug('Closing Moro application...');
1561
- // Shutdown job scheduler first
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
1562
1423
  if (this.jobScheduler) {
1563
1424
  try {
1564
1425
  this.logger.info('Shutting down job scheduler...');
@@ -1569,13 +1430,20 @@ export class Moro extends EventEmitter {
1569
1430
  this.logger.error(`Error shutting down job scheduler: ${String(err)}`);
1570
1431
  }
1571
1432
  }
1572
- // Cleanup GraphQL executor timers
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
1573
1444
  if (this.graphqlCore) {
1574
1445
  try {
1575
- const executor = this.graphqlCore.getExecutor();
1576
- if (executor) {
1577
- executor.cleanup();
1578
- }
1446
+ await this.graphqlCore.cleanup();
1579
1447
  }
1580
1448
  catch (err) {
1581
1449
  this.logger.error(`Error cleaning up GraphQL: ${String(err)}`);
@@ -1592,14 +1460,27 @@ export class Moro extends EventEmitter {
1592
1460
  // Close the core framework with timeout
1593
1461
  if (this.coreFramework && this.coreFramework.httpServer) {
1594
1462
  try {
1595
- await Promise.race([
1596
- new Promise(resolve => {
1597
- this.coreFramework.httpServer.close(() => {
1598
- resolve();
1599
- });
1600
- }),
1601
- new Promise(resolve => setTimeout(resolve, 2000)), // 2 second timeout
1602
- ]);
1463
+ const httpServer = this.coreFramework.httpServer;
1464
+ const server = httpServer.getServer?.() || httpServer.getApp?.();
1465
+ // Only wait for close if the server is actually listening
1466
+ const isListening = server?.listening || server?.address?.() !== null;
1467
+ if (isListening) {
1468
+ await Promise.race([
1469
+ new Promise(resolve => {
1470
+ httpServer.close(() => {
1471
+ resolve();
1472
+ });
1473
+ }),
1474
+ new Promise(resolve => {
1475
+ const timer = setTimeout(resolve, 2000); // 2 second timeout
1476
+ timer.unref(); // Don't keep process alive
1477
+ }),
1478
+ ]);
1479
+ }
1480
+ else {
1481
+ // Server was never started, just skip close
1482
+ this.logger.debug('HTTP server was never started, skipping close');
1483
+ }
1603
1484
  }
1604
1485
  catch {
1605
1486
  // Force close if graceful close fails
@@ -1615,6 +1496,31 @@ export class Moro extends EventEmitter {
1615
1496
  // Ignore cleanup errors
1616
1497
  }
1617
1498
  }
1499
+ // Shutdown queue manager
1500
+ if (this.queueManager) {
1501
+ try {
1502
+ await this.queueManager.shutdown();
1503
+ this.logger.debug('Queue system shutdown complete');
1504
+ }
1505
+ catch (error) {
1506
+ this.logger.warn(`Error shutting down queue system: ${error}`);
1507
+ }
1508
+ }
1509
+ // Clear queue state on close
1510
+ this.queueConfigs.clear();
1511
+ this.queueInitialized = false;
1512
+ this.queueInitPromise = undefined;
1513
+ this.queueManager = undefined;
1514
+ // Shutdown mail system
1515
+ if (this.mailManager) {
1516
+ try {
1517
+ await this.mailManager.close();
1518
+ this.logger.debug('Mail system shutdown complete');
1519
+ }
1520
+ catch (error) {
1521
+ this.logger.warn(`Error shutting down mail system: ${error}`);
1522
+ }
1523
+ }
1618
1524
  // Clean up event listeners
1619
1525
  try {
1620
1526
  this.eventBus.removeAllListeners();
@@ -1796,14 +1702,14 @@ export class Moro extends EventEmitter {
1796
1702
  // GraphQL API
1797
1703
  // ========================================
1798
1704
  /**
1799
- * Configure GraphQL endpoint with schema, resolvers, and options
1705
+ * Configure GraphQL endpoint (synchronous, lazy initialization)
1800
1706
  *
1801
1707
  * @param options - GraphQL configuration options
1802
1708
  *
1803
1709
  * @example
1804
1710
  * ```ts
1805
1711
  * // Using type definitions and resolvers
1806
- * app.graphql({
1712
+ * app.graphqlInit({
1807
1713
  * typeDefs: `
1808
1714
  * type Query {
1809
1715
  * hello: String
@@ -1832,14 +1738,14 @@ export class Moro extends EventEmitter {
1832
1738
  * })
1833
1739
  * });
1834
1740
  *
1835
- * app.graphql({
1741
+ * app.graphqlInit({
1836
1742
  * pothosSchema: builder
1837
1743
  * });
1838
1744
  * ```
1839
1745
  */
1840
- graphql(options) {
1746
+ graphqlInit(options) {
1841
1747
  if (this.graphqlCore || this.graphqlInitPromise) {
1842
- throw new Error('GraphQL has already been configured. Call graphql() only once.');
1748
+ throw new Error('GraphQL has already been configured. Call graphqlInit() only once.');
1843
1749
  }
1844
1750
  // Check if graphql package is available
1845
1751
  if (!this.isGraphQLAvailable()) {
@@ -1848,21 +1754,31 @@ export class Moro extends EventEmitter {
1848
1754
  'For TypeScript-first GraphQL, also consider: npm install @pothos/core\n' +
1849
1755
  'For performance boost: npm install graphql-jit');
1850
1756
  }
1851
- this.logger.info('Configuring GraphQL', 'GraphQL', {
1757
+ this.logger.info('Configuring GraphQL (will initialize on server start)', 'GraphQL', {
1852
1758
  path: options.path || '/graphql',
1853
1759
  jit: options.enableJIT !== false,
1854
1760
  playground: options.enablePlayground !== false,
1855
1761
  });
1856
- // Initialize GraphQL asynchronously (like WebSocket registration pattern)
1762
+ // Store config and trigger initialization immediately
1763
+ this.graphqlConfig = options;
1857
1764
  this.graphqlInitPromise = this.initializeGraphQL(options);
1858
- // Add to initialization promises
1859
- const originalEnsure = this.ensureAutoDiscoveryComplete.bind(this);
1860
- this.ensureAutoDiscoveryComplete = async () => {
1861
- await originalEnsure();
1862
- await this.graphqlInitPromise;
1863
- };
1765
+ this.eventBus.emit('graphql:configured', { options });
1864
1766
  return this;
1865
1767
  }
1768
+ /**
1769
+ * Lazy initialize GraphQL system
1770
+ */
1771
+ async ensureGraphQLInitialized() {
1772
+ if (this.graphqlCore || this.graphqlInitPromise) {
1773
+ await this.graphqlInitPromise;
1774
+ return;
1775
+ }
1776
+ if (!this.graphqlConfig) {
1777
+ return; // GraphQL not configured, skip
1778
+ }
1779
+ this.graphqlInitPromise = this.initializeGraphQL(this.graphqlConfig);
1780
+ await this.graphqlInitPromise;
1781
+ }
1866
1782
  /**
1867
1783
  * Initialize GraphQL system asynchronously
1868
1784
  */
@@ -1941,13 +1857,74 @@ export class Moro extends EventEmitter {
1941
1857
  /**
1942
1858
  * Get GraphQL schema (if configured)
1943
1859
  */
1944
- getGraphQLSchema() {
1860
+ async getGraphQLSchema() {
1861
+ await this.ensureGraphQLInitialized();
1945
1862
  return this.graphqlCore?.getSchema();
1946
1863
  }
1864
+ // ========================================
1865
+ // Worker Threads API
1866
+ // ========================================
1867
+ /**
1868
+ * Execute a task on worker threads (CPU-intensive operations)
1869
+ * @param task - Task to execute
1870
+ * @returns Promise resolving to task result
1871
+ *
1872
+ * @example
1873
+ * ```ts
1874
+ * // JWT verification (CPU-intensive)
1875
+ * const payload = await app.executeOnWorker({
1876
+ * id: 'jwt-verify-123',
1877
+ * type: 'jwt:verify',
1878
+ * data: { token, secret }
1879
+ * });
1880
+ *
1881
+ * // Heavy computation
1882
+ * const result = await app.executeOnWorker({
1883
+ * id: 'compute-456',
1884
+ * type: 'computation:heavy',
1885
+ * data: { iterations: 1000000 }
1886
+ * });
1887
+ * ```
1888
+ */
1889
+ async executeOnWorker(task) {
1890
+ return this.workerFacade.executeTask(task);
1891
+ }
1892
+ /**
1893
+ * Get worker manager instance for advanced usage
1894
+ */
1895
+ async getWorkerManager() {
1896
+ await this.workerFacade.ensureInitialized?.(); // Trigger initialization if needed
1897
+ return this.workerFacade;
1898
+ }
1899
+ /**
1900
+ * Get worker thread statistics
1901
+ */
1902
+ async getWorkerStats() {
1903
+ return this.workerFacade.getStats();
1904
+ }
1905
+ /**
1906
+ * JWT operations using worker threads (prevents event loop blocking)
1907
+ */
1908
+ async getJwtWorker() {
1909
+ return this.workerFacade.getJwtWorker();
1910
+ }
1911
+ /**
1912
+ * Crypto operations using worker threads
1913
+ */
1914
+ async getCryptoWorker() {
1915
+ return this.workerFacade.getCryptoWorker();
1916
+ }
1917
+ /**
1918
+ * Heavy computation operations using worker threads
1919
+ */
1920
+ async getComputeWorker() {
1921
+ return this.workerFacade.getComputeWorker();
1922
+ }
1947
1923
  /**
1948
1924
  * Get GraphQL stats
1949
1925
  */
1950
- getGraphQLStats() {
1926
+ async getGraphQLStats() {
1927
+ await this.ensureGraphQLInitialized();
1951
1928
  if (!this.graphqlCore) {
1952
1929
  return null;
1953
1930
  }
@@ -1956,6 +1933,628 @@ export class Moro extends EventEmitter {
1956
1933
  subscriptions: this.graphqlSubscriptionManager?.getSubscriptionCount() || 0,
1957
1934
  };
1958
1935
  }
1936
+ // =====================
1937
+ // gRPC Methods
1938
+ // =====================
1939
+ /**
1940
+ * Configure gRPC server (synchronous, lazy initialization)
1941
+ *
1942
+ * @example
1943
+ * ```typescript
1944
+ * app.grpcInit({
1945
+ * port: 50051,
1946
+ * host: '0.0.0.0',
1947
+ * adapter: 'grpc-js',
1948
+ * enableHealthCheck: true,
1949
+ * enableReflection: true
1950
+ * });
1951
+ * ```
1952
+ */
1953
+ grpcInit(options = {}) {
1954
+ if (this.grpcInitPromise) {
1955
+ this.logger.warn('gRPC already configured', 'GRPC');
1956
+ return this;
1957
+ }
1958
+ this.logger.info('Configuring gRPC (will initialize on server start)', 'GRPC');
1959
+ // Store config for lazy initialization
1960
+ this.grpcConfig = {
1961
+ port: 50051,
1962
+ host: '0.0.0.0',
1963
+ adapter: 'grpc-js',
1964
+ enableHealthCheck: true,
1965
+ enableReflection: false,
1966
+ ...options,
1967
+ };
1968
+ return this;
1969
+ }
1970
+ /**
1971
+ * Lazy initialize gRPC system
1972
+ */
1973
+ async ensureGrpcInitialized() {
1974
+ if (this.grpcManager || this.grpcInitPromise) {
1975
+ await this.grpcInitPromise;
1976
+ return;
1977
+ }
1978
+ if (!this.grpcConfig) {
1979
+ return; // gRPC not configured, skip
1980
+ }
1981
+ this.grpcInitPromise = (async () => {
1982
+ try {
1983
+ this.logger.info('Initializing gRPC system', 'GRPC');
1984
+ // Lazy load gRPC manager
1985
+ const { GrpcManager } = await import('./core/grpc/grpc-manager.js');
1986
+ // Create gRPC manager
1987
+ this.grpcManager = new GrpcManager(this.grpcConfig);
1988
+ // Initialize gRPC
1989
+ await this.grpcManager.initialize();
1990
+ this.logger.info('gRPC system initialized', 'GRPC');
1991
+ }
1992
+ catch (error) {
1993
+ this.logger.error(`Failed to initialize gRPC: ${error}`, 'GRPC');
1994
+ throw error;
1995
+ }
1996
+ })();
1997
+ await this.grpcInitPromise;
1998
+ }
1999
+ /**
2000
+ * Register a gRPC service from a proto file
2001
+ *
2002
+ * @example
2003
+ * ```typescript
2004
+ * app.grpcService('./proto/users.proto', 'UserService', {
2005
+ * getUser: async (call, callback) => {
2006
+ * const user = await db.users.findById(call.request.id);
2007
+ * callback(null, user);
2008
+ * },
2009
+ * listUsers: async (call) => {
2010
+ * for (const user of users) {
2011
+ * call.write(user);
2012
+ * }
2013
+ * call.end();
2014
+ * }
2015
+ * });
2016
+ * ```
2017
+ */
2018
+ async grpcService(protoPath, serviceName, implementation, packageName) {
2019
+ if (!this.grpcConfig && !this.grpcManager) {
2020
+ throw new Error('gRPC not initialized. Call app.grpcInit() first.\n' +
2021
+ 'Example: app.grpcInit({ port: 50051 });');
2022
+ }
2023
+ // Lazy initialize gRPC if not already done
2024
+ await this.ensureGrpcInitialized();
2025
+ if (!this.grpcManager) {
2026
+ throw new Error('gRPC not initialized. Call app.grpcInit() first.\n' +
2027
+ 'Example: app.grpcInit({ port: 50051 });');
2028
+ }
2029
+ try {
2030
+ await this.grpcManager.registerService(protoPath, serviceName, implementation, packageName);
2031
+ this.logger.info(`gRPC service registered: ${serviceName}`, 'GRPC');
2032
+ }
2033
+ catch (error) {
2034
+ this.logger.error(`Failed to register gRPC service ${serviceName}: ${error}`, 'GRPC');
2035
+ throw error;
2036
+ }
2037
+ }
2038
+ /**
2039
+ * Start gRPC server
2040
+ * Called automatically by listen() if gRPC is configured
2041
+ */
2042
+ async startGrpc() {
2043
+ // Lazy initialize if needed
2044
+ await this.ensureGrpcInitialized();
2045
+ if (!this.grpcManager) {
2046
+ return;
2047
+ }
2048
+ if (this.grpcStarted) {
2049
+ this.logger.warn('gRPC server already started', 'GRPC');
2050
+ return;
2051
+ }
2052
+ try {
2053
+ await this.grpcManager.start();
2054
+ this.grpcStarted = true;
2055
+ const stats = this.grpcManager.getStats();
2056
+ if (stats) {
2057
+ this.logger.info('gRPC server started successfully', 'GRPC');
2058
+ }
2059
+ }
2060
+ catch (error) {
2061
+ this.logger.error(`Failed to start gRPC server: ${error}`, 'GRPC');
2062
+ throw error;
2063
+ }
2064
+ }
2065
+ /**
2066
+ * Stop gRPC server gracefully
2067
+ */
2068
+ async stopGrpc() {
2069
+ if (!this.grpcManager || !this.grpcStarted) {
2070
+ return;
2071
+ }
2072
+ try {
2073
+ await this.grpcManager.stop();
2074
+ this.grpcStarted = false;
2075
+ this.logger.info('gRPC server stopped', 'GRPC');
2076
+ }
2077
+ catch (error) {
2078
+ this.logger.error(`Error stopping gRPC server: ${error}`, 'GRPC');
2079
+ throw error;
2080
+ }
2081
+ }
2082
+ /**
2083
+ * Create a gRPC client for calling remote services
2084
+ *
2085
+ * @example
2086
+ * ```typescript
2087
+ * const client = await app.createGrpcClient(
2088
+ * './proto/users.proto',
2089
+ * 'UserService',
2090
+ * 'localhost:50051'
2091
+ * );
2092
+ *
2093
+ * const user = await client.getUser({ id: '123' });
2094
+ * ```
2095
+ */
2096
+ async createGrpcClient(protoPath, serviceName, address, options) {
2097
+ if (!this.grpcConfig && !this.grpcManager) {
2098
+ throw new Error('gRPC not initialized. Call app.grpcInit() first.\n' +
2099
+ 'Example: app.grpcInit({ port: 50051 });');
2100
+ }
2101
+ // Lazy initialize gRPC if not already done
2102
+ await this.ensureGrpcInitialized();
2103
+ if (!this.grpcManager) {
2104
+ throw new Error('gRPC not initialized. Call app.grpcInit() first.\n' +
2105
+ 'Example: app.grpcInit({ port: 50051 });');
2106
+ }
2107
+ try {
2108
+ const client = await this.grpcManager.createClient(protoPath, serviceName, address, options);
2109
+ this.logger.info(`gRPC client created for ${serviceName} at ${address}`, 'GRPC');
2110
+ return client;
2111
+ }
2112
+ catch (error) {
2113
+ this.logger.error(`Failed to create gRPC client: ${error}`, 'GRPC');
2114
+ throw error;
2115
+ }
2116
+ }
2117
+ /**
2118
+ * Get gRPC statistics
2119
+ */
2120
+ getGrpcStats() {
2121
+ if (!this.grpcManager) {
2122
+ return null;
2123
+ }
2124
+ return this.grpcManager.getStats();
2125
+ }
2126
+ /**
2127
+ * Get list of registered gRPC services
2128
+ */
2129
+ getGrpcServices() {
2130
+ if (!this.grpcManager) {
2131
+ return [];
2132
+ }
2133
+ return this.grpcManager.getServices();
2134
+ }
2135
+ /**
2136
+ * Initialize queue system (synchronous for first queue, subsequent queues added immediately)
2137
+ *
2138
+ * @example
2139
+ * ```typescript
2140
+ * app.queueInit('emails', {
2141
+ * adapter: 'bull',
2142
+ * connection: {
2143
+ * host: 'localhost',
2144
+ * port: 6379
2145
+ * },
2146
+ * concurrency: 5
2147
+ * });
2148
+ * ```
2149
+ */
2150
+ queueInit(name, options) {
2151
+ // Initialize queue manager on first call
2152
+ if (!this.queueInitialized && !this.queueInitPromise) {
2153
+ this.queueInitPromise = (async () => {
2154
+ try {
2155
+ this.logger.info('Initializing queue system', 'QUEUE');
2156
+ const { QueueManager } = await import('./core/queue/index.js');
2157
+ this.queueManager = new QueueManager(this.eventBus);
2158
+ this.queueInitialized = true;
2159
+ this.logger.info('Queue system initialized', 'QUEUE');
2160
+ }
2161
+ catch (error) {
2162
+ this.logger.error(`Failed to initialize queue system: ${error}`, 'QUEUE');
2163
+ throw error;
2164
+ }
2165
+ })();
2166
+ }
2167
+ // Store config to register after initialization
2168
+ this.queueConfigs.set(name, options);
2169
+ this.logger.debug(`Queue "${name}" configured`, 'QUEUE');
2170
+ // Register queue async (manager will be ready)
2171
+ if (this.queueInitPromise) {
2172
+ this.queueInitPromise
2173
+ .then(async () => {
2174
+ if (this.queueManager) {
2175
+ await this.queueManager.registerQueue(name, options);
2176
+ this.logger.info(`Queue "${name}" registered with ${options.adapter} adapter`, 'QUEUE');
2177
+ }
2178
+ })
2179
+ .catch(error => {
2180
+ this.logger.error(`Failed to register queue "${name}": ${error}`, 'QUEUE');
2181
+ });
2182
+ }
2183
+ return this;
2184
+ }
2185
+ /**
2186
+ * Ensure queue system is initialized
2187
+ */
2188
+ async ensureQueueInitialized() {
2189
+ if (this.queueInitPromise) {
2190
+ await this.queueInitPromise;
2191
+ }
2192
+ }
2193
+ /**
2194
+ * @deprecated Use queueInit() instead
2195
+ */
2196
+ async queue(name, options) {
2197
+ if (!this.queueInitialized) {
2198
+ try {
2199
+ this.logger.info('Initializing queue system', 'QUEUE');
2200
+ const { QueueManager } = await import('./core/queue/index.js');
2201
+ this.queueManager = new QueueManager(this.eventBus);
2202
+ this.queueInitialized = true;
2203
+ this.logger.info('Queue system initialized', 'QUEUE');
2204
+ }
2205
+ catch (error) {
2206
+ this.logger.error(`Failed to initialize queue system: ${error}`, 'QUEUE');
2207
+ throw error;
2208
+ }
2209
+ }
2210
+ try {
2211
+ await this.queueManager.registerQueue(name, options);
2212
+ this.logger.info(`Queue "${name}" registered with ${options.adapter} adapter`, 'QUEUE');
2213
+ }
2214
+ catch (error) {
2215
+ this.logger.error(`Failed to register queue "${name}": ${error}`, 'QUEUE');
2216
+ throw error;
2217
+ }
2218
+ }
2219
+ /**
2220
+ * Add a job to a queue
2221
+ *
2222
+ * @example
2223
+ * ```typescript
2224
+ * await app.addToQueue('emails', {
2225
+ * to: 'user@example.com',
2226
+ * subject: 'Welcome'
2227
+ * }, {
2228
+ * priority: 10,
2229
+ * delay: 5000
2230
+ * });
2231
+ * ```
2232
+ */
2233
+ async addToQueue(queueName, data, options) {
2234
+ // Ensure queue system is initialized
2235
+ await this.ensureQueueInitialized();
2236
+ if (!this.queueManager) {
2237
+ throw new Error(`Queue "${queueName}" not initialized. Call app.queueInit('${queueName}', options) first.`);
2238
+ }
2239
+ return await this.queueManager.addToQueue(queueName, data, options);
2240
+ }
2241
+ /**
2242
+ * Add multiple jobs to a queue in bulk
2243
+ *
2244
+ * @example
2245
+ * ```typescript
2246
+ * await app.addBulkToQueue('emails', [
2247
+ * { data: { to: 'user1@example.com' }, options: { priority: 1 } },
2248
+ * { data: { to: 'user2@example.com' }, options: { priority: 2 } }
2249
+ * ]);
2250
+ * ```
2251
+ */
2252
+ async addBulkToQueue(queueName, jobs) {
2253
+ // Ensure queue system is initialized
2254
+ await this.ensureQueueInitialized();
2255
+ if (!this.queueManager) {
2256
+ throw new Error(`Queue "${queueName}" not initialized. Call app.queue('${queueName}', options) first.`);
2257
+ }
2258
+ return await this.queueManager.addBulkToQueue(queueName, jobs);
2259
+ }
2260
+ /**
2261
+ * Register a processor for a queue
2262
+ *
2263
+ * @example
2264
+ * ```typescript
2265
+ * // Simple processor
2266
+ * app.processQueue('emails', async (job) => {
2267
+ * await sendEmail(job.data);
2268
+ * });
2269
+ *
2270
+ * // With concurrency
2271
+ * app.processQueue('images', 3, async (job) => {
2272
+ * await processImage(job.data);
2273
+ * });
2274
+ * ```
2275
+ */
2276
+ async processQueue(queueName, concurrencyOrHandler, handler) {
2277
+ // Ensure queue system is initialized
2278
+ await this.ensureQueueInitialized();
2279
+ if (!this.queueManager) {
2280
+ throw new Error(`Queue "${queueName}" not initialized. Call app.queueInit('${queueName}', options) first.`);
2281
+ }
2282
+ return await this.queueManager.processQueue(queueName, concurrencyOrHandler, handler);
2283
+ }
2284
+ /**
2285
+ * Get queue status
2286
+ */
2287
+ async getQueueStatus(queueName) {
2288
+ if (!this.queueManager) {
2289
+ throw new Error(`Queue system not initialized.`);
2290
+ }
2291
+ return await this.queueManager.getQueueStatus(queueName);
2292
+ }
2293
+ /**
2294
+ * Get a specific job from a queue
2295
+ */
2296
+ async getJob(queueName, jobId) {
2297
+ if (!this.queueManager) {
2298
+ throw new Error(`Queue system not initialized.`);
2299
+ }
2300
+ return await this.queueManager.getJob(queueName, jobId);
2301
+ }
2302
+ /**
2303
+ * Get jobs from a queue by status
2304
+ */
2305
+ async getJobs(queueName, status, start = 0, end = -1) {
2306
+ if (!this.queueManager) {
2307
+ throw new Error(`Queue system not initialized.`);
2308
+ }
2309
+ return await this.queueManager.getJobs(queueName, status, start, end);
2310
+ }
2311
+ /**
2312
+ * Remove a job from a queue
2313
+ */
2314
+ async removeJob(queueName, jobId) {
2315
+ if (!this.queueManager) {
2316
+ throw new Error(`Queue system not initialized.`);
2317
+ }
2318
+ return await this.queueManager.removeJob(queueName, jobId);
2319
+ }
2320
+ /**
2321
+ * Retry a failed job
2322
+ */
2323
+ async retryJob(queueName, jobId) {
2324
+ if (!this.queueManager) {
2325
+ throw new Error(`Queue system not initialized.`);
2326
+ }
2327
+ return await this.queueManager.retryJob(queueName, jobId);
2328
+ }
2329
+ /**
2330
+ * Pause a queue
2331
+ */
2332
+ async pauseQueue(queueName) {
2333
+ if (!this.queueManager) {
2334
+ throw new Error(`Queue system not initialized.`);
2335
+ }
2336
+ return await this.queueManager.pauseQueue(queueName);
2337
+ }
2338
+ /**
2339
+ * Resume a paused queue
2340
+ */
2341
+ async resumeQueue(queueName) {
2342
+ if (!this.queueManager) {
2343
+ throw new Error(`Queue system not initialized.`);
2344
+ }
2345
+ return await this.queueManager.resumeQueue(queueName);
2346
+ }
2347
+ /**
2348
+ * Clean old jobs from a queue
2349
+ */
2350
+ async cleanQueue(queueName, gracePeriod, status) {
2351
+ if (!this.queueManager) {
2352
+ throw new Error(`Queue system not initialized.`);
2353
+ }
2354
+ return await this.queueManager.cleanQueue(queueName, gracePeriod, status);
2355
+ }
2356
+ /**
2357
+ * Get all registered queue names
2358
+ */
2359
+ getQueueNames() {
2360
+ // Return configured queues (includes both initialized and pending)
2361
+ const configuredQueues = Array.from(this.queueConfigs.keys());
2362
+ if (!this.queueManager) {
2363
+ return configuredQueues;
2364
+ }
2365
+ // Merge with manager's queues (in case some were added directly)
2366
+ const managerQueues = this.queueManager.getQueueNames();
2367
+ const allQueues = new Set([...configuredQueues, ...managerQueues]);
2368
+ return Array.from(allQueues);
2369
+ }
2370
+ /**
2371
+ * Check if a queue is registered
2372
+ */
2373
+ hasQueue(queueName) {
2374
+ // Check if it's configured (includes both initialized and pending)
2375
+ if (this.queueConfigs.has(queueName)) {
2376
+ return true;
2377
+ }
2378
+ if (!this.queueManager) {
2379
+ return false;
2380
+ }
2381
+ return this.queueManager.hasQueue(queueName);
2382
+ }
2383
+ // =====================
2384
+ // Mail System Methods
2385
+ // =====================
2386
+ /**
2387
+ * Configure mail system (synchronous, lazy initialization)
2388
+ *
2389
+ * @example
2390
+ * ```typescript
2391
+ * // Using Nodemailer (SMTP) - chainable, no await needed!
2392
+ * app.mailInit({
2393
+ * adapter: 'nodemailer',
2394
+ * from: { name: 'My App', email: 'noreply@myapp.com' },
2395
+ * connection: {
2396
+ * host: 'smtp.gmail.com',
2397
+ * port: 587,
2398
+ * secure: false,
2399
+ * auth: { user: process.env.EMAIL_USER, pass: process.env.EMAIL_PASSWORD }
2400
+ * },
2401
+ * templates: { path: './emails', engine: 'moro', cache: true }
2402
+ * });
2403
+ *
2404
+ * // Using SendGrid
2405
+ * app.mailInit({
2406
+ * adapter: 'sendgrid',
2407
+ * from: 'noreply@myapp.com',
2408
+ * connection: { apiKey: process.env.SENDGRID_API_KEY }
2409
+ * });
2410
+ * ```
2411
+ */
2412
+ mailInit(config) {
2413
+ if (this.mailInitialized) {
2414
+ this.logger.warn('Mail system already configured', 'Mail');
2415
+ return this;
2416
+ }
2417
+ // Store config for lazy initialization
2418
+ this.mailConfig = config;
2419
+ this.logger.debug('Mail system configured (will initialize on first use)', 'Mail');
2420
+ this.eventBus.emit('mail:configured', { config });
2421
+ return this;
2422
+ }
2423
+ /**
2424
+ * Lazy initialize mail system on first use
2425
+ */
2426
+ async ensureMailInitialized() {
2427
+ if (this.mailInitialized) {
2428
+ return;
2429
+ }
2430
+ if (!this.mailConfig) {
2431
+ throw new Error('Mail system not configured. Call app.mailInit(config) first.\n' +
2432
+ "Example: app.mailInit({ adapter: 'console', from: 'noreply@myapp.com' });");
2433
+ }
2434
+ try {
2435
+ this.logger.info('Initializing mail system', 'Mail');
2436
+ const { MailManager } = await import('./core/mail/index.js');
2437
+ this.mailManager = new MailManager(this.mailConfig);
2438
+ await this.mailManager.initialize();
2439
+ if (this.mailConfig.queue?.enabled && this.queueManager) {
2440
+ this.mailManager.setQueueManager(this.queueManager);
2441
+ const queueName = this.mailConfig.queue.name || 'emails';
2442
+ if (!this.queueManager.hasQueue(queueName)) {
2443
+ this.queueConfigs.set(queueName, {
2444
+ adapter: 'memory',
2445
+ concurrency: this.mailConfig.queue.attempts || 3,
2446
+ });
2447
+ await this.ensureQueueInitialized();
2448
+ await this.processQueue(queueName, async (job) => {
2449
+ if (this.mailManager) {
2450
+ return await this.mailManager.send(job.data);
2451
+ }
2452
+ throw new Error('Mail manager not initialized');
2453
+ });
2454
+ }
2455
+ this.logger.info(`Mail queue "${queueName}" configured`, 'Mail');
2456
+ }
2457
+ this.mailInitialized = true;
2458
+ this.logger.info('Mail system initialized successfully', 'Mail');
2459
+ }
2460
+ catch (error) {
2461
+ this.logger.error(`Failed to initialize mail system: ${error}`, 'Mail');
2462
+ throw error;
2463
+ }
2464
+ }
2465
+ /**
2466
+ * Send an email
2467
+ *
2468
+ * @example
2469
+ * ```typescript
2470
+ * // Simple email
2471
+ * await app.sendMail({
2472
+ * to: 'user@example.com',
2473
+ * subject: 'Welcome',
2474
+ * text: 'Welcome to our app!'
2475
+ * });
2476
+ *
2477
+ * // With template
2478
+ * await app.sendMail({
2479
+ * to: 'user@example.com',
2480
+ * subject: 'Password Reset',
2481
+ * template: 'password-reset',
2482
+ * data: { name: 'John', resetUrl: 'https://myapp.com/reset/token123' }
2483
+ * });
2484
+ *
2485
+ * // With attachments
2486
+ * await app.sendMail({
2487
+ * to: 'user@example.com',
2488
+ * subject: 'Invoice',
2489
+ * template: 'invoice',
2490
+ * data: { invoice },
2491
+ * attachments: [{ filename: 'invoice.pdf', content: pdfBuffer }]
2492
+ * });
2493
+ * ```
2494
+ */
2495
+ async sendMail(options) {
2496
+ // Lazy initialize on first use
2497
+ await this.ensureMailInitialized();
2498
+ this.eventBus.emit('mail:sending', { options });
2499
+ try {
2500
+ const result = await this.mailManager.send(options);
2501
+ if (result.success) {
2502
+ this.eventBus.emit('mail:sent', { result, options });
2503
+ }
2504
+ else {
2505
+ this.eventBus.emit('mail:failed', { error: new Error(result.error), options });
2506
+ }
2507
+ return result;
2508
+ }
2509
+ catch (error) {
2510
+ this.eventBus.emit('mail:failed', { error, options });
2511
+ throw error;
2512
+ }
2513
+ }
2514
+ /**
2515
+ * Send multiple emails in bulk
2516
+ *
2517
+ * @example
2518
+ * ```typescript
2519
+ * await app.sendBulkMail([
2520
+ * { to: 'user1@example.com', subject: 'Hello', text: 'Hi!' },
2521
+ * { to: 'user2@example.com', subject: 'Hello', text: 'Hi!' }
2522
+ * ]);
2523
+ * ```
2524
+ */
2525
+ async sendBulkMail(options) {
2526
+ // Lazy initialize on first use
2527
+ await this.ensureMailInitialized();
2528
+ return await this.mailManager.sendBulk(options);
2529
+ }
2530
+ /**
2531
+ * Verify mail adapter connection
2532
+ */
2533
+ async verifyMail() {
2534
+ // Lazy initialize on first use
2535
+ try {
2536
+ await this.ensureMailInitialized();
2537
+ return await this.mailManager.verify();
2538
+ }
2539
+ catch {
2540
+ return false;
2541
+ }
2542
+ }
2543
+ /**
2544
+ * Get mail template engine for advanced usage
2545
+ */
2546
+ getMailTemplateEngine() {
2547
+ if (!this.mailManager) {
2548
+ return undefined;
2549
+ }
2550
+ return this.mailManager.getTemplateEngine();
2551
+ }
2552
+ /**
2553
+ * Check if mail system is configured
2554
+ */
2555
+ hasMailSystem() {
2556
+ return !!this.mailConfig || this.mailInitialized;
2557
+ }
1959
2558
  }
1960
2559
  // Export convenience function
1961
2560
  export function createApp(options) {