@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
@@ -0,0 +1,803 @@
1
+ // HTTP/2 Server Implementation for Moro Framework
2
+ import { createSecureServer as createHttp2SecureServer, createServer as createHttp2Server, } from 'http2';
3
+ import * as zlib from 'zlib';
4
+ import { promisify } from 'util';
5
+ import { createFrameworkLogger } from '../logger/index.js';
6
+ import { PathMatcher } from '../routing/path-matcher.js';
7
+ import { ObjectPoolManager } from '../pooling/object-pool-manager.js';
8
+ const gzip = promisify(zlib.gzip);
9
+ const deflate = promisify(zlib.deflate);
10
+ export class MoroHttp2Server {
11
+ server;
12
+ routes = [];
13
+ globalMiddleware = [];
14
+ compressionEnabled = true;
15
+ compressionThreshold = 1024;
16
+ requestTrackingEnabled = true;
17
+ logger = createFrameworkLogger('Http2Server');
18
+ hookManager;
19
+ requestCounter = 0;
20
+ isSecure;
21
+ // Use shared object pool manager
22
+ poolManager = ObjectPoolManager.getInstance();
23
+ // Interned method strings for fast comparison
24
+ static METHOD_POST = 'POST';
25
+ static METHOD_PUT = 'PUT';
26
+ static METHOD_PATCH = 'PATCH';
27
+ static METHOD_GET = 'GET';
28
+ static METHOD_DELETE = 'DELETE';
29
+ static METHOD_HEAD = 'HEAD';
30
+ static METHOD_OPTIONS = 'OPTIONS';
31
+ // Pre-compiled response templates
32
+ static RESPONSE_TEMPLATES = {
33
+ notFound: Buffer.from('{"success":false,"error":"Not found"}'),
34
+ unauthorized: Buffer.from('{"success":false,"error":"Unauthorized"}'),
35
+ forbidden: Buffer.from('{"success":false,"error":"Forbidden"}'),
36
+ internalError: Buffer.from('{"success":false,"error":"Internal server error"}'),
37
+ methodNotAllowed: Buffer.from('{"success":false,"error":"Method not allowed"}'),
38
+ rateLimited: Buffer.from('{"success":false,"error":"Rate limit exceeded"}'),
39
+ };
40
+ // Route optimization structures
41
+ routeCache = new Map();
42
+ staticRoutes = new Map();
43
+ dynamicRoutes = [];
44
+ routesBySegmentCount = new Map();
45
+ pathNormalizationCache = new Map();
46
+ constructor(options = {}) {
47
+ this.isSecure = !!(options.key && options.cert);
48
+ const serverOptions = {
49
+ allowHTTP1: options.allowHTTP1 !== false,
50
+ };
51
+ // Add SSL options if secure
52
+ if (this.isSecure) {
53
+ serverOptions.key = options.key;
54
+ serverOptions.cert = options.cert;
55
+ if (options.ca) {
56
+ serverOptions.ca = options.ca;
57
+ }
58
+ }
59
+ // Add HTTP/2 settings
60
+ if (options.settings) {
61
+ serverOptions.settings = {
62
+ headerTableSize: options.settings.headerTableSize,
63
+ enablePush: options.settings.enablePush !== false,
64
+ initialWindowSize: options.settings.initialWindowSize || 65535,
65
+ maxFrameSize: options.settings.maxFrameSize || 16384,
66
+ maxConcurrentStreams: options.settings.maxConcurrentStreams || 100,
67
+ maxHeaderListSize: options.settings.maxHeaderListSize,
68
+ maxHeaderSize: options.settings.maxHeaderSize,
69
+ enableConnectProtocol: options.settings.enableConnectProtocol,
70
+ };
71
+ }
72
+ else {
73
+ serverOptions.settings = {
74
+ enablePush: true,
75
+ initialWindowSize: 65535,
76
+ maxFrameSize: 16384,
77
+ maxConcurrentStreams: 100,
78
+ };
79
+ }
80
+ // Create server
81
+ if (this.isSecure) {
82
+ this.server = createHttp2SecureServer(serverOptions);
83
+ this.logger.info('HTTP/2 secure server created', 'ServerInit');
84
+ }
85
+ else {
86
+ this.server = createHttp2Server(serverOptions);
87
+ this.logger.info('HTTP/2 server created', 'ServerInit');
88
+ }
89
+ // Configure server settings
90
+ this.server.setTimeout(30000);
91
+ // Handle streams (HTTP/2 requests)
92
+ this.server.on('stream', this.handleStream.bind(this));
93
+ // Handle session events
94
+ this.server.on('session', session => {
95
+ this.logger.debug('HTTP/2 session created', 'Session');
96
+ session.on('error', err => {
97
+ this.logger.error('HTTP/2 session error', 'Session', { error: err.message });
98
+ });
99
+ });
100
+ // Handle server errors
101
+ this.server.on('error', err => {
102
+ this.logger.error('HTTP/2 server error', 'ServerError', { error: err.message });
103
+ });
104
+ }
105
+ // Configure server for maximum performance
106
+ configurePerformance(config = {}) {
107
+ if (config.compression !== undefined) {
108
+ this.compressionEnabled = config.compression.enabled;
109
+ if (config.compression.threshold !== undefined) {
110
+ this.compressionThreshold = config.compression.threshold;
111
+ }
112
+ }
113
+ if (config.minimal) {
114
+ this.compressionEnabled = false;
115
+ this.compressionThreshold = Infinity;
116
+ }
117
+ }
118
+ // Configure request tracking
119
+ setRequestTracking(enabled) {
120
+ this.requestTrackingEnabled = enabled;
121
+ }
122
+ // Middleware management
123
+ use(middleware) {
124
+ this.globalMiddleware.push(middleware);
125
+ }
126
+ // Set hooks manager
127
+ setHookManager(hookManager) {
128
+ this.hookManager = hookManager;
129
+ }
130
+ // Routing methods
131
+ get(path, ...handlers) {
132
+ this.addRoute('GET', path, handlers);
133
+ }
134
+ post(path, ...handlers) {
135
+ this.addRoute('POST', path, handlers);
136
+ }
137
+ put(path, ...handlers) {
138
+ this.addRoute('PUT', path, handlers);
139
+ }
140
+ delete(path, ...handlers) {
141
+ this.addRoute('DELETE', path, handlers);
142
+ }
143
+ patch(path, ...handlers) {
144
+ this.addRoute('PATCH', path, handlers);
145
+ }
146
+ addRoute(method, path, handlers) {
147
+ const { pattern, paramNames } = this.pathToRegex(path);
148
+ const handler = handlers.pop();
149
+ const middleware = handlers;
150
+ const route = {
151
+ method,
152
+ path,
153
+ pattern,
154
+ paramNames,
155
+ handler,
156
+ middleware,
157
+ };
158
+ this.routes.push(route);
159
+ // Organize routes for optimal lookup
160
+ if (paramNames.length === 0) {
161
+ const staticKey = `${method}:${path}`;
162
+ this.staticRoutes.set(staticKey, route);
163
+ }
164
+ else {
165
+ this.dynamicRoutes.push(route);
166
+ const segmentCount = PathMatcher.countSegments(path);
167
+ if (!this.routesBySegmentCount.has(segmentCount)) {
168
+ this.routesBySegmentCount.set(segmentCount, []);
169
+ }
170
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
171
+ this.routesBySegmentCount.get(segmentCount).push(route);
172
+ }
173
+ }
174
+ pathToRegex(path) {
175
+ const compiled = PathMatcher.compile(path);
176
+ return {
177
+ pattern: compiled.pattern || new RegExp(`^${path.replace(/\//g, '\\/')}$`),
178
+ paramNames: compiled.paramNames,
179
+ };
180
+ }
181
+ async handleStream(stream, headers) {
182
+ this.requestCounter++;
183
+ const httpReq = this.createRequestFromStream(stream, headers);
184
+ const httpRes = this.createResponseFromStream(stream, httpReq);
185
+ try {
186
+ // Parse URL and query
187
+ const url = headers[':path'] || '/';
188
+ const queryIndex = url.indexOf('?');
189
+ if (queryIndex === -1) {
190
+ httpReq.path = url;
191
+ httpReq.query = {};
192
+ }
193
+ else {
194
+ httpReq.path = url.substring(0, queryIndex);
195
+ httpReq.query = this.parseQueryString(url.substring(queryIndex + 1));
196
+ }
197
+ // Parse body for POST/PUT/PATCH
198
+ const method = httpReq.method;
199
+ if (method === MoroHttp2Server.METHOD_POST ||
200
+ method === MoroHttp2Server.METHOD_PUT ||
201
+ method === MoroHttp2Server.METHOD_PATCH) {
202
+ httpReq.body = await this.parseBody(stream, headers);
203
+ }
204
+ // Execute hooks
205
+ if (this.hookManager) {
206
+ await this.hookManager.execute('request', {
207
+ request: httpReq,
208
+ response: httpRes,
209
+ });
210
+ }
211
+ // Execute global middleware
212
+ if (this.globalMiddleware.length > 0) {
213
+ await this.executeMiddleware(this.globalMiddleware, httpReq, httpRes);
214
+ }
215
+ // If middleware handled the request, don't continue
216
+ if (httpRes.headersSent) {
217
+ return;
218
+ }
219
+ // Find matching route (path is always set after URL parsing)
220
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
221
+ const route = this.findRoute(method || MoroHttp2Server.METHOD_GET, httpReq.path);
222
+ if (!route) {
223
+ httpRes.statusCode = 404;
224
+ httpRes.setHeader('Content-Type', 'application/json; charset=utf-8');
225
+ httpRes.setHeader('Content-Length', MoroHttp2Server.RESPONSE_TEMPLATES.notFound.length);
226
+ httpRes.end(MoroHttp2Server.RESPONSE_TEMPLATES.notFound);
227
+ return;
228
+ }
229
+ // Extract path parameters
230
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
231
+ const matches = httpReq.path.match(route.pattern);
232
+ if (matches) {
233
+ httpReq.params = this.poolManager.acquireParams();
234
+ const paramNames = route.paramNames;
235
+ for (let i = 0; i < paramNames.length; i++) {
236
+ httpReq.params[paramNames[i]] = matches[i + 1];
237
+ }
238
+ }
239
+ // Execute route middleware
240
+ if (route.middleware.length > 0) {
241
+ await this.executeMiddleware(route.middleware, httpReq, httpRes);
242
+ }
243
+ // Execute handler
244
+ const handlerResult = route.handler(httpReq, httpRes);
245
+ if (handlerResult && typeof handlerResult.then === 'function') {
246
+ await handlerResult;
247
+ }
248
+ }
249
+ catch (error) {
250
+ this.logger.error('HTTP/2 stream error', 'StreamError', {
251
+ error: error instanceof Error ? error.message : String(error),
252
+ requestId: httpReq.requestId,
253
+ path: httpReq.path,
254
+ });
255
+ if (!httpRes.headersSent) {
256
+ httpRes.status(500).json({
257
+ success: false,
258
+ error: 'Internal server error',
259
+ requestId: httpReq.requestId,
260
+ });
261
+ }
262
+ }
263
+ finally {
264
+ // Release pooled objects
265
+ if (httpReq.params && Object.keys(httpReq.params).length === 0) {
266
+ this.poolManager.releaseParams(httpReq.params);
267
+ }
268
+ if (httpReq.query && Object.keys(httpReq.query).length === 0) {
269
+ this.poolManager.releaseQuery(httpReq.query);
270
+ }
271
+ }
272
+ }
273
+ createRequestFromStream(stream, headers) {
274
+ // Extract method from pseudo-header
275
+ const methodRaw = (headers[':method'] || 'GET').toUpperCase();
276
+ // Intern method string for fast comparison
277
+ let method;
278
+ switch (methodRaw) {
279
+ case 'POST':
280
+ method = MoroHttp2Server.METHOD_POST;
281
+ break;
282
+ case 'PUT':
283
+ method = MoroHttp2Server.METHOD_PUT;
284
+ break;
285
+ case 'PATCH':
286
+ method = MoroHttp2Server.METHOD_PATCH;
287
+ break;
288
+ case 'GET':
289
+ method = MoroHttp2Server.METHOD_GET;
290
+ break;
291
+ case 'DELETE':
292
+ method = MoroHttp2Server.METHOD_DELETE;
293
+ break;
294
+ case 'HEAD':
295
+ method = MoroHttp2Server.METHOD_HEAD;
296
+ break;
297
+ case 'OPTIONS':
298
+ method = MoroHttp2Server.METHOD_OPTIONS;
299
+ break;
300
+ default:
301
+ method = methodRaw;
302
+ }
303
+ // Convert HTTP/2 headers to standard headers (remove pseudo-headers)
304
+ const standardHeaders = {};
305
+ for (const [key, value] of Object.entries(headers)) {
306
+ if (!key.startsWith(':')) {
307
+ standardHeaders[key] = Array.isArray(value) ? value.join(', ') : value;
308
+ }
309
+ }
310
+ // Parse cookies
311
+ const cookieHeader = standardHeaders['cookie'];
312
+ const cookies = {};
313
+ if (cookieHeader) {
314
+ const cookieParts = cookieHeader.split(';');
315
+ for (const cookie of cookieParts) {
316
+ const equalIndex = cookie.indexOf('=');
317
+ if (equalIndex > 0) {
318
+ const name = cookie.substring(0, equalIndex).trim();
319
+ const value = cookie.substring(equalIndex + 1);
320
+ if (name && value) {
321
+ cookies[name] = decodeURIComponent(value);
322
+ }
323
+ }
324
+ }
325
+ }
326
+ const httpReq = {
327
+ method,
328
+ path: '',
329
+ url: headers[':path'] || '/',
330
+ query: {},
331
+ params: {},
332
+ headers: standardHeaders,
333
+ body: null,
334
+ cookies,
335
+ ip: stream.session?.socket?.remoteAddress || '',
336
+ requestId: this.requestTrackingEnabled ? this.poolManager.generateRequestId() : '',
337
+ httpVersion: '2.0',
338
+ };
339
+ // Store stream reference for push capability
340
+ httpReq._http2Stream = stream;
341
+ httpReq._http2Headers = headers;
342
+ return httpReq;
343
+ }
344
+ createResponseFromStream(stream, req) {
345
+ const httpRes = {
346
+ statusCode: 200,
347
+ headersSent: false,
348
+ _headers: {},
349
+ _stream: stream,
350
+ _req: req,
351
+ _logger: this.logger,
352
+ _poolManager: this.poolManager,
353
+ _compressionEnabled: this.compressionEnabled,
354
+ _compressionThreshold: this.compressionThreshold,
355
+ };
356
+ // Status method
357
+ httpRes.status = (code) => {
358
+ httpRes.statusCode = code;
359
+ return httpRes;
360
+ };
361
+ // Set header
362
+ httpRes.setHeader = (name, value) => {
363
+ httpRes._headers[name.toLowerCase()] = value;
364
+ return httpRes;
365
+ };
366
+ // Get header
367
+ httpRes.getHeader = (name) => {
368
+ return httpRes._headers[name.toLowerCase()];
369
+ };
370
+ // Remove header
371
+ httpRes.removeHeader = (name) => {
372
+ delete httpRes._headers[name.toLowerCase()];
373
+ return httpRes;
374
+ };
375
+ // Has header
376
+ httpRes.hasHeader = (name) => {
377
+ return httpRes._headers[name.toLowerCase()] !== undefined;
378
+ };
379
+ // Get headers
380
+ httpRes.getHeaders = () => {
381
+ return { ...httpRes._headers };
382
+ };
383
+ // JSON response
384
+ httpRes.json = async (data) => {
385
+ if (httpRes.headersSent || stream.destroyed)
386
+ return;
387
+ const jsonString = JSON.stringify(data);
388
+ const finalBuffer = Buffer.from(jsonString, 'utf8');
389
+ httpRes._headers['content-type'] = 'application/json; charset=utf-8';
390
+ // Compression
391
+ if (httpRes._compressionEnabled && finalBuffer.length > httpRes._compressionThreshold) {
392
+ const acceptEncoding = req.headers['accept-encoding'];
393
+ if (acceptEncoding && acceptEncoding.includes('gzip')) {
394
+ const compressed = await gzip(finalBuffer);
395
+ httpRes._headers['content-encoding'] = 'gzip';
396
+ httpRes._headers['content-length'] = compressed.length;
397
+ stream.respond({
398
+ ':status': httpRes.statusCode,
399
+ ...httpRes._headers,
400
+ });
401
+ stream.end(compressed);
402
+ httpRes.headersSent = true;
403
+ return;
404
+ }
405
+ else if (acceptEncoding && acceptEncoding.includes('deflate')) {
406
+ const compressed = await deflate(finalBuffer);
407
+ httpRes._headers['content-encoding'] = 'deflate';
408
+ httpRes._headers['content-length'] = compressed.length;
409
+ stream.respond({
410
+ ':status': httpRes.statusCode,
411
+ ...httpRes._headers,
412
+ });
413
+ stream.end(compressed);
414
+ httpRes.headersSent = true;
415
+ return;
416
+ }
417
+ }
418
+ httpRes._headers['content-length'] = finalBuffer.length;
419
+ stream.respond({
420
+ ':status': httpRes.statusCode,
421
+ ...httpRes._headers,
422
+ });
423
+ stream.end(finalBuffer);
424
+ httpRes.headersSent = true;
425
+ };
426
+ // Send response
427
+ httpRes.send = (data) => {
428
+ if (httpRes.headersSent || stream.destroyed)
429
+ return;
430
+ if (!httpRes._headers['content-type']) {
431
+ if (typeof data === 'string') {
432
+ try {
433
+ JSON.parse(data);
434
+ httpRes._headers['content-type'] = 'application/json; charset=utf-8';
435
+ }
436
+ catch {
437
+ httpRes._headers['content-type'] = 'text/plain; charset=utf-8';
438
+ }
439
+ }
440
+ else {
441
+ httpRes._headers['content-type'] = 'application/octet-stream';
442
+ }
443
+ }
444
+ const buffer = typeof data === 'string' ? Buffer.from(data) : data;
445
+ httpRes._headers['content-length'] = buffer.length;
446
+ stream.respond({
447
+ ':status': httpRes.statusCode,
448
+ ...httpRes._headers,
449
+ });
450
+ stream.end(buffer);
451
+ httpRes.headersSent = true;
452
+ };
453
+ // End response
454
+ httpRes.end = (data) => {
455
+ if (httpRes.headersSent || stream.destroyed)
456
+ return httpRes;
457
+ stream.respond({
458
+ ':status': httpRes.statusCode,
459
+ ...httpRes._headers,
460
+ });
461
+ stream.end(data || '');
462
+ httpRes.headersSent = true;
463
+ return httpRes;
464
+ };
465
+ // Cookie handling
466
+ httpRes.cookie = (name, value, options = {}) => {
467
+ if (httpRes.headersSent) {
468
+ const isCritical = options.critical || name.includes('session') || name.includes('auth');
469
+ const message = `Cookie '${name}' could not be set - headers already sent`;
470
+ if (isCritical || options.throwOnLateSet) {
471
+ throw new Error(`${message}. This may cause authentication or security issues.`);
472
+ }
473
+ else {
474
+ httpRes._logger.warn(message, 'CookieWarning', { cookieName: name });
475
+ }
476
+ return httpRes;
477
+ }
478
+ const cookieValue = encodeURIComponent(value);
479
+ let cookieString = `${name}=${cookieValue}`;
480
+ if (options.maxAge)
481
+ cookieString += `; Max-Age=${options.maxAge}`;
482
+ if (options.expires)
483
+ cookieString += `; Expires=${options.expires.toUTCString()}`;
484
+ if (options.httpOnly)
485
+ cookieString += '; HttpOnly';
486
+ if (options.secure)
487
+ cookieString += '; Secure';
488
+ if (options.sameSite)
489
+ cookieString += `; SameSite=${options.sameSite}`;
490
+ if (options.domain)
491
+ cookieString += `; Domain=${options.domain}`;
492
+ if (options.path)
493
+ cookieString += `; Path=${options.path}`;
494
+ const existingCookies = httpRes._headers['set-cookie'] || [];
495
+ const cookies = Array.isArray(existingCookies)
496
+ ? existingCookies
497
+ : [existingCookies];
498
+ cookies.push(cookieString);
499
+ httpRes._headers['set-cookie'] = cookies;
500
+ return httpRes;
501
+ };
502
+ // Clear cookie
503
+ httpRes.clearCookie = (name, options = {}) => {
504
+ return httpRes.cookie(name, '', {
505
+ expires: new Date(0),
506
+ maxAge: 0,
507
+ ...options,
508
+ });
509
+ };
510
+ // Redirect
511
+ httpRes.redirect = (url, status = 302) => {
512
+ if (httpRes.headersSent || stream.destroyed)
513
+ return;
514
+ httpRes.statusCode = status;
515
+ httpRes._headers['location'] = url;
516
+ stream.respond({
517
+ ':status': status,
518
+ ...httpRes._headers,
519
+ });
520
+ stream.end();
521
+ httpRes.headersSent = true;
522
+ };
523
+ // HTTP/2 Server Push
524
+ httpRes.push = (path, options = {}) => {
525
+ if (httpRes.headersSent || stream.destroyed || !stream.pushAllowed) {
526
+ return null;
527
+ }
528
+ try {
529
+ const pushHeaders = {
530
+ ':path': path,
531
+ ':method': 'GET',
532
+ ...options.headers,
533
+ };
534
+ const pushStream = stream.pushStream(pushHeaders, err => {
535
+ if (err) {
536
+ httpRes._logger.debug('Server push failed', 'ServerPush', {
537
+ path,
538
+ error: err.message,
539
+ });
540
+ }
541
+ });
542
+ // Set stream priority if specified
543
+ if (options.priority !== undefined && pushStream) {
544
+ try {
545
+ // Priority weight: 1-256 (default 16)
546
+ // Higher values = higher priority
547
+ const weight = Math.max(1, Math.min(256, options.priority));
548
+ pushStream.priority({
549
+ parent: 0,
550
+ weight,
551
+ exclusive: false,
552
+ });
553
+ }
554
+ catch (error) {
555
+ httpRes._logger.debug('Failed to set stream priority', 'StreamPriority', {
556
+ error: error instanceof Error ? error.message : String(error),
557
+ });
558
+ }
559
+ }
560
+ return pushStream;
561
+ }
562
+ catch (error) {
563
+ httpRes._logger.debug('Server push error', 'ServerPush', {
564
+ path,
565
+ error: error instanceof Error ? error.message : String(error),
566
+ });
567
+ return null;
568
+ }
569
+ };
570
+ // Set stream priority for current response
571
+ httpRes.setPriority = (options = {}) => {
572
+ if (httpRes.headersSent || stream.destroyed) {
573
+ return httpRes;
574
+ }
575
+ try {
576
+ stream.priority({
577
+ parent: options.parent || 0,
578
+ weight: options.weight ? Math.max(1, Math.min(256, options.weight)) : 16,
579
+ exclusive: options.exclusive || false,
580
+ });
581
+ }
582
+ catch (error) {
583
+ httpRes._logger.debug('Failed to set stream priority', 'StreamPriority', {
584
+ error: error instanceof Error ? error.message : String(error),
585
+ });
586
+ }
587
+ return httpRes;
588
+ };
589
+ // Set bulk headers
590
+ httpRes.setBulkHeaders = (headers) => {
591
+ if (httpRes.headersSent) {
592
+ httpRes._logger.warn('Cannot set headers - headers already sent', 'HeaderWarning');
593
+ return httpRes;
594
+ }
595
+ for (const key in headers) {
596
+ httpRes._headers[key.toLowerCase()] = String(headers[key]);
597
+ }
598
+ return httpRes;
599
+ };
600
+ // Response state
601
+ httpRes.canSetHeaders = () => {
602
+ return !httpRes.headersSent;
603
+ };
604
+ httpRes.getResponseState = () => {
605
+ return {
606
+ headersSent: httpRes.headersSent,
607
+ statusCode: httpRes.statusCode,
608
+ headers: httpRes.getHeaders(),
609
+ finished: stream.destroyed,
610
+ writable: !stream.destroyed,
611
+ };
612
+ };
613
+ return httpRes;
614
+ }
615
+ async parseBody(stream, headers) {
616
+ const contentType = headers['content-type'] || '';
617
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
618
+ const contentLength = parseInt(headers['content-length'] || '0');
619
+ const maxSize = 10 * 1024 * 1024; // 10MB limit
620
+ return new Promise((resolve, reject) => {
621
+ const chunks = [];
622
+ let totalLength = 0;
623
+ stream.on('data', (chunk) => {
624
+ totalLength += chunk.length;
625
+ if (totalLength > maxSize) {
626
+ reject(new Error('Request body too large'));
627
+ return;
628
+ }
629
+ chunks.push(chunk);
630
+ });
631
+ stream.on('end', () => {
632
+ try {
633
+ const body = Buffer.concat(chunks);
634
+ if (contentType.includes('application/json')) {
635
+ resolve(JSON.parse(body.toString()));
636
+ }
637
+ else if (contentType.includes('application/x-www-form-urlencoded')) {
638
+ resolve(this.parseUrlEncoded(body.toString()));
639
+ }
640
+ else {
641
+ resolve(body.toString());
642
+ }
643
+ }
644
+ catch (error) {
645
+ reject(error);
646
+ }
647
+ });
648
+ stream.on('error', reject);
649
+ });
650
+ }
651
+ parseUrlEncoded(body) {
652
+ const params = new URLSearchParams(body);
653
+ const result = {};
654
+ for (const [key, value] of params) {
655
+ result[key] = value;
656
+ }
657
+ return result;
658
+ }
659
+ parseQueryString(queryString) {
660
+ if (!queryString)
661
+ return {};
662
+ const result = this.poolManager.acquireQuery();
663
+ const pairs = queryString.split('&');
664
+ for (const pair of pairs) {
665
+ const equalIndex = pair.indexOf('=');
666
+ if (equalIndex === -1) {
667
+ result[decodeURIComponent(pair)] = '';
668
+ }
669
+ else {
670
+ const key = decodeURIComponent(pair.substring(0, equalIndex));
671
+ const value = decodeURIComponent(pair.substring(equalIndex + 1));
672
+ result[key] = value;
673
+ }
674
+ }
675
+ return result;
676
+ }
677
+ normalizePath(path) {
678
+ if (this.pathNormalizationCache.has(path)) {
679
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
680
+ return this.pathNormalizationCache.get(path);
681
+ }
682
+ let normalized = path;
683
+ if (normalized.length > 1 && normalized.endsWith('/')) {
684
+ normalized = normalized.slice(0, -1);
685
+ }
686
+ if (this.pathNormalizationCache.size < 200) {
687
+ this.pathNormalizationCache.set(path, normalized);
688
+ }
689
+ return normalized;
690
+ }
691
+ findRoute(method, path) {
692
+ // Default to '/' if path is undefined
693
+ const searchPath = path || '/';
694
+ const cacheKey = `${method}:${searchPath}`;
695
+ if (this.routeCache.has(cacheKey)) {
696
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
697
+ return this.routeCache.get(cacheKey);
698
+ }
699
+ const normalizedPath = this.normalizePath(searchPath);
700
+ const normalizedCacheKey = normalizedPath !== searchPath ? `${method}:${normalizedPath}` : cacheKey;
701
+ if (normalizedPath !== path && this.routeCache.has(normalizedCacheKey)) {
702
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
703
+ return this.routeCache.get(normalizedCacheKey);
704
+ }
705
+ const staticRoute = this.staticRoutes.get(normalizedCacheKey);
706
+ if (staticRoute) {
707
+ this.routeCache.set(normalizedCacheKey, staticRoute);
708
+ if (normalizedPath !== path) {
709
+ this.routeCache.set(cacheKey, staticRoute);
710
+ }
711
+ return staticRoute;
712
+ }
713
+ let route = null;
714
+ if (this.dynamicRoutes.length > 0) {
715
+ const segmentCount = PathMatcher.countSegments(normalizedPath);
716
+ const candidateRoutes = this.routesBySegmentCount.get(segmentCount) || this.dynamicRoutes;
717
+ for (const candidateRoute of candidateRoutes) {
718
+ if (candidateRoute.method === method && candidateRoute.pattern.test(normalizedPath)) {
719
+ route = candidateRoute;
720
+ break;
721
+ }
722
+ }
723
+ }
724
+ if (this.routeCache.size < 500) {
725
+ this.routeCache.set(normalizedCacheKey, route);
726
+ if (normalizedPath !== path) {
727
+ this.routeCache.set(cacheKey, route);
728
+ }
729
+ }
730
+ return route;
731
+ }
732
+ async executeMiddleware(middleware, req, res) {
733
+ for (const mw of middleware) {
734
+ if (res.headersSent)
735
+ return;
736
+ await new Promise((resolve, reject) => {
737
+ let resolved = false;
738
+ const next = () => {
739
+ if (resolved)
740
+ return;
741
+ resolved = true;
742
+ resolve();
743
+ };
744
+ try {
745
+ const result = mw(req, res, next);
746
+ if (result && typeof result.then === 'function') {
747
+ result
748
+ .then(() => {
749
+ if (!resolved)
750
+ next();
751
+ })
752
+ .catch(reject);
753
+ }
754
+ else if (!resolved) {
755
+ next();
756
+ }
757
+ }
758
+ catch (error) {
759
+ if (!resolved) {
760
+ resolved = true;
761
+ reject(error);
762
+ }
763
+ }
764
+ });
765
+ }
766
+ }
767
+ listen(port, host, callback) {
768
+ if (typeof host === 'function') {
769
+ callback = host;
770
+ host = undefined;
771
+ }
772
+ if (host) {
773
+ this.server.listen(port, host, callback);
774
+ }
775
+ else {
776
+ this.server.listen(port, callback);
777
+ }
778
+ }
779
+ close() {
780
+ return new Promise(resolve => {
781
+ this.server.close(() => resolve());
782
+ });
783
+ }
784
+ forceCleanup() {
785
+ this.poolManager.clearAll();
786
+ if (globalThis?.gc) {
787
+ globalThis.gc();
788
+ }
789
+ }
790
+ getServer() {
791
+ return this.server;
792
+ }
793
+ getPerformanceStats() {
794
+ const poolStats = this.poolManager.getStats();
795
+ return {
796
+ paramObjectPoolSize: poolStats.paramPool.poolSize,
797
+ queryObjectPoolSize: poolStats.queryPool.poolSize,
798
+ headerObjectPoolSize: poolStats.headerPool.poolSize,
799
+ poolManager: poolStats,
800
+ };
801
+ }
802
+ }
803
+ //# sourceMappingURL=http2-server.js.map