@morojs/moro 1.0.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 (345) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +233 -0
  3. package/dist/core/config/index.d.ts +19 -0
  4. package/dist/core/config/index.js +59 -0
  5. package/dist/core/config/index.js.map +1 -0
  6. package/dist/core/config/loader.d.ts +6 -0
  7. package/dist/core/config/loader.js +288 -0
  8. package/dist/core/config/loader.js.map +1 -0
  9. package/dist/core/config/schema.d.ts +335 -0
  10. package/dist/core/config/schema.js +286 -0
  11. package/dist/core/config/schema.js.map +1 -0
  12. package/dist/core/config/utils.d.ts +50 -0
  13. package/dist/core/config/utils.js +185 -0
  14. package/dist/core/config/utils.js.map +1 -0
  15. package/dist/core/database/adapters/drizzle.d.ts +29 -0
  16. package/dist/core/database/adapters/drizzle.js +366 -0
  17. package/dist/core/database/adapters/drizzle.js.map +1 -0
  18. package/dist/core/database/adapters/index.d.ts +8 -0
  19. package/dist/core/database/adapters/index.js +48 -0
  20. package/dist/core/database/adapters/index.js.map +1 -0
  21. package/dist/core/database/adapters/mongodb.d.ts +35 -0
  22. package/dist/core/database/adapters/mongodb.js +215 -0
  23. package/dist/core/database/adapters/mongodb.js.map +1 -0
  24. package/dist/core/database/adapters/mysql.d.ts +23 -0
  25. package/dist/core/database/adapters/mysql.js +149 -0
  26. package/dist/core/database/adapters/mysql.js.map +1 -0
  27. package/dist/core/database/adapters/postgresql.d.ts +24 -0
  28. package/dist/core/database/adapters/postgresql.js +160 -0
  29. package/dist/core/database/adapters/postgresql.js.map +1 -0
  30. package/dist/core/database/adapters/redis.d.ts +50 -0
  31. package/dist/core/database/adapters/redis.js +266 -0
  32. package/dist/core/database/adapters/redis.js.map +1 -0
  33. package/dist/core/database/adapters/sqlite.d.ts +23 -0
  34. package/dist/core/database/adapters/sqlite.js +194 -0
  35. package/dist/core/database/adapters/sqlite.js.map +1 -0
  36. package/dist/core/database/index.d.ts +2 -0
  37. package/dist/core/database/index.js +20 -0
  38. package/dist/core/database/index.js.map +1 -0
  39. package/dist/core/docs/index.d.ts +63 -0
  40. package/dist/core/docs/index.js +170 -0
  41. package/dist/core/docs/index.js.map +1 -0
  42. package/dist/core/docs/openapi-generator.d.ts +124 -0
  43. package/dist/core/docs/openapi-generator.js +413 -0
  44. package/dist/core/docs/openapi-generator.js.map +1 -0
  45. package/dist/core/docs/simple-docs.d.ts +21 -0
  46. package/dist/core/docs/simple-docs.js +268 -0
  47. package/dist/core/docs/simple-docs.js.map +1 -0
  48. package/dist/core/docs/swagger-ui.d.ts +28 -0
  49. package/dist/core/docs/swagger-ui.js +317 -0
  50. package/dist/core/docs/swagger-ui.js.map +1 -0
  51. package/dist/core/docs/zod-to-openapi.d.ts +29 -0
  52. package/dist/core/docs/zod-to-openapi.js +414 -0
  53. package/dist/core/docs/zod-to-openapi.js.map +1 -0
  54. package/dist/core/events/event-bus.d.ts +27 -0
  55. package/dist/core/events/event-bus.js +193 -0
  56. package/dist/core/events/event-bus.js.map +1 -0
  57. package/dist/core/events/index.d.ts +2 -0
  58. package/dist/core/events/index.js +7 -0
  59. package/dist/core/events/index.js.map +1 -0
  60. package/dist/core/framework.d.ts +57 -0
  61. package/dist/core/framework.js +432 -0
  62. package/dist/core/framework.js.map +1 -0
  63. package/dist/core/http/http-server.d.ts +114 -0
  64. package/dist/core/http/http-server.js +1154 -0
  65. package/dist/core/http/http-server.js.map +1 -0
  66. package/dist/core/http/index.d.ts +3 -0
  67. package/dist/core/http/index.js +10 -0
  68. package/dist/core/http/index.js.map +1 -0
  69. package/dist/core/http/router.d.ts +14 -0
  70. package/dist/core/http/router.js +113 -0
  71. package/dist/core/http/router.js.map +1 -0
  72. package/dist/core/logger/filters.d.ts +9 -0
  73. package/dist/core/logger/filters.js +134 -0
  74. package/dist/core/logger/filters.js.map +1 -0
  75. package/dist/core/logger/index.d.ts +3 -0
  76. package/dist/core/logger/index.js +26 -0
  77. package/dist/core/logger/index.js.map +1 -0
  78. package/dist/core/logger/logger.d.ts +49 -0
  79. package/dist/core/logger/logger.js +332 -0
  80. package/dist/core/logger/logger.js.map +1 -0
  81. package/dist/core/logger/outputs.d.ts +42 -0
  82. package/dist/core/logger/outputs.js +110 -0
  83. package/dist/core/logger/outputs.js.map +1 -0
  84. package/dist/core/middleware/built-in/adapters/cache/file.d.ts +15 -0
  85. package/dist/core/middleware/built-in/adapters/cache/file.js +128 -0
  86. package/dist/core/middleware/built-in/adapters/cache/file.js.map +1 -0
  87. package/dist/core/middleware/built-in/adapters/cache/index.d.ts +5 -0
  88. package/dist/core/middleware/built-in/adapters/cache/index.js +28 -0
  89. package/dist/core/middleware/built-in/adapters/cache/index.js.map +1 -0
  90. package/dist/core/middleware/built-in/adapters/cache/memory.d.ts +11 -0
  91. package/dist/core/middleware/built-in/adapters/cache/memory.js +65 -0
  92. package/dist/core/middleware/built-in/adapters/cache/memory.js.map +1 -0
  93. package/dist/core/middleware/built-in/adapters/cache/redis.d.ts +17 -0
  94. package/dist/core/middleware/built-in/adapters/cache/redis.js +91 -0
  95. package/dist/core/middleware/built-in/adapters/cache/redis.js.map +1 -0
  96. package/dist/core/middleware/built-in/adapters/cdn/azure.d.ts +21 -0
  97. package/dist/core/middleware/built-in/adapters/cdn/azure.js +40 -0
  98. package/dist/core/middleware/built-in/adapters/cdn/azure.js.map +1 -0
  99. package/dist/core/middleware/built-in/adapters/cdn/cloudflare.d.ts +14 -0
  100. package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js +77 -0
  101. package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js.map +1 -0
  102. package/dist/core/middleware/built-in/adapters/cdn/cloudfront.d.ts +15 -0
  103. package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js +73 -0
  104. package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js.map +1 -0
  105. package/dist/core/middleware/built-in/adapters/cdn/index.d.ts +5 -0
  106. package/dist/core/middleware/built-in/adapters/cdn/index.js +28 -0
  107. package/dist/core/middleware/built-in/adapters/cdn/index.js.map +1 -0
  108. package/dist/core/middleware/built-in/adapters/index.d.ts +4 -0
  109. package/dist/core/middleware/built-in/adapters/index.js +26 -0
  110. package/dist/core/middleware/built-in/adapters/index.js.map +1 -0
  111. package/dist/core/middleware/built-in/auth.d.ts +2 -0
  112. package/dist/core/middleware/built-in/auth.js +38 -0
  113. package/dist/core/middleware/built-in/auth.js.map +1 -0
  114. package/dist/core/middleware/built-in/cache.d.ts +3 -0
  115. package/dist/core/middleware/built-in/cache.js +188 -0
  116. package/dist/core/middleware/built-in/cache.js.map +1 -0
  117. package/dist/core/middleware/built-in/cdn.d.ts +3 -0
  118. package/dist/core/middleware/built-in/cdn.js +115 -0
  119. package/dist/core/middleware/built-in/cdn.js.map +1 -0
  120. package/dist/core/middleware/built-in/cookie.d.ts +14 -0
  121. package/dist/core/middleware/built-in/cookie.js +68 -0
  122. package/dist/core/middleware/built-in/cookie.js.map +1 -0
  123. package/dist/core/middleware/built-in/cors.d.ts +2 -0
  124. package/dist/core/middleware/built-in/cors.js +29 -0
  125. package/dist/core/middleware/built-in/cors.js.map +1 -0
  126. package/dist/core/middleware/built-in/csp.d.ts +22 -0
  127. package/dist/core/middleware/built-in/csp.js +74 -0
  128. package/dist/core/middleware/built-in/csp.js.map +1 -0
  129. package/dist/core/middleware/built-in/csrf.d.ts +9 -0
  130. package/dist/core/middleware/built-in/csrf.js +66 -0
  131. package/dist/core/middleware/built-in/csrf.js.map +1 -0
  132. package/dist/core/middleware/built-in/error-tracker.d.ts +1 -0
  133. package/dist/core/middleware/built-in/error-tracker.js +19 -0
  134. package/dist/core/middleware/built-in/error-tracker.js.map +1 -0
  135. package/dist/core/middleware/built-in/index.d.ts +70 -0
  136. package/dist/core/middleware/built-in/index.js +70 -0
  137. package/dist/core/middleware/built-in/index.js.map +1 -0
  138. package/dist/core/middleware/built-in/performance-monitor.d.ts +1 -0
  139. package/dist/core/middleware/built-in/performance-monitor.js +22 -0
  140. package/dist/core/middleware/built-in/performance-monitor.js.map +1 -0
  141. package/dist/core/middleware/built-in/rate-limit.d.ts +6 -0
  142. package/dist/core/middleware/built-in/rate-limit.js +47 -0
  143. package/dist/core/middleware/built-in/rate-limit.js.map +1 -0
  144. package/dist/core/middleware/built-in/request-logger.d.ts +1 -0
  145. package/dist/core/middleware/built-in/request-logger.js +15 -0
  146. package/dist/core/middleware/built-in/request-logger.js.map +1 -0
  147. package/dist/core/middleware/built-in/session.d.ts +41 -0
  148. package/dist/core/middleware/built-in/session.js +209 -0
  149. package/dist/core/middleware/built-in/session.js.map +1 -0
  150. package/dist/core/middleware/built-in/sse.d.ts +6 -0
  151. package/dist/core/middleware/built-in/sse.js +73 -0
  152. package/dist/core/middleware/built-in/sse.js.map +1 -0
  153. package/dist/core/middleware/built-in/validation.d.ts +2 -0
  154. package/dist/core/middleware/built-in/validation.js +31 -0
  155. package/dist/core/middleware/built-in/validation.js.map +1 -0
  156. package/dist/core/middleware/index.d.ts +21 -0
  157. package/dist/core/middleware/index.js +152 -0
  158. package/dist/core/middleware/index.js.map +1 -0
  159. package/dist/core/modules/auto-discovery.d.ts +27 -0
  160. package/dist/core/modules/auto-discovery.js +255 -0
  161. package/dist/core/modules/auto-discovery.js.map +1 -0
  162. package/dist/core/modules/index.d.ts +2 -0
  163. package/dist/core/modules/index.js +11 -0
  164. package/dist/core/modules/index.js.map +1 -0
  165. package/dist/core/modules/modules.d.ts +10 -0
  166. package/dist/core/modules/modules.js +137 -0
  167. package/dist/core/modules/modules.js.map +1 -0
  168. package/dist/core/networking/index.d.ts +2 -0
  169. package/dist/core/networking/index.js +9 -0
  170. package/dist/core/networking/index.js.map +1 -0
  171. package/dist/core/networking/service-discovery.d.ts +38 -0
  172. package/dist/core/networking/service-discovery.js +233 -0
  173. package/dist/core/networking/service-discovery.js.map +1 -0
  174. package/dist/core/networking/websocket-manager.d.ts +27 -0
  175. package/dist/core/networking/websocket-manager.js +211 -0
  176. package/dist/core/networking/websocket-manager.js.map +1 -0
  177. package/dist/core/routing/app-integration.d.ts +42 -0
  178. package/dist/core/routing/app-integration.js +152 -0
  179. package/dist/core/routing/app-integration.js.map +1 -0
  180. package/dist/core/routing/index.d.ts +106 -0
  181. package/dist/core/routing/index.js +343 -0
  182. package/dist/core/routing/index.js.map +1 -0
  183. package/dist/core/runtime/aws-lambda-adapter.d.ts +43 -0
  184. package/dist/core/runtime/aws-lambda-adapter.js +108 -0
  185. package/dist/core/runtime/aws-lambda-adapter.js.map +1 -0
  186. package/dist/core/runtime/base-adapter.d.ts +16 -0
  187. package/dist/core/runtime/base-adapter.js +105 -0
  188. package/dist/core/runtime/base-adapter.js.map +1 -0
  189. package/dist/core/runtime/cloudflare-workers-adapter.d.ts +18 -0
  190. package/dist/core/runtime/cloudflare-workers-adapter.js +131 -0
  191. package/dist/core/runtime/cloudflare-workers-adapter.js.map +1 -0
  192. package/dist/core/runtime/index.d.ts +14 -0
  193. package/dist/core/runtime/index.js +56 -0
  194. package/dist/core/runtime/index.js.map +1 -0
  195. package/dist/core/runtime/node-adapter.d.ts +15 -0
  196. package/dist/core/runtime/node-adapter.js +204 -0
  197. package/dist/core/runtime/node-adapter.js.map +1 -0
  198. package/dist/core/runtime/vercel-edge-adapter.d.ts +10 -0
  199. package/dist/core/runtime/vercel-edge-adapter.js +106 -0
  200. package/dist/core/runtime/vercel-edge-adapter.js.map +1 -0
  201. package/dist/core/utilities/circuit-breaker.d.ts +14 -0
  202. package/dist/core/utilities/circuit-breaker.js +42 -0
  203. package/dist/core/utilities/circuit-breaker.js.map +1 -0
  204. package/dist/core/utilities/container.d.ts +116 -0
  205. package/dist/core/utilities/container.js +529 -0
  206. package/dist/core/utilities/container.js.map +1 -0
  207. package/dist/core/utilities/hooks.d.ts +24 -0
  208. package/dist/core/utilities/hooks.js +131 -0
  209. package/dist/core/utilities/hooks.js.map +1 -0
  210. package/dist/core/utilities/index.d.ts +4 -0
  211. package/dist/core/utilities/index.js +22 -0
  212. package/dist/core/utilities/index.js.map +1 -0
  213. package/dist/core/validation/index.d.ts +30 -0
  214. package/dist/core/validation/index.js +144 -0
  215. package/dist/core/validation/index.js.map +1 -0
  216. package/dist/index.d.ts +30 -0
  217. package/dist/index.js +72 -0
  218. package/dist/index.js.map +1 -0
  219. package/dist/moro.d.ts +82 -0
  220. package/dist/moro.js +679 -0
  221. package/dist/moro.js.map +1 -0
  222. package/dist/types/cache.d.ts +34 -0
  223. package/dist/types/cache.js +3 -0
  224. package/dist/types/cache.js.map +1 -0
  225. package/dist/types/cdn.d.ts +19 -0
  226. package/dist/types/cdn.js +3 -0
  227. package/dist/types/cdn.js.map +1 -0
  228. package/dist/types/core.d.ts +13 -0
  229. package/dist/types/core.js +3 -0
  230. package/dist/types/core.js.map +1 -0
  231. package/dist/types/database.d.ts +29 -0
  232. package/dist/types/database.js +3 -0
  233. package/dist/types/database.js.map +1 -0
  234. package/dist/types/discovery.d.ts +6 -0
  235. package/dist/types/discovery.js +3 -0
  236. package/dist/types/discovery.js.map +1 -0
  237. package/dist/types/events.d.ts +116 -0
  238. package/dist/types/events.js +3 -0
  239. package/dist/types/events.js.map +1 -0
  240. package/dist/types/hooks.d.ts +38 -0
  241. package/dist/types/hooks.js +3 -0
  242. package/dist/types/hooks.js.map +1 -0
  243. package/dist/types/http.d.ts +51 -0
  244. package/dist/types/http.js +3 -0
  245. package/dist/types/http.js.map +1 -0
  246. package/dist/types/logger.d.ts +77 -0
  247. package/dist/types/logger.js +3 -0
  248. package/dist/types/logger.js.map +1 -0
  249. package/dist/types/module.d.ts +91 -0
  250. package/dist/types/module.js +3 -0
  251. package/dist/types/module.js.map +1 -0
  252. package/dist/types/runtime.d.ts +48 -0
  253. package/dist/types/runtime.js +3 -0
  254. package/dist/types/runtime.js.map +1 -0
  255. package/dist/types/session.d.ts +66 -0
  256. package/dist/types/session.js +3 -0
  257. package/dist/types/session.js.map +1 -0
  258. package/package.json +176 -0
  259. package/src/core/config/index.ts +47 -0
  260. package/src/core/config/loader.ts +366 -0
  261. package/src/core/config/schema.ts +346 -0
  262. package/src/core/config/utils.ts +220 -0
  263. package/src/core/database/README.md +228 -0
  264. package/src/core/database/adapters/drizzle.ts +425 -0
  265. package/src/core/database/adapters/index.ts +45 -0
  266. package/src/core/database/adapters/mongodb.ts +292 -0
  267. package/src/core/database/adapters/mysql.ts +217 -0
  268. package/src/core/database/adapters/postgresql.ts +211 -0
  269. package/src/core/database/adapters/redis.ts +331 -0
  270. package/src/core/database/adapters/sqlite.ts +255 -0
  271. package/src/core/database/index.ts +3 -0
  272. package/src/core/docs/index.ts +245 -0
  273. package/src/core/docs/openapi-generator.ts +588 -0
  274. package/src/core/docs/simple-docs.ts +305 -0
  275. package/src/core/docs/swagger-ui.ts +370 -0
  276. package/src/core/docs/zod-to-openapi.ts +532 -0
  277. package/src/core/events/event-bus.ts +249 -0
  278. package/src/core/events/index.ts +12 -0
  279. package/src/core/framework.ts +621 -0
  280. package/src/core/http/http-server.ts +1421 -0
  281. package/src/core/http/index.ts +11 -0
  282. package/src/core/http/router.ts +153 -0
  283. package/src/core/logger/filters.ts +148 -0
  284. package/src/core/logger/index.ts +20 -0
  285. package/src/core/logger/logger.ts +434 -0
  286. package/src/core/logger/outputs.ts +136 -0
  287. package/src/core/middleware/built-in/adapters/cache/file.ts +106 -0
  288. package/src/core/middleware/built-in/adapters/cache/index.ts +26 -0
  289. package/src/core/middleware/built-in/adapters/cache/memory.ts +73 -0
  290. package/src/core/middleware/built-in/adapters/cache/redis.ts +103 -0
  291. package/src/core/middleware/built-in/adapters/cdn/azure.ts +68 -0
  292. package/src/core/middleware/built-in/adapters/cdn/cloudflare.ts +100 -0
  293. package/src/core/middleware/built-in/adapters/cdn/cloudfront.ts +92 -0
  294. package/src/core/middleware/built-in/adapters/cdn/index.ts +23 -0
  295. package/src/core/middleware/built-in/adapters/index.ts +7 -0
  296. package/src/core/middleware/built-in/auth.ts +39 -0
  297. package/src/core/middleware/built-in/cache.ts +228 -0
  298. package/src/core/middleware/built-in/cdn.ts +151 -0
  299. package/src/core/middleware/built-in/cookie.ts +90 -0
  300. package/src/core/middleware/built-in/cors.ts +38 -0
  301. package/src/core/middleware/built-in/csp.ts +107 -0
  302. package/src/core/middleware/built-in/csrf.ts +87 -0
  303. package/src/core/middleware/built-in/error-tracker.ts +16 -0
  304. package/src/core/middleware/built-in/index.ts +57 -0
  305. package/src/core/middleware/built-in/performance-monitor.ts +25 -0
  306. package/src/core/middleware/built-in/rate-limit.ts +60 -0
  307. package/src/core/middleware/built-in/request-logger.ts +14 -0
  308. package/src/core/middleware/built-in/session.ts +311 -0
  309. package/src/core/middleware/built-in/sse.ts +91 -0
  310. package/src/core/middleware/built-in/validation.ts +33 -0
  311. package/src/core/middleware/index.ts +188 -0
  312. package/src/core/modules/auto-discovery.ts +265 -0
  313. package/src/core/modules/index.ts +6 -0
  314. package/src/core/modules/modules.ts +125 -0
  315. package/src/core/networking/index.ts +7 -0
  316. package/src/core/networking/service-discovery.ts +309 -0
  317. package/src/core/networking/websocket-manager.ts +259 -0
  318. package/src/core/routing/app-integration.ts +229 -0
  319. package/src/core/routing/index.ts +519 -0
  320. package/src/core/runtime/aws-lambda-adapter.ts +157 -0
  321. package/src/core/runtime/base-adapter.ts +140 -0
  322. package/src/core/runtime/cloudflare-workers-adapter.ts +166 -0
  323. package/src/core/runtime/index.ts +74 -0
  324. package/src/core/runtime/node-adapter.ts +210 -0
  325. package/src/core/runtime/vercel-edge-adapter.ts +125 -0
  326. package/src/core/utilities/circuit-breaker.ts +46 -0
  327. package/src/core/utilities/container.ts +760 -0
  328. package/src/core/utilities/hooks.ts +148 -0
  329. package/src/core/utilities/index.ts +16 -0
  330. package/src/core/validation/index.ts +216 -0
  331. package/src/index.ts +120 -0
  332. package/src/moro.ts +842 -0
  333. package/src/types/cache.ts +38 -0
  334. package/src/types/cdn.ts +22 -0
  335. package/src/types/core.ts +17 -0
  336. package/src/types/database.ts +40 -0
  337. package/src/types/discovery.ts +7 -0
  338. package/src/types/events.ts +90 -0
  339. package/src/types/hooks.ts +47 -0
  340. package/src/types/http.ts +70 -0
  341. package/src/types/logger.ts +109 -0
  342. package/src/types/module.ts +87 -0
  343. package/src/types/runtime.ts +91 -0
  344. package/src/types/session.ts +89 -0
  345. package/tsconfig.json +21 -0
@@ -0,0 +1,760 @@
1
+ // Enhanced Functional Dependency Injection Container
2
+ import { EventEmitter } from "events";
3
+
4
+ // Service lifecycle states
5
+ export enum ServiceLifecycle {
6
+ UNINITIALIZED = "uninitialized",
7
+ INITIALIZING = "initializing",
8
+ INITIALIZED = "initialized",
9
+ DISPOSING = "disposing",
10
+ DISPOSED = "disposed",
11
+ ERROR = "error",
12
+ }
13
+
14
+ // Service scopes
15
+ export enum ServiceScope {
16
+ SINGLETON = "singleton", // One instance per container
17
+ TRANSIENT = "transient", // New instance every time
18
+ REQUEST = "request", // One instance per request context
19
+ MODULE = "module", // One instance per module
20
+ }
21
+
22
+ // Service metadata and configuration
23
+ export interface ServiceMetadata {
24
+ name: string;
25
+ scope: ServiceScope;
26
+ tags: string[];
27
+ dependencies: string[];
28
+ optional: string[];
29
+ lifecycle?: {
30
+ init?: () => Promise<void> | void;
31
+ dispose?: () => Promise<void> | void;
32
+ healthCheck?: () => Promise<boolean> | boolean;
33
+ };
34
+ fallback?: () => any;
35
+ timeout?: number;
36
+ }
37
+
38
+ // Service definition with functional patterns
39
+ export interface ServiceDefinition<T = any> {
40
+ factory: ServiceFactory<T>;
41
+ metadata: ServiceMetadata;
42
+ interceptors: ServiceInterceptor[];
43
+ decorators: ServiceDecorator<T>[];
44
+ }
45
+
46
+ // Functional factory type
47
+ export type ServiceFactory<T> = (
48
+ dependencies: Record<string, any>,
49
+ context?: ServiceContext,
50
+ ) => T | Promise<T>;
51
+
52
+ // Service interceptor for AOP patterns
53
+ export type ServiceInterceptor = (
54
+ serviceName: string,
55
+ dependencies: Record<string, any>,
56
+ context: ServiceContext,
57
+ next: () => any,
58
+ ) => any | Promise<any>;
59
+
60
+ // Service decorator for functional composition
61
+ export type ServiceDecorator<T> = (
62
+ instance: T,
63
+ context: ServiceContext,
64
+ ) => T | Promise<T>;
65
+
66
+ // Service context for request-scoped services
67
+ export interface ServiceContext {
68
+ requestId?: string;
69
+ moduleId?: string;
70
+ metadata: Record<string, any>;
71
+ timestamp: number;
72
+ }
73
+
74
+ // Service instance wrapper
75
+ interface ServiceInstance<T = any> {
76
+ value: T;
77
+ metadata: ServiceMetadata;
78
+ lifecycle: ServiceLifecycle;
79
+ lastAccessed: number;
80
+ accessCount: number;
81
+ context?: ServiceContext;
82
+ }
83
+
84
+ // Higher-order functions for service composition
85
+ export const withLogging =
86
+ <T>(logger: any) =>
87
+ (factory: ServiceFactory<T>): ServiceFactory<T> =>
88
+ (deps, ctx) => {
89
+ logger.debug(
90
+ `Creating service with dependencies: ${Object.keys(deps).join(", ")}`,
91
+ );
92
+ const start = Date.now();
93
+ const result = factory(deps, ctx);
94
+ logger.debug(`Service created in ${Date.now() - start}ms`);
95
+ return result;
96
+ };
97
+
98
+ export const withCaching =
99
+ <T>(ttl = 300000) =>
100
+ (factory: ServiceFactory<T>): ServiceFactory<T> => {
101
+ const cache = new Map<string, { value: T; expires: number }>();
102
+ return async (deps, ctx) => {
103
+ const key = `${ctx?.requestId || "global"}_${JSON.stringify(deps)}`;
104
+ const cached = cache.get(key);
105
+ if (cached && cached.expires > Date.now()) {
106
+ return cached.value;
107
+ }
108
+ const result = await factory(deps, ctx);
109
+ cache.set(key, { value: result, expires: Date.now() + ttl });
110
+ return result;
111
+ };
112
+ };
113
+
114
+ export const withRetry =
115
+ <T>(maxRetries = 3, delay = 1000) =>
116
+ (factory: ServiceFactory<T>): ServiceFactory<T> =>
117
+ async (deps, ctx) => {
118
+ let lastError: Error | null = null;
119
+ for (let i = 0; i <= maxRetries; i++) {
120
+ try {
121
+ return await factory(deps, ctx);
122
+ } catch (error) {
123
+ lastError = error as Error;
124
+ if (i < maxRetries) {
125
+ await new Promise((resolve) =>
126
+ setTimeout(resolve, delay * Math.pow(2, i)),
127
+ );
128
+ }
129
+ }
130
+ }
131
+ throw lastError;
132
+ };
133
+
134
+ export const withTimeout =
135
+ <T>(timeoutMs = 5000) =>
136
+ (factory: ServiceFactory<T>): ServiceFactory<T> =>
137
+ async (deps, ctx) => {
138
+ return Promise.race([
139
+ factory(deps, ctx),
140
+ new Promise<never>((_, reject) =>
141
+ setTimeout(
142
+ () =>
143
+ reject(new Error(`Service creation timeout after ${timeoutMs}ms`)),
144
+ timeoutMs,
145
+ ),
146
+ ),
147
+ ]);
148
+ };
149
+
150
+ // Enhanced Functional Container
151
+ export class FunctionalContainer extends EventEmitter {
152
+ private services = new Map<string, ServiceDefinition>();
153
+ private instances = new Map<string, ServiceInstance>();
154
+ private requestScopes = new Map<string, Map<string, ServiceInstance>>();
155
+ private moduleScopes = new Map<string, Map<string, ServiceInstance>>();
156
+ private globalInterceptors: ServiceInterceptor[] = [];
157
+ private cleanupInterval?: NodeJS.Timeout;
158
+
159
+ constructor() {
160
+ super();
161
+ this.setupCleanup();
162
+ }
163
+
164
+ // Fluent registration API
165
+ register<T>(name: string): ServiceRegistrationBuilder<T> {
166
+ return new ServiceRegistrationBuilder<T>(this, name);
167
+ }
168
+
169
+ // Direct registration for simple cases
170
+ singleton<T>(name: string, factory: ServiceFactory<T>): this {
171
+ this.register<T>(name).singleton().factory(factory).build();
172
+ return this;
173
+ }
174
+
175
+ transient<T>(name: string, factory: ServiceFactory<T>): this {
176
+ this.register<T>(name).transient().factory(factory).build();
177
+ return this;
178
+ }
179
+
180
+ // Functional service registration with HOFs
181
+ compose<T>(
182
+ name: string,
183
+ ...compositionFns: Array<(factory: ServiceFactory<T>) => ServiceFactory<T>>
184
+ ): ServiceRegistrationBuilder<T> {
185
+ const builder = this.register<T>(name);
186
+ return builder.compose(...compositionFns);
187
+ }
188
+
189
+ // Enhanced resolution with context
190
+ async resolve<T>(name: string, context?: ServiceContext): Promise<T> {
191
+ const service = this.services.get(name);
192
+ if (!service) {
193
+ throw new Error(`Service '${name}' not registered`);
194
+ }
195
+
196
+ const scopeKey = this.getScopeKey(name, service.metadata.scope, context);
197
+ const instanceMap = this.getInstanceMap(service.metadata.scope, context);
198
+
199
+ let instance = instanceMap.get(scopeKey);
200
+
201
+ if (!instance || this.shouldRecreate(instance, service.metadata)) {
202
+ instance = await this.createInstance(name, service, context);
203
+ instanceMap.set(scopeKey, instance);
204
+ }
205
+
206
+ instance.lastAccessed = Date.now();
207
+ instance.accessCount++;
208
+
209
+ return instance.value;
210
+ }
211
+
212
+ // Synchronous resolution for non-async services
213
+ resolveSync<T>(name: string, context?: ServiceContext): T {
214
+ const service = this.services.get(name);
215
+ if (!service) {
216
+ throw new Error(`Service '${name}' not registered`);
217
+ }
218
+
219
+ const scopeKey = this.getScopeKey(name, service.metadata.scope, context);
220
+ const instanceMap = this.getInstanceMap(service.metadata.scope, context);
221
+
222
+ let instance = instanceMap.get(scopeKey);
223
+
224
+ if (!instance || this.shouldRecreate(instance, service.metadata)) {
225
+ const result = this.createInstanceSync(name, service, context);
226
+ instance = {
227
+ value: result,
228
+ metadata: service.metadata,
229
+ lifecycle: ServiceLifecycle.INITIALIZED,
230
+ lastAccessed: Date.now(),
231
+ accessCount: 1,
232
+ context,
233
+ };
234
+ instanceMap.set(scopeKey, instance);
235
+ }
236
+
237
+ instance.lastAccessed = Date.now();
238
+ instance.accessCount++;
239
+
240
+ return instance.value;
241
+ }
242
+
243
+ // Add global interceptors
244
+ addInterceptor(interceptor: ServiceInterceptor): this {
245
+ this.globalInterceptors.push(interceptor);
246
+ return this;
247
+ }
248
+
249
+ // Service health checks
250
+ async healthCheck(): Promise<Record<string, boolean>> {
251
+ const results: Record<string, boolean> = {};
252
+
253
+ for (const [name, instance] of this.instances) {
254
+ const service = this.services.get(name);
255
+ if (service?.metadata.lifecycle?.healthCheck) {
256
+ try {
257
+ results[name] = await service.metadata.lifecycle.healthCheck();
258
+ } catch {
259
+ results[name] = false;
260
+ }
261
+ } else {
262
+ results[name] = instance.lifecycle === ServiceLifecycle.INITIALIZED;
263
+ }
264
+ }
265
+
266
+ return results;
267
+ }
268
+
269
+ // Clear request-scoped services
270
+ clearRequestScope(requestId: string): void {
271
+ const requestScope = this.requestScopes.get(requestId);
272
+ if (requestScope) {
273
+ requestScope.clear();
274
+ this.requestScopes.delete(requestId);
275
+ }
276
+ }
277
+
278
+ // Clear module-scoped services
279
+ clearModuleScope(moduleId: string): void {
280
+ const moduleScope = this.moduleScopes.get(moduleId);
281
+ if (moduleScope) {
282
+ moduleScope.clear();
283
+ this.moduleScopes.delete(moduleId);
284
+ }
285
+ }
286
+
287
+ // Service introspection
288
+ getServiceInfo(): Record<string, any> {
289
+ const info: Record<string, any> = {};
290
+
291
+ for (const [name, service] of this.services) {
292
+ const instance = this.instances.get(name);
293
+ info[name] = {
294
+ scope: service.metadata.scope,
295
+ dependencies: service.metadata.dependencies,
296
+ tags: service.metadata.tags,
297
+ lifecycle: instance?.lifecycle || ServiceLifecycle.UNINITIALIZED,
298
+ accessCount: instance?.accessCount || 0,
299
+ lastAccessed: instance?.lastAccessed
300
+ ? new Date(instance.lastAccessed).toISOString()
301
+ : null,
302
+ };
303
+ }
304
+
305
+ return info;
306
+ }
307
+
308
+ // Dispose all services
309
+ async dispose(): Promise<void> {
310
+ for (const [name, instance] of this.instances) {
311
+ const service = this.services.get(name);
312
+ if (
313
+ service?.metadata.lifecycle?.dispose &&
314
+ instance.lifecycle === ServiceLifecycle.INITIALIZED
315
+ ) {
316
+ try {
317
+ instance.lifecycle = ServiceLifecycle.DISPOSING;
318
+ await service.metadata.lifecycle.dispose();
319
+ instance.lifecycle = ServiceLifecycle.DISPOSED;
320
+ } catch (error) {
321
+ instance.lifecycle = ServiceLifecycle.ERROR;
322
+ this.emit("disposeError", { name, error });
323
+ }
324
+ }
325
+ }
326
+
327
+ this.instances.clear();
328
+ this.requestScopes.clear();
329
+ this.moduleScopes.clear();
330
+ }
331
+
332
+ // Internal implementation methods
333
+ private async createInstance<T>(
334
+ name: string,
335
+ service: ServiceDefinition<T>,
336
+ context?: ServiceContext,
337
+ ): Promise<ServiceInstance<T>> {
338
+ const instance: ServiceInstance<T> = {
339
+ value: undefined as any,
340
+ metadata: service.metadata,
341
+ lifecycle: ServiceLifecycle.INITIALIZING,
342
+ lastAccessed: Date.now(),
343
+ accessCount: 0,
344
+ context,
345
+ };
346
+
347
+ try {
348
+ // Resolve dependencies
349
+ const dependencies = await this.resolveDependencies(
350
+ service.metadata,
351
+ context,
352
+ );
353
+
354
+ // Apply interceptors
355
+ const interceptedFactory = this.applyInterceptors(
356
+ name,
357
+ service.factory,
358
+ dependencies,
359
+ context,
360
+ );
361
+
362
+ // Create instance
363
+ instance.value = await interceptedFactory();
364
+
365
+ // Apply decorators
366
+ instance.value = await this.applyDecorators(
367
+ instance.value,
368
+ service.decorators,
369
+ context,
370
+ );
371
+
372
+ // Run initialization lifecycle
373
+ if (service.metadata.lifecycle?.init) {
374
+ await service.metadata.lifecycle.init();
375
+ }
376
+
377
+ instance.lifecycle = ServiceLifecycle.INITIALIZED;
378
+ this.emit("serviceCreated", { name, instance });
379
+ } catch (error) {
380
+ instance.lifecycle = ServiceLifecycle.ERROR;
381
+ this.emit("serviceError", { name, error });
382
+
383
+ // Try fallback if available
384
+ if (service.metadata.fallback) {
385
+ instance.value = service.metadata.fallback();
386
+ instance.lifecycle = ServiceLifecycle.INITIALIZED;
387
+ } else {
388
+ throw error;
389
+ }
390
+ }
391
+
392
+ return instance;
393
+ }
394
+
395
+ private createInstanceSync<T>(
396
+ name: string,
397
+ service: ServiceDefinition<T>,
398
+ context?: ServiceContext,
399
+ ): T {
400
+ // Simplified sync version - no async dependencies or lifecycle
401
+ const dependencies = this.resolveDependenciesSync(
402
+ service.metadata,
403
+ context,
404
+ );
405
+ return service.factory(dependencies, context) as T;
406
+ }
407
+
408
+ private async resolveDependencies(
409
+ metadata: ServiceMetadata,
410
+ context?: ServiceContext,
411
+ ): Promise<Record<string, any>> {
412
+ const dependencies: Record<string, any> = {};
413
+
414
+ for (const dep of metadata.dependencies) {
415
+ dependencies[dep] = await this.resolve(dep, context);
416
+ }
417
+
418
+ for (const optDep of metadata.optional) {
419
+ try {
420
+ dependencies[optDep] = await this.resolve(optDep, context);
421
+ } catch {
422
+ // Optional dependency - continue without it
423
+ }
424
+ }
425
+
426
+ return dependencies;
427
+ }
428
+
429
+ private resolveDependenciesSync(
430
+ metadata: ServiceMetadata,
431
+ context?: ServiceContext,
432
+ ): Record<string, any> {
433
+ const dependencies: Record<string, any> = {};
434
+
435
+ for (const dep of metadata.dependencies) {
436
+ dependencies[dep] = this.resolveSync(dep, context);
437
+ }
438
+
439
+ for (const optDep of metadata.optional) {
440
+ try {
441
+ dependencies[optDep] = this.resolveSync(optDep, context);
442
+ } catch {
443
+ // Optional dependency - continue without it
444
+ }
445
+ }
446
+
447
+ return dependencies;
448
+ }
449
+
450
+ private applyInterceptors(
451
+ name: string,
452
+ factory: ServiceFactory<any>,
453
+ dependencies: Record<string, any>,
454
+ context?: ServiceContext,
455
+ ): () => any {
456
+ return [...this.globalInterceptors].reduceRight(
457
+ (next: () => any, interceptor: ServiceInterceptor) => () =>
458
+ interceptor(
459
+ name,
460
+ dependencies,
461
+ context || this.createDefaultContext(),
462
+ next,
463
+ ),
464
+ () => factory(dependencies, context),
465
+ );
466
+ }
467
+
468
+ private async applyDecorators<T>(
469
+ instance: T,
470
+ decorators: ServiceDecorator<T>[],
471
+ context?: ServiceContext,
472
+ ): Promise<T> {
473
+ let result = instance;
474
+ for (const decorator of decorators) {
475
+ result = await decorator(result, context || this.createDefaultContext());
476
+ }
477
+ return result;
478
+ }
479
+
480
+ private getScopeKey(
481
+ serviceName: string,
482
+ scope: ServiceScope,
483
+ context?: ServiceContext,
484
+ ): string {
485
+ switch (scope) {
486
+ case ServiceScope.REQUEST:
487
+ return `${serviceName}:${context?.requestId || "default-request"}`;
488
+ case ServiceScope.MODULE:
489
+ return `${serviceName}:${context?.moduleId || "default-module"}`;
490
+ default:
491
+ return serviceName; // Each singleton service gets its own key
492
+ }
493
+ }
494
+
495
+ private getInstanceMap(
496
+ scope: ServiceScope,
497
+ context?: ServiceContext,
498
+ ): Map<string, ServiceInstance> {
499
+ switch (scope) {
500
+ case ServiceScope.REQUEST: {
501
+ const requestId = context?.requestId || "default-request";
502
+ if (!this.requestScopes.has(requestId)) {
503
+ this.requestScopes.set(requestId, new Map());
504
+ }
505
+ return this.requestScopes.get(requestId)!;
506
+ }
507
+
508
+ case ServiceScope.MODULE: {
509
+ const moduleId = context?.moduleId || "default-module";
510
+ if (!this.moduleScopes.has(moduleId)) {
511
+ this.moduleScopes.set(moduleId, new Map());
512
+ }
513
+ return this.moduleScopes.get(moduleId)!;
514
+ }
515
+
516
+ default:
517
+ return this.instances;
518
+ }
519
+ }
520
+
521
+ private shouldRecreate(
522
+ instance: ServiceInstance,
523
+ metadata: ServiceMetadata,
524
+ ): boolean {
525
+ return (
526
+ metadata.scope === ServiceScope.TRANSIENT ||
527
+ instance.lifecycle === ServiceLifecycle.ERROR ||
528
+ instance.lifecycle === ServiceLifecycle.DISPOSED
529
+ );
530
+ }
531
+
532
+ private createDefaultContext(): ServiceContext {
533
+ return {
534
+ metadata: {},
535
+ timestamp: Date.now(),
536
+ };
537
+ }
538
+
539
+ private setupCleanup(): void {
540
+ // Cleanup request scopes after timeout
541
+ this.cleanupInterval = setInterval(
542
+ () => {
543
+ const now = Date.now();
544
+ const timeout = 30 * 60 * 1000; // 30 minutes
545
+
546
+ for (const [requestId, scope] of this.requestScopes) {
547
+ const hasRecentActivity = Array.from(scope.values()).some(
548
+ (instance) => now - instance.lastAccessed < timeout,
549
+ );
550
+
551
+ if (!hasRecentActivity) {
552
+ this.clearRequestScope(requestId);
553
+ }
554
+ }
555
+ },
556
+ 5 * 60 * 1000,
557
+ ); // Check every 5 minutes
558
+
559
+ // Unref the interval so it doesn't keep the process alive during testing
560
+ this.cleanupInterval.unref();
561
+ }
562
+
563
+ // Cleanup and destroy the container
564
+ destroy(): void {
565
+ if (this.cleanupInterval) {
566
+ clearInterval(this.cleanupInterval);
567
+ this.cleanupInterval = undefined;
568
+ }
569
+
570
+ // Clear all scopes
571
+ this.requestScopes.clear();
572
+ this.moduleScopes.clear();
573
+ this.instances.clear();
574
+ this.services.clear();
575
+
576
+ this.emit("containerDestroyed");
577
+ }
578
+
579
+ // Internal registration method
580
+ _registerService<T>(name: string, definition: ServiceDefinition<T>): this {
581
+ this.services.set(name, definition);
582
+ this.emit("serviceRegistered", { name, metadata: definition.metadata });
583
+ return this;
584
+ }
585
+
586
+ // Check if service exists
587
+ has(name: string): boolean {
588
+ return this.services.has(name);
589
+ }
590
+ }
591
+
592
+ // Fluent registration builder
593
+ export class ServiceRegistrationBuilder<T> {
594
+ private metadata: Partial<ServiceMetadata> = {
595
+ scope: ServiceScope.SINGLETON,
596
+ tags: [],
597
+ dependencies: [],
598
+ optional: [],
599
+ };
600
+ private _factory?: ServiceFactory<T>;
601
+ private interceptors: ServiceInterceptor[] = [];
602
+ private decorators: ServiceDecorator<T>[] = [];
603
+
604
+ constructor(
605
+ private container: FunctionalContainer,
606
+ private name: string,
607
+ ) {}
608
+
609
+ // Scope configuration
610
+ singleton(): this {
611
+ this.metadata.scope = ServiceScope.SINGLETON;
612
+ return this;
613
+ }
614
+
615
+ transient(): this {
616
+ this.metadata.scope = ServiceScope.TRANSIENT;
617
+ return this;
618
+ }
619
+
620
+ requestScoped(): this {
621
+ this.metadata.scope = ServiceScope.REQUEST;
622
+ return this;
623
+ }
624
+
625
+ moduleScoped(): this {
626
+ this.metadata.scope = ServiceScope.MODULE;
627
+ return this;
628
+ }
629
+
630
+ // Dependencies
631
+ dependsOn(...deps: string[]): this {
632
+ this.metadata.dependencies = [
633
+ ...(this.metadata.dependencies || []),
634
+ ...deps,
635
+ ];
636
+ return this;
637
+ }
638
+
639
+ optionalDependsOn(...deps: string[]): this {
640
+ this.metadata.optional = [...(this.metadata.optional || []), ...deps];
641
+ return this;
642
+ }
643
+
644
+ // Metadata
645
+ tags(...tags: string[]): this {
646
+ this.metadata.tags = [...(this.metadata.tags || []), ...tags];
647
+ return this;
648
+ }
649
+
650
+ // Lifecycle
651
+ onInit(initFn: () => Promise<void> | void): this {
652
+ this.metadata.lifecycle = { ...this.metadata.lifecycle, init: initFn };
653
+ return this;
654
+ }
655
+
656
+ onDispose(disposeFn: () => Promise<void> | void): this {
657
+ this.metadata.lifecycle = {
658
+ ...this.metadata.lifecycle,
659
+ dispose: disposeFn,
660
+ };
661
+ return this;
662
+ }
663
+
664
+ healthCheck(healthFn: () => Promise<boolean> | boolean): this {
665
+ this.metadata.lifecycle = {
666
+ ...this.metadata.lifecycle,
667
+ healthCheck: healthFn,
668
+ };
669
+ return this;
670
+ }
671
+
672
+ fallback(fallbackFn: () => T): this {
673
+ this.metadata.fallback = fallbackFn;
674
+ return this;
675
+ }
676
+
677
+ timeout(ms: number): this {
678
+ this.metadata.timeout = ms;
679
+ return this;
680
+ }
681
+
682
+ // Factory and composition
683
+ factory(factory: ServiceFactory<T>): this {
684
+ this._factory = factory;
685
+ return this;
686
+ }
687
+
688
+ compose(
689
+ ...compositionFns: Array<(factory: ServiceFactory<T>) => ServiceFactory<T>>
690
+ ): this {
691
+ if (!this._factory) {
692
+ throw new Error("Factory must be set before composition");
693
+ }
694
+
695
+ this._factory = compositionFns.reduce((acc, fn) => fn(acc), this._factory);
696
+ return this;
697
+ }
698
+
699
+ // Interceptors and decorators
700
+ intercept(interceptor: ServiceInterceptor): this {
701
+ this.interceptors.push(interceptor);
702
+ return this;
703
+ }
704
+
705
+ decorate(decorator: ServiceDecorator<T>): this {
706
+ this.decorators.push(decorator);
707
+ return this;
708
+ }
709
+
710
+ // Build and register
711
+ build(): FunctionalContainer {
712
+ if (!this._factory) {
713
+ throw new Error(`Factory not provided for service '${this.name}'`);
714
+ }
715
+
716
+ const definition: ServiceDefinition<T> = {
717
+ factory: this._factory,
718
+ metadata: {
719
+ name: this.name,
720
+ scope: this.metadata.scope!,
721
+ tags: this.metadata.tags!,
722
+ dependencies: this.metadata.dependencies!,
723
+ optional: this.metadata.optional!,
724
+ lifecycle: this.metadata.lifecycle,
725
+ fallback: this.metadata.fallback,
726
+ timeout: this.metadata.timeout,
727
+ },
728
+ interceptors: this.interceptors,
729
+ decorators: this.decorators,
730
+ };
731
+
732
+ return this.container._registerService(this.name, definition);
733
+ }
734
+ }
735
+
736
+ // Standard Container class
737
+ export class Container {
738
+ private functionalContainer = new FunctionalContainer();
739
+
740
+ register<T>(name: string, factory: () => T, singleton = false): void {
741
+ this.functionalContainer
742
+ .register<T>(name)
743
+ .factory(() => factory())
744
+ [singleton ? "singleton" : "transient"]()
745
+ .build();
746
+ }
747
+
748
+ resolve<T>(name: string): T {
749
+ return this.functionalContainer.resolveSync<T>(name);
750
+ }
751
+
752
+ has(name: string): boolean {
753
+ return this.functionalContainer.has(name);
754
+ }
755
+
756
+ // Expose enhanced container for migration
757
+ getEnhanced(): FunctionalContainer {
758
+ return this.functionalContainer;
759
+ }
760
+ }