@morojs/moro 1.6.8 → 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 (300) 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 +205 -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 +803 -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 +21 -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 +415 -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/workers/facade.d.ts +74 -0
  280. package/dist/core/workers/facade.js +98 -0
  281. package/dist/core/workers/facade.js.map +1 -0
  282. package/dist/core/workers/index.d.ts +2 -0
  283. package/dist/core/workers/index.js +6 -0
  284. package/dist/core/workers/index.js.map +1 -0
  285. package/dist/core/workers/worker-manager.d.ts +124 -0
  286. package/dist/core/workers/worker-manager.js +299 -0
  287. package/dist/core/workers/worker-manager.js.map +1 -0
  288. package/dist/core/workers/worker.d.ts +1 -0
  289. package/dist/core/workers/worker.js +225 -0
  290. package/dist/core/workers/worker.js.map +1 -0
  291. package/dist/index.d.ts +8 -1
  292. package/dist/index.js +6 -1
  293. package/dist/index.js.map +1 -1
  294. package/dist/moro.d.ts +345 -13
  295. package/dist/moro.js +803 -214
  296. package/dist/moro.js.map +1 -1
  297. package/dist/types/cache.d.ts +4 -0
  298. package/dist/types/config.d.ts +42 -0
  299. package/dist/types/core.d.ts +18 -1
  300. package/package.json +94 -20
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)}`);
@@ -1598,7 +1466,10 @@ export class Moro extends EventEmitter {
1598
1466
  resolve();
1599
1467
  });
1600
1468
  }),
1601
- 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
+ }),
1602
1473
  ]);
1603
1474
  }
1604
1475
  catch {
@@ -1615,6 +1486,31 @@ export class Moro extends EventEmitter {
1615
1486
  // Ignore cleanup errors
1616
1487
  }
1617
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
+ }
1618
1514
  // Clean up event listeners
1619
1515
  try {
1620
1516
  this.eventBus.removeAllListeners();
@@ -1796,14 +1692,14 @@ export class Moro extends EventEmitter {
1796
1692
  // GraphQL API
1797
1693
  // ========================================
1798
1694
  /**
1799
- * Configure GraphQL endpoint with schema, resolvers, and options
1695
+ * Configure GraphQL endpoint (synchronous, lazy initialization)
1800
1696
  *
1801
1697
  * @param options - GraphQL configuration options
1802
1698
  *
1803
1699
  * @example
1804
1700
  * ```ts
1805
1701
  * // Using type definitions and resolvers
1806
- * app.graphql({
1702
+ * app.graphqlInit({
1807
1703
  * typeDefs: `
1808
1704
  * type Query {
1809
1705
  * hello: String
@@ -1832,14 +1728,14 @@ export class Moro extends EventEmitter {
1832
1728
  * })
1833
1729
  * });
1834
1730
  *
1835
- * app.graphql({
1731
+ * app.graphqlInit({
1836
1732
  * pothosSchema: builder
1837
1733
  * });
1838
1734
  * ```
1839
1735
  */
1840
- graphql(options) {
1736
+ graphqlInit(options) {
1841
1737
  if (this.graphqlCore || this.graphqlInitPromise) {
1842
- throw new Error('GraphQL has already been configured. Call graphql() only once.');
1738
+ throw new Error('GraphQL has already been configured. Call graphqlInit() only once.');
1843
1739
  }
1844
1740
  // Check if graphql package is available
1845
1741
  if (!this.isGraphQLAvailable()) {
@@ -1848,21 +1744,31 @@ export class Moro extends EventEmitter {
1848
1744
  'For TypeScript-first GraphQL, also consider: npm install @pothos/core\n' +
1849
1745
  'For performance boost: npm install graphql-jit');
1850
1746
  }
1851
- this.logger.info('Configuring GraphQL', 'GraphQL', {
1747
+ this.logger.info('Configuring GraphQL (will initialize on server start)', 'GraphQL', {
1852
1748
  path: options.path || '/graphql',
1853
1749
  jit: options.enableJIT !== false,
1854
1750
  playground: options.enablePlayground !== false,
1855
1751
  });
1856
- // Initialize GraphQL asynchronously (like WebSocket registration pattern)
1752
+ // Store config and trigger initialization immediately
1753
+ this.graphqlConfig = options;
1857
1754
  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
- };
1755
+ this.eventBus.emit('graphql:configured', { options });
1864
1756
  return this;
1865
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
+ }
1866
1772
  /**
1867
1773
  * Initialize GraphQL system asynchronously
1868
1774
  */
@@ -1941,13 +1847,74 @@ export class Moro extends EventEmitter {
1941
1847
  /**
1942
1848
  * Get GraphQL schema (if configured)
1943
1849
  */
1944
- getGraphQLSchema() {
1850
+ async getGraphQLSchema() {
1851
+ await this.ensureGraphQLInitialized();
1945
1852
  return this.graphqlCore?.getSchema();
1946
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
+ }
1947
1913
  /**
1948
1914
  * Get GraphQL stats
1949
1915
  */
1950
- getGraphQLStats() {
1916
+ async getGraphQLStats() {
1917
+ await this.ensureGraphQLInitialized();
1951
1918
  if (!this.graphqlCore) {
1952
1919
  return null;
1953
1920
  }
@@ -1956,6 +1923,628 @@ export class Moro extends EventEmitter {
1956
1923
  subscriptions: this.graphqlSubscriptionManager?.getSubscriptionCount() || 0,
1957
1924
  };
1958
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
+ }
1959
2548
  }
1960
2549
  // Export convenience function
1961
2550
  export function createApp(options) {