@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,309 @@
1
+ // Service Discovery Client for Microservices
2
+ // Supports Consul, Kubernetes, and in-memory registry
3
+
4
+ export interface ServiceInfo {
5
+ name: string;
6
+ host: string;
7
+ port: number;
8
+ health?: string;
9
+ version?: string;
10
+ tags?: string[];
11
+ metadata?: Record<string, any>;
12
+ }
13
+
14
+ export interface ServiceDiscoveryOptions {
15
+ type: "consul" | "kubernetes" | "memory";
16
+ consulUrl?: string;
17
+ kubernetesNamespace?: string;
18
+ healthCheckInterval?: number;
19
+ tags?: string[];
20
+ }
21
+
22
+ export class ServiceRegistry {
23
+ private services = new Map<string, ServiceInfo[]>();
24
+ private options: ServiceDiscoveryOptions;
25
+ private healthCheckInterval?: NodeJS.Timeout;
26
+
27
+ constructor(options: ServiceDiscoveryOptions) {
28
+ this.options = options;
29
+ this.startHealthChecks();
30
+ }
31
+
32
+ async register(service: ServiceInfo): Promise<void> {
33
+ const { name } = service;
34
+
35
+ switch (this.options.type) {
36
+ case "consul":
37
+ await this.registerWithConsul(service);
38
+ break;
39
+ case "kubernetes":
40
+ await this.registerWithKubernetes(service);
41
+ break;
42
+ case "memory":
43
+ this.registerInMemory(service);
44
+ break;
45
+ }
46
+
47
+ console.log(`Service registered: ${name}@${service.host}:${service.port}`);
48
+ }
49
+
50
+ async discover(serviceName: string): Promise<ServiceInfo[]> {
51
+ switch (this.options.type) {
52
+ case "consul":
53
+ return this.discoverFromConsul(serviceName);
54
+ case "kubernetes":
55
+ return this.discoverFromKubernetes(serviceName);
56
+ case "memory":
57
+ return this.discoverFromMemory(serviceName);
58
+ default:
59
+ return [];
60
+ }
61
+ }
62
+
63
+ async deregister(serviceName: string): Promise<void> {
64
+ switch (this.options.type) {
65
+ case "consul":
66
+ await this.deregisterFromConsul(serviceName);
67
+ break;
68
+ case "kubernetes":
69
+ // K8s handles this automatically
70
+ break;
71
+ case "memory":
72
+ this.services.delete(serviceName);
73
+ break;
74
+ }
75
+
76
+ console.log(`Service deregistered: ${serviceName}`);
77
+ }
78
+
79
+ // In-memory registry methods
80
+ private registerInMemory(service: ServiceInfo): void {
81
+ const existing = this.services.get(service.name) || [];
82
+ const updated = existing.filter(
83
+ (s) => s.host !== service.host || s.port !== service.port,
84
+ );
85
+ updated.push(service);
86
+ this.services.set(service.name, updated);
87
+ }
88
+
89
+ private discoverFromMemory(serviceName: string): ServiceInfo[] {
90
+ return this.services.get(serviceName) || [];
91
+ }
92
+
93
+ // Consul integration
94
+ private async registerWithConsul(service: ServiceInfo): Promise<void> {
95
+ if (!this.options.consulUrl) {
96
+ throw new Error("Consul URL required for consul service discovery");
97
+ }
98
+
99
+ const consulService = {
100
+ ID: `${service.name}-${service.host}-${service.port}`,
101
+ Name: service.name,
102
+ Tags: service.tags || [],
103
+ Address: service.host,
104
+ Port: service.port,
105
+ Check: service.health
106
+ ? {
107
+ HTTP: `http://${service.host}:${service.port}${service.health}`,
108
+ Interval: "30s",
109
+ Timeout: "10s",
110
+ }
111
+ : undefined,
112
+ Meta: service.metadata || {},
113
+ };
114
+
115
+ try {
116
+ const response = await fetch(
117
+ `${this.options.consulUrl}/v1/agent/service/register`,
118
+ {
119
+ method: "PUT",
120
+ headers: { "Content-Type": "application/json" },
121
+ body: JSON.stringify(consulService),
122
+ },
123
+ );
124
+
125
+ if (!response.ok) {
126
+ throw new Error(`Consul registration failed: ${response.statusText}`);
127
+ }
128
+ } catch (error) {
129
+ console.error("Failed to register with Consul:", error);
130
+ // Fallback to in-memory
131
+ this.registerInMemory(service);
132
+ }
133
+ }
134
+
135
+ private async discoverFromConsul(
136
+ serviceName: string,
137
+ ): Promise<ServiceInfo[]> {
138
+ if (!this.options.consulUrl) {
139
+ return this.discoverFromMemory(serviceName);
140
+ }
141
+
142
+ try {
143
+ const response = await fetch(
144
+ `${this.options.consulUrl}/v1/health/service/${serviceName}?passing=true`,
145
+ );
146
+
147
+ if (!response.ok) {
148
+ throw new Error(`Consul discovery failed: ${response.statusText}`);
149
+ }
150
+
151
+ const services = (await response.json()) as any[];
152
+ return services.map((entry: any) => ({
153
+ name: entry.Service.Service,
154
+ host: entry.Service.Address,
155
+ port: entry.Service.Port,
156
+ tags: entry.Service.Tags,
157
+ metadata: entry.Service.Meta,
158
+ }));
159
+ } catch (error) {
160
+ console.error("Failed to discover from Consul:", error);
161
+ return this.discoverFromMemory(serviceName);
162
+ }
163
+ }
164
+
165
+ private async deregisterFromConsul(serviceName: string): Promise<void> {
166
+ if (!this.options.consulUrl) return;
167
+
168
+ try {
169
+ await fetch(
170
+ `${this.options.consulUrl}/v1/agent/service/deregister/${serviceName}`,
171
+ {
172
+ method: "PUT",
173
+ },
174
+ );
175
+ } catch (error) {
176
+ console.error("Failed to deregister from Consul:", error);
177
+ }
178
+ }
179
+
180
+ // Kubernetes integration
181
+ private async registerWithKubernetes(service: ServiceInfo): Promise<void> {
182
+ // In Kubernetes, services are registered via Service/Endpoints resources
183
+ // This would typically be handled by the K8s API, not application code
184
+ console.log(
185
+ `K8s service registration: ${service.name} (handled by Kubernetes)`,
186
+ );
187
+
188
+ // Fallback to in-memory for local development
189
+ this.registerInMemory(service);
190
+ }
191
+
192
+ private async discoverFromKubernetes(
193
+ serviceName: string,
194
+ ): Promise<ServiceInfo[]> {
195
+ // In K8s, we can discover services via DNS or the K8s API
196
+ const namespace = this.options.kubernetesNamespace || "default";
197
+
198
+ try {
199
+ // Try K8s service DNS resolution
200
+ const host = `${serviceName}.${namespace}.svc.cluster.local`;
201
+
202
+ // For demo purposes, return the service info
203
+ // In production, you'd query the K8s API or use DNS
204
+ return [
205
+ {
206
+ name: serviceName,
207
+ host,
208
+ port: 80, // Default port, should be discovered from service definition
209
+ metadata: { discovered: "kubernetes" },
210
+ },
211
+ ];
212
+ } catch (error) {
213
+ console.error("Failed to discover from Kubernetes:", error);
214
+ return this.discoverFromMemory(serviceName);
215
+ }
216
+ }
217
+
218
+ // Health checking
219
+ private startHealthChecks(): void {
220
+ if (this.options.healthCheckInterval) {
221
+ this.healthCheckInterval = setInterval(
222
+ () => this.performHealthChecks(),
223
+ this.options.healthCheckInterval,
224
+ );
225
+ }
226
+ }
227
+
228
+ private async performHealthChecks(): Promise<void> {
229
+ for (const [serviceName, services] of this.services.entries()) {
230
+ for (const service of services) {
231
+ if (service.health) {
232
+ try {
233
+ const response = await fetch(
234
+ `http://${service.host}:${service.port}${service.health}`,
235
+ {
236
+ timeout: 5000,
237
+ } as any,
238
+ );
239
+
240
+ if (!response.ok) {
241
+ console.warn(
242
+ `Health check failed for ${serviceName}: ${response.statusText}`,
243
+ );
244
+ // Remove unhealthy service
245
+ this.removeUnhealthyService(serviceName, service);
246
+ }
247
+ } catch (error) {
248
+ console.warn(`Health check failed for ${serviceName}:`, error);
249
+ this.removeUnhealthyService(serviceName, service);
250
+ }
251
+ }
252
+ }
253
+ }
254
+ }
255
+
256
+ private removeUnhealthyService(
257
+ serviceName: string,
258
+ unhealthyService: ServiceInfo,
259
+ ): void {
260
+ const services = this.services.get(serviceName) || [];
261
+ const filtered = services.filter(
262
+ (s) =>
263
+ s.host !== unhealthyService.host || s.port !== unhealthyService.port,
264
+ );
265
+
266
+ if (filtered.length === 0) {
267
+ this.services.delete(serviceName);
268
+ } else {
269
+ this.services.set(serviceName, filtered);
270
+ }
271
+ }
272
+
273
+ // Load balancing
274
+ selectService(
275
+ serviceName: string,
276
+ strategy: "round-robin" | "random" | "least-connections" = "round-robin",
277
+ ): ServiceInfo | null {
278
+ const services = this.services.get(serviceName) || [];
279
+
280
+ if (services.length === 0) {
281
+ return null;
282
+ }
283
+
284
+ switch (strategy) {
285
+ case "random":
286
+ return services[Math.floor(Math.random() * services.length)];
287
+ case "round-robin":
288
+ // Simple round-robin (in production, maintain state)
289
+ return services[Date.now() % services.length];
290
+ case "least-connections":
291
+ // For demo, just return the first (in production, track connections)
292
+ return services[0];
293
+ default:
294
+ return services[0];
295
+ }
296
+ }
297
+
298
+ // Cleanup
299
+ destroy(): void {
300
+ if (this.healthCheckInterval) {
301
+ clearInterval(this.healthCheckInterval);
302
+ }
303
+ }
304
+
305
+ // Get all registered services
306
+ getAllServices(): Record<string, ServiceInfo[]> {
307
+ return Object.fromEntries(this.services.entries());
308
+ }
309
+ }
@@ -0,0 +1,259 @@
1
+ // src/core/websocket-manager.ts
2
+ import { Server as SocketIOServer, Socket, Namespace } from "socket.io";
3
+ import { Container } from "../utilities";
4
+ import { CircuitBreaker } from "../utilities";
5
+ import { ModuleConfig, WebSocketDefinition } from "../../types/module";
6
+
7
+ export class WebSocketManager {
8
+ private circuitBreakers = new Map<string, CircuitBreaker>();
9
+ private rateLimiters = new Map<
10
+ string,
11
+ Map<string, { count: number; resetTime: number }>
12
+ >();
13
+ private compressionEnabled = true;
14
+ private customIdGenerator?: () => string;
15
+
16
+ constructor(
17
+ private io: SocketIOServer,
18
+ private container: Container,
19
+ ) {
20
+ this.setupAdvancedFeatures();
21
+ }
22
+
23
+ private setupAdvancedFeatures() {
24
+ // Enable compression for WebSocket messages
25
+ if (this.compressionEnabled) {
26
+ (this.io.engine as any).compression = true;
27
+ (this.io.engine as any).perMessageDeflate = {
28
+ threshold: 1024,
29
+ concurrencyLimit: 10,
30
+ memLevel: 8,
31
+ };
32
+ }
33
+
34
+ // Custom session ID generation if provided
35
+ if (this.customIdGenerator) {
36
+ (this.io.engine as any).generateId = this.customIdGenerator;
37
+ }
38
+
39
+ // Global WebSocket middleware for advanced features
40
+ this.io.use((socket, next) => {
41
+ // Add binary message handling
42
+ socket.onAny((event, ...args) => {
43
+ // Handle binary frames efficiently
44
+ args.forEach((arg, index) => {
45
+ if (Buffer.isBuffer(arg)) {
46
+ // Process binary data with optimizations
47
+ args[index] = this.processBinaryData(arg);
48
+ }
49
+ });
50
+ });
51
+
52
+ // Add compression per message
53
+ (socket as any).compressedEmit = (event: string, data: any) => {
54
+ if (this.compressionEnabled && this.shouldCompress(data)) {
55
+ socket.compress(true).emit(event, data);
56
+ } else {
57
+ socket.emit(event, data);
58
+ }
59
+ };
60
+
61
+ // Add heartbeat mechanism
62
+ (socket as any).heartbeat = () => {
63
+ socket.emit("heartbeat", { timestamp: Date.now() });
64
+ };
65
+
66
+ next();
67
+ });
68
+ }
69
+
70
+ setCustomIdGenerator(generator: () => string) {
71
+ this.customIdGenerator = generator;
72
+ (this.io.engine as any).generateId = generator;
73
+ }
74
+
75
+ enableCompression(options?: {
76
+ threshold?: number;
77
+ concurrencyLimit?: number;
78
+ memLevel?: number;
79
+ }) {
80
+ this.compressionEnabled = true;
81
+ if (options) {
82
+ (this.io.engine as any).perMessageDeflate = {
83
+ threshold: options.threshold || 1024,
84
+ concurrencyLimit: options.concurrencyLimit || 10,
85
+ memLevel: options.memLevel || 8,
86
+ };
87
+ }
88
+ }
89
+
90
+ private processBinaryData(buffer: Buffer): Buffer {
91
+ // Optimize binary data processing
92
+ // Could add compression, validation, etc.
93
+ return buffer;
94
+ }
95
+
96
+ private shouldCompress(data: any): boolean {
97
+ // Determine if data should be compressed
98
+ const serialized = JSON.stringify(data);
99
+ return serialized.length > 1024; // Compress if larger than 1KB
100
+ }
101
+
102
+ async registerHandler(
103
+ namespace: Namespace,
104
+ wsConfig: WebSocketDefinition,
105
+ moduleConfig: ModuleConfig,
106
+ ): Promise<void> {
107
+ namespace.on("connection", (socket: Socket) => {
108
+ console.log(`WebSocket connected to /${moduleConfig.name}: ${socket.id}`);
109
+ this.setupSocketHandlers(socket, wsConfig, moduleConfig);
110
+ this.setupSocketMiddleware(socket, moduleConfig.name);
111
+ });
112
+ }
113
+
114
+ private setupSocketHandlers(
115
+ socket: Socket,
116
+ wsConfig: WebSocketDefinition,
117
+ moduleConfig: ModuleConfig,
118
+ ): void {
119
+ socket.on(wsConfig.event, async (data: any, callback?: Function) => {
120
+ const handlerKey = `${moduleConfig.name}.${wsConfig.handler}`;
121
+
122
+ try {
123
+ // Rate limiting
124
+ if (
125
+ wsConfig.rateLimit &&
126
+ !this.checkRateLimit(socket.id, handlerKey, wsConfig.rateLimit)
127
+ ) {
128
+ const error = {
129
+ success: false,
130
+ error: "Rate limit exceeded",
131
+ code: "RATE_LIMIT",
132
+ };
133
+ if (callback) callback(error);
134
+ else socket.emit("error", error);
135
+ return;
136
+ }
137
+
138
+ // Validation (Zod-only)
139
+ if (wsConfig.validation) {
140
+ try {
141
+ data = wsConfig.validation.parse(data);
142
+ } catch (validationError: any) {
143
+ if (validationError.issues) {
144
+ const error = {
145
+ success: false,
146
+ error: "Validation failed",
147
+ details: validationError.issues.map((issue: any) => ({
148
+ field: issue.path.length > 0 ? issue.path.join(".") : "data",
149
+ message: issue.message,
150
+ code: issue.code,
151
+ })),
152
+ };
153
+ if (callback) callback(error);
154
+ else socket.emit("error", error);
155
+ return;
156
+ }
157
+ throw validationError;
158
+ }
159
+ }
160
+
161
+ // Circuit breaker protection
162
+ const circuitBreaker = this.getCircuitBreaker(handlerKey);
163
+
164
+ const result = await circuitBreaker.execute(async () => {
165
+ const controller = this.container.resolve(moduleConfig.name);
166
+ return await (controller as any)[wsConfig.handler](socket, data);
167
+ });
168
+
169
+ // Handle response
170
+ if (callback) {
171
+ callback({ success: true, data: result });
172
+ } else if (wsConfig.broadcast && result?.event) {
173
+ socket.broadcast.emit(result.event, result.data);
174
+ } else if (result) {
175
+ socket.emit(`${wsConfig.event}:response`, result);
176
+ }
177
+ } catch (error) {
178
+ const errorMessage =
179
+ error instanceof Error ? error.message : String(error);
180
+ const errorCode = (error as any)?.code || "INTERNAL_ERROR";
181
+ console.error(`WebSocket error in ${handlerKey}:`, errorMessage);
182
+
183
+ const errorResponse = {
184
+ success: false,
185
+ error: errorMessage,
186
+ code: errorCode,
187
+ };
188
+
189
+ if (callback) {
190
+ callback(errorResponse);
191
+ } else {
192
+ socket.emit("error", errorResponse);
193
+ }
194
+ }
195
+ });
196
+ }
197
+
198
+ private setupSocketMiddleware(socket: Socket, moduleName: string): void {
199
+ socket.on("disconnect", (reason) => {
200
+ console.log(
201
+ `WebSocket disconnected from /${moduleName}: ${socket.id} (${reason})`,
202
+ );
203
+ this.cleanup(socket.id);
204
+ });
205
+
206
+ socket.on("ping", () => {
207
+ socket.emit("pong");
208
+ });
209
+ }
210
+
211
+ private checkRateLimit(
212
+ socketId: string,
213
+ handlerKey: string,
214
+ rateLimit: { requests: number; window: number },
215
+ ): boolean {
216
+ if (!this.rateLimiters.has(handlerKey)) {
217
+ this.rateLimiters.set(handlerKey, new Map());
218
+ }
219
+
220
+ const handlerLimiter = this.rateLimiters.get(handlerKey)!;
221
+ const now = Date.now();
222
+ const socketLimit = handlerLimiter.get(socketId);
223
+
224
+ if (!socketLimit || now > socketLimit.resetTime) {
225
+ handlerLimiter.set(socketId, {
226
+ count: 1,
227
+ resetTime: now + rateLimit.window,
228
+ });
229
+ return true;
230
+ }
231
+
232
+ if (socketLimit.count >= rateLimit.requests) {
233
+ return false;
234
+ }
235
+
236
+ socketLimit.count++;
237
+ return true;
238
+ }
239
+
240
+ private getCircuitBreaker(key: string): CircuitBreaker {
241
+ if (!this.circuitBreakers.has(key)) {
242
+ this.circuitBreakers.set(
243
+ key,
244
+ new CircuitBreaker({
245
+ failureThreshold: 5,
246
+ resetTimeout: 30000,
247
+ monitoringPeriod: 10000,
248
+ }),
249
+ );
250
+ }
251
+ return this.circuitBreakers.get(key)!;
252
+ }
253
+
254
+ private cleanup(socketId: string): void {
255
+ this.rateLimiters.forEach((limiter) => {
256
+ limiter.delete(socketId);
257
+ });
258
+ }
259
+ }