@expressots/adapter-express 3.0.0-beta.4.2 → 4.0.0-preview.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/README.md +39 -96
  2. package/lib/CHANGELOG.md +43 -0
  3. package/lib/README.md +39 -96
  4. package/lib/cjs/adapter-express/application-express.base.js +3 -1
  5. package/lib/cjs/adapter-express/application-express.js +1049 -85
  6. package/lib/cjs/adapter-express/express-utils/conditional-middleware.js +102 -0
  7. package/lib/cjs/adapter-express/express-utils/constants.js +17 -0
  8. package/lib/cjs/adapter-express/express-utils/content-negotiation-decorators.js +129 -0
  9. package/lib/cjs/adapter-express/express-utils/decorators.js +186 -49
  10. package/lib/cjs/adapter-express/express-utils/exception-filter-decorators.js +11 -0
  11. package/lib/cjs/adapter-express/express-utils/guard-context-factory.js +84 -0
  12. package/lib/cjs/adapter-express/express-utils/guard-middleware.js +115 -0
  13. package/lib/cjs/adapter-express/express-utils/guard-utils.js +18 -0
  14. package/lib/cjs/adapter-express/express-utils/http-context-store.js +15 -0
  15. package/lib/cjs/adapter-express/express-utils/http-status-middleware.js +37 -2
  16. package/lib/cjs/adapter-express/express-utils/index.js +67 -1
  17. package/lib/cjs/adapter-express/express-utils/interceptor-middleware.js +132 -0
  18. package/lib/cjs/adapter-express/express-utils/inversify-express-server.js +810 -63
  19. package/lib/cjs/adapter-express/express-utils/lazy-module-middleware.js +241 -0
  20. package/lib/cjs/adapter-express/express-utils/middleware-composition.js +95 -0
  21. package/lib/cjs/adapter-express/express-utils/permission-preloader.middleware.js +48 -0
  22. package/lib/cjs/adapter-express/express-utils/route-constraints.js +95 -0
  23. package/lib/cjs/adapter-express/express-utils/scope-extractor.interface.js +2 -0
  24. package/lib/cjs/adapter-express/express-utils/scope-extractor.js +66 -0
  25. package/lib/cjs/adapter-express/express-utils/setup-authorization.js +71 -0
  26. package/lib/cjs/adapter-express/express-utils/setup-event-system.js +113 -0
  27. package/lib/cjs/adapter-express/express-utils/setup-interceptors.js +103 -0
  28. package/lib/cjs/adapter-express/express-utils/setup-lazy-loading.js +228 -0
  29. package/lib/cjs/adapter-express/express-utils/utils.js +30 -12
  30. package/lib/cjs/adapter-express/express-utils/validation-decorators.js +205 -0
  31. package/lib/cjs/adapter-express/express-utils/validation-service.js +252 -0
  32. package/lib/cjs/adapter-express/index.js +7 -5
  33. package/lib/cjs/adapter-express/micro-api/application-express-micro-route.js +31 -1
  34. package/lib/cjs/adapter-express/micro-api/application-express-micro.js +11 -37
  35. package/lib/cjs/adapter-express/micro-api/gateway/circuit-breaker.js +174 -0
  36. package/lib/cjs/adapter-express/micro-api/gateway/index.js +11 -0
  37. package/lib/cjs/adapter-express/micro-api/gateway/service-proxy.js +214 -0
  38. package/lib/cjs/adapter-express/micro-api/index.js +27 -3
  39. package/lib/cjs/adapter-express/micro-api/micro.js +217 -0
  40. package/lib/cjs/adapter-express/micro-api/queue/index.js +8 -0
  41. package/lib/cjs/adapter-express/micro-api/queue/queue.interface.js +2 -0
  42. package/lib/cjs/adapter-express/micro-api/queue/rabbitmq-consumer.js +255 -0
  43. package/lib/cjs/adapter-express/micro-api/serverless/aws-lambda.adapter.js +183 -0
  44. package/lib/cjs/adapter-express/micro-api/serverless/cloudflare.adapter.js +158 -0
  45. package/lib/cjs/adapter-express/micro-api/serverless/index.js +12 -0
  46. package/lib/cjs/adapter-express/micro-api/serverless/vercel.adapter.js +102 -0
  47. package/lib/cjs/adapter-express/micro-api/service-mesh/index.js +10 -0
  48. package/lib/cjs/adapter-express/micro-api/service-mesh/service-client.js +194 -0
  49. package/lib/cjs/adapter-express/micro-api/service-mesh/service-discovery.js +261 -0
  50. package/lib/cjs/adapter-express/middleware/index.js +21 -0
  51. package/lib/cjs/adapter-express/middleware/request-logging.middleware.js +244 -0
  52. package/lib/cjs/adapter-express/render/engine.js +15 -15
  53. package/lib/cjs/adapter-express/render/index.js +5 -0
  54. package/lib/cjs/adapter-express/studio/index.js +9 -0
  55. package/lib/cjs/adapter-express/studio/studio-integration.js +214 -0
  56. package/lib/cjs/index.js +1 -1
  57. package/lib/cjs/types/adapter-express/application-express.base.d.ts +20 -7
  58. package/lib/cjs/types/adapter-express/application-express.d.ts +273 -32
  59. package/lib/cjs/types/adapter-express/express-utils/base-middleware.d.ts +2 -2
  60. package/lib/cjs/types/adapter-express/express-utils/conditional-middleware.d.ts +97 -0
  61. package/lib/cjs/types/adapter-express/express-utils/constants.d.ts +13 -0
  62. package/lib/cjs/types/adapter-express/express-utils/content-negotiation-decorators.d.ts +94 -0
  63. package/lib/cjs/types/adapter-express/express-utils/decorators.d.ts +54 -6
  64. package/lib/cjs/types/adapter-express/express-utils/exception-filter-decorators.d.ts +6 -0
  65. package/lib/cjs/types/adapter-express/express-utils/guard-context-factory.d.ts +17 -0
  66. package/lib/cjs/types/adapter-express/express-utils/guard-middleware.d.ts +22 -0
  67. package/lib/cjs/types/adapter-express/express-utils/guard-utils.d.ts +11 -0
  68. package/lib/cjs/types/adapter-express/express-utils/http-context-store.d.ts +20 -0
  69. package/lib/cjs/types/adapter-express/express-utils/httpResponseMessage.d.ts +1 -1
  70. package/lib/cjs/types/adapter-express/express-utils/index.d.ts +30 -2
  71. package/lib/cjs/types/adapter-express/express-utils/interceptor-middleware.d.ts +40 -0
  72. package/lib/cjs/types/adapter-express/express-utils/interfaces.d.ts +42 -5
  73. package/lib/cjs/types/adapter-express/express-utils/inversify-express-server.d.ts +114 -2
  74. package/lib/cjs/types/adapter-express/express-utils/lazy-module-middleware.d.ts +122 -0
  75. package/lib/cjs/types/adapter-express/express-utils/middleware-composition.d.ts +85 -0
  76. package/lib/cjs/types/adapter-express/express-utils/permission-preloader.middleware.d.ts +10 -0
  77. package/lib/cjs/types/adapter-express/express-utils/route-constraints.d.ts +89 -0
  78. package/lib/cjs/types/adapter-express/express-utils/scope-extractor.d.ts +21 -0
  79. package/lib/cjs/types/adapter-express/express-utils/scope-extractor.interface.d.ts +12 -0
  80. package/lib/cjs/types/adapter-express/express-utils/setup-authorization.d.ts +34 -0
  81. package/lib/cjs/types/adapter-express/express-utils/setup-event-system.d.ts +118 -0
  82. package/lib/cjs/types/adapter-express/express-utils/setup-interceptors.d.ts +115 -0
  83. package/lib/cjs/types/adapter-express/express-utils/setup-lazy-loading.d.ts +123 -0
  84. package/lib/cjs/types/adapter-express/express-utils/utils.d.ts +17 -2
  85. package/lib/cjs/types/adapter-express/express-utils/validation-decorators.d.ts +145 -0
  86. package/lib/cjs/types/adapter-express/express-utils/validation-service.d.ts +88 -0
  87. package/lib/cjs/types/adapter-express/index.d.ts +6 -4
  88. package/lib/cjs/types/adapter-express/micro-api/application-express-micro-route.d.ts +25 -14
  89. package/lib/cjs/types/adapter-express/micro-api/application-express-micro.d.ts +3 -10
  90. package/lib/cjs/types/adapter-express/micro-api/gateway/circuit-breaker.d.ts +111 -0
  91. package/lib/cjs/types/adapter-express/micro-api/gateway/index.d.ts +5 -0
  92. package/lib/cjs/types/adapter-express/micro-api/gateway/service-proxy.d.ts +83 -0
  93. package/lib/cjs/types/adapter-express/micro-api/index.d.ts +7 -1
  94. package/lib/cjs/types/adapter-express/micro-api/micro.d.ts +66 -0
  95. package/lib/cjs/types/adapter-express/micro-api/queue/index.d.ts +5 -0
  96. package/lib/cjs/types/adapter-express/micro-api/queue/queue.interface.d.ts +60 -0
  97. package/lib/cjs/types/adapter-express/micro-api/queue/rabbitmq-consumer.d.ts +86 -0
  98. package/lib/cjs/types/adapter-express/micro-api/serverless/aws-lambda.adapter.d.ts +77 -0
  99. package/lib/cjs/types/adapter-express/micro-api/serverless/cloudflare.adapter.d.ts +64 -0
  100. package/lib/cjs/types/adapter-express/micro-api/serverless/index.d.ts +6 -0
  101. package/lib/cjs/types/adapter-express/micro-api/serverless/vercel.adapter.d.ts +56 -0
  102. package/lib/cjs/types/adapter-express/micro-api/service-mesh/index.d.ts +5 -0
  103. package/lib/cjs/types/adapter-express/micro-api/service-mesh/service-client.d.ts +122 -0
  104. package/lib/cjs/types/adapter-express/micro-api/service-mesh/service-discovery.d.ts +150 -0
  105. package/lib/cjs/types/adapter-express/middleware/index.d.ts +5 -0
  106. package/lib/cjs/types/adapter-express/middleware/request-logging.middleware.d.ts +65 -0
  107. package/lib/cjs/types/adapter-express/render/index.d.ts +1 -0
  108. package/lib/cjs/types/adapter-express/studio/index.d.ts +1 -0
  109. package/lib/cjs/types/adapter-express/studio/studio-integration.d.ts +92 -0
  110. package/lib/cjs/types/index.d.ts +1 -1
  111. package/lib/esm/adapter-express/application-express.base.js +24 -0
  112. package/lib/esm/adapter-express/application-express.js +1300 -0
  113. package/lib/esm/adapter-express/application-express.types.js +1 -0
  114. package/lib/esm/adapter-express/express-utils/base-middleware.js +19 -0
  115. package/lib/esm/adapter-express/express-utils/conditional-middleware.js +96 -0
  116. package/lib/esm/adapter-express/express-utils/constants.js +63 -0
  117. package/lib/esm/adapter-express/express-utils/content/httpContent.js +6 -0
  118. package/lib/esm/adapter-express/express-utils/content-negotiation-decorators.js +120 -0
  119. package/lib/esm/adapter-express/express-utils/decorators.js +575 -0
  120. package/lib/esm/adapter-express/express-utils/exception-filter-decorators.js +6 -0
  121. package/lib/esm/adapter-express/express-utils/guard-context-factory.js +83 -0
  122. package/lib/esm/adapter-express/express-utils/guard-middleware.js +115 -0
  123. package/lib/esm/adapter-express/express-utils/guard-utils.js +14 -0
  124. package/lib/esm/adapter-express/express-utils/http-context-store.js +10 -0
  125. package/lib/esm/adapter-express/express-utils/http-status-middleware.js +116 -0
  126. package/lib/esm/adapter-express/express-utils/httpResponseMessage.js +29 -0
  127. package/lib/esm/adapter-express/express-utils/index.js +24 -0
  128. package/lib/esm/adapter-express/express-utils/interceptor-middleware.js +130 -0
  129. package/lib/esm/adapter-express/express-utils/interfaces.js +1 -0
  130. package/lib/esm/adapter-express/express-utils/inversify-express-server.js +1031 -0
  131. package/lib/esm/adapter-express/express-utils/lazy-module-middleware.js +236 -0
  132. package/lib/esm/adapter-express/express-utils/middleware-composition.js +89 -0
  133. package/lib/esm/adapter-express/express-utils/permission-preloader.middleware.js +45 -0
  134. package/lib/esm/adapter-express/express-utils/resolver-multer.js +30 -0
  135. package/lib/esm/adapter-express/express-utils/route-constraints.js +91 -0
  136. package/lib/esm/adapter-express/express-utils/scope-extractor.interface.js +1 -0
  137. package/lib/esm/adapter-express/express-utils/scope-extractor.js +63 -0
  138. package/lib/esm/adapter-express/express-utils/setup-authorization.js +68 -0
  139. package/lib/esm/adapter-express/express-utils/setup-event-system.js +110 -0
  140. package/lib/esm/adapter-express/express-utils/setup-interceptors.js +100 -0
  141. package/lib/esm/adapter-express/express-utils/setup-lazy-loading.js +225 -0
  142. package/lib/esm/adapter-express/express-utils/utils.js +68 -0
  143. package/lib/esm/adapter-express/express-utils/validation-decorators.js +199 -0
  144. package/lib/esm/adapter-express/express-utils/validation-service.js +251 -0
  145. package/lib/esm/adapter-express/index.js +7 -0
  146. package/lib/esm/adapter-express/micro-api/application-express-micro-container.js +48 -0
  147. package/lib/esm/adapter-express/micro-api/application-express-micro-route.js +128 -0
  148. package/lib/esm/adapter-express/micro-api/application-express-micro.js +161 -0
  149. package/lib/esm/adapter-express/micro-api/gateway/circuit-breaker.js +174 -0
  150. package/lib/esm/adapter-express/micro-api/gateway/index.js +5 -0
  151. package/lib/esm/adapter-express/micro-api/gateway/service-proxy.js +210 -0
  152. package/lib/esm/adapter-express/micro-api/index.js +10 -0
  153. package/lib/esm/adapter-express/micro-api/micro.js +211 -0
  154. package/lib/esm/adapter-express/micro-api/queue/index.js +4 -0
  155. package/lib/esm/adapter-express/micro-api/queue/queue.interface.js +1 -0
  156. package/lib/esm/adapter-express/micro-api/queue/rabbitmq-consumer.js +229 -0
  157. package/lib/esm/adapter-express/micro-api/serverless/aws-lambda.adapter.js +180 -0
  158. package/lib/esm/adapter-express/micro-api/serverless/cloudflare.adapter.js +155 -0
  159. package/lib/esm/adapter-express/micro-api/serverless/index.js +6 -0
  160. package/lib/esm/adapter-express/micro-api/serverless/vercel.adapter.js +99 -0
  161. package/lib/esm/adapter-express/micro-api/service-mesh/index.js +5 -0
  162. package/lib/esm/adapter-express/micro-api/service-mesh/service-client.js +191 -0
  163. package/lib/esm/adapter-express/micro-api/service-mesh/service-discovery.js +259 -0
  164. package/lib/esm/adapter-express/middleware/index.js +5 -0
  165. package/lib/esm/adapter-express/middleware/request-logging.middleware.js +239 -0
  166. package/lib/esm/adapter-express/render/constants.js +37 -0
  167. package/lib/esm/adapter-express/render/engine.js +51 -0
  168. package/lib/esm/adapter-express/render/index.js +1 -0
  169. package/lib/esm/adapter-express/render/resolve-render.js +30 -0
  170. package/lib/esm/adapter-express/studio/index.js +1 -0
  171. package/lib/esm/adapter-express/studio/studio-integration.js +184 -0
  172. package/lib/esm/index.mjs +1 -0
  173. package/lib/esm/package.json +3 -0
  174. package/lib/esm/types/adapter-express/application-express.base.d.ts +77 -0
  175. package/lib/esm/types/adapter-express/application-express.d.ts +411 -0
  176. package/lib/esm/types/adapter-express/application-express.types.d.ts +23 -0
  177. package/lib/esm/types/adapter-express/express-utils/base-middleware.d.ts +8 -0
  178. package/lib/esm/types/adapter-express/express-utils/conditional-middleware.d.ts +97 -0
  179. package/lib/esm/types/adapter-express/express-utils/constants.d.ts +57 -0
  180. package/lib/esm/types/adapter-express/express-utils/content/httpContent.d.ts +6 -0
  181. package/lib/esm/types/adapter-express/express-utils/content-negotiation-decorators.d.ts +94 -0
  182. package/lib/esm/types/adapter-express/express-utils/decorators.d.ts +257 -0
  183. package/lib/esm/types/adapter-express/express-utils/exception-filter-decorators.d.ts +6 -0
  184. package/lib/esm/types/adapter-express/express-utils/guard-context-factory.d.ts +17 -0
  185. package/lib/esm/types/adapter-express/express-utils/guard-middleware.d.ts +22 -0
  186. package/lib/esm/types/adapter-express/express-utils/guard-utils.d.ts +11 -0
  187. package/lib/esm/types/adapter-express/express-utils/http-context-store.d.ts +20 -0
  188. package/lib/esm/types/adapter-express/express-utils/http-status-middleware.d.ts +26 -0
  189. package/lib/esm/types/adapter-express/express-utils/httpResponseMessage.d.ts +14 -0
  190. package/lib/esm/types/adapter-express/express-utils/index.d.ts +30 -0
  191. package/lib/esm/types/adapter-express/express-utils/interceptor-middleware.d.ts +40 -0
  192. package/lib/esm/types/adapter-express/express-utils/interfaces.d.ts +115 -0
  193. package/lib/esm/types/adapter-express/express-utils/inversify-express-server.d.ts +172 -0
  194. package/lib/esm/types/adapter-express/express-utils/lazy-module-middleware.d.ts +122 -0
  195. package/lib/esm/types/adapter-express/express-utils/middleware-composition.d.ts +85 -0
  196. package/lib/esm/types/adapter-express/express-utils/permission-preloader.middleware.d.ts +10 -0
  197. package/lib/esm/types/adapter-express/express-utils/resolver-multer.d.ts +7 -0
  198. package/lib/esm/types/adapter-express/express-utils/route-constraints.d.ts +89 -0
  199. package/lib/esm/types/adapter-express/express-utils/scope-extractor.d.ts +21 -0
  200. package/lib/esm/types/adapter-express/express-utils/scope-extractor.interface.d.ts +12 -0
  201. package/lib/esm/types/adapter-express/express-utils/setup-authorization.d.ts +34 -0
  202. package/lib/esm/types/adapter-express/express-utils/setup-event-system.d.ts +118 -0
  203. package/lib/esm/types/adapter-express/express-utils/setup-interceptors.d.ts +115 -0
  204. package/lib/esm/types/adapter-express/express-utils/setup-lazy-loading.d.ts +123 -0
  205. package/lib/esm/types/adapter-express/express-utils/utils.d.ts +24 -0
  206. package/lib/esm/types/adapter-express/express-utils/validation-decorators.d.ts +145 -0
  207. package/lib/esm/types/adapter-express/express-utils/validation-service.d.ts +88 -0
  208. package/lib/esm/types/adapter-express/index.d.ts +7 -0
  209. package/lib/esm/types/adapter-express/micro-api/application-express-micro-container.d.ts +47 -0
  210. package/lib/esm/types/adapter-express/micro-api/application-express-micro-route.d.ts +104 -0
  211. package/lib/esm/types/adapter-express/micro-api/application-express-micro.d.ts +72 -0
  212. package/lib/esm/types/adapter-express/micro-api/gateway/circuit-breaker.d.ts +111 -0
  213. package/lib/esm/types/adapter-express/micro-api/gateway/index.d.ts +5 -0
  214. package/lib/esm/types/adapter-express/micro-api/gateway/service-proxy.d.ts +83 -0
  215. package/lib/esm/types/adapter-express/micro-api/index.d.ts +7 -0
  216. package/lib/esm/types/adapter-express/micro-api/micro.d.ts +66 -0
  217. package/lib/esm/types/adapter-express/micro-api/queue/index.d.ts +5 -0
  218. package/lib/esm/types/adapter-express/micro-api/queue/queue.interface.d.ts +60 -0
  219. package/lib/esm/types/adapter-express/micro-api/queue/rabbitmq-consumer.d.ts +86 -0
  220. package/lib/esm/types/adapter-express/micro-api/serverless/aws-lambda.adapter.d.ts +77 -0
  221. package/lib/esm/types/adapter-express/micro-api/serverless/cloudflare.adapter.d.ts +64 -0
  222. package/lib/esm/types/adapter-express/micro-api/serverless/index.d.ts +6 -0
  223. package/lib/esm/types/adapter-express/micro-api/serverless/vercel.adapter.d.ts +56 -0
  224. package/lib/esm/types/adapter-express/micro-api/service-mesh/index.d.ts +5 -0
  225. package/lib/esm/types/adapter-express/micro-api/service-mesh/service-client.d.ts +122 -0
  226. package/lib/esm/types/adapter-express/micro-api/service-mesh/service-discovery.d.ts +150 -0
  227. package/lib/esm/types/adapter-express/middleware/index.d.ts +5 -0
  228. package/lib/esm/types/adapter-express/middleware/request-logging.middleware.d.ts +65 -0
  229. package/lib/esm/types/adapter-express/render/constants.d.ts +26 -0
  230. package/lib/esm/types/adapter-express/render/engine.d.ts +20 -0
  231. package/lib/esm/types/adapter-express/render/index.d.ts +5 -0
  232. package/lib/esm/types/adapter-express/render/resolve-render.d.ts +7 -0
  233. package/lib/esm/types/adapter-express/studio/index.d.ts +1 -0
  234. package/lib/esm/types/adapter-express/studio/studio-integration.d.ts +92 -0
  235. package/lib/esm/types/index.d.ts +1 -0
  236. package/lib/package.json +156 -146
  237. package/package.json +156 -146
  238. package/lib/cjs/di/di.interfaces.js +0 -10
  239. package/lib/cjs/types/di/di.interfaces.d.ts +0 -289
@@ -0,0 +1,259 @@
1
+ /**
2
+ * ServiceDiscovery - Service discovery for microservices.
3
+ *
4
+ * Features:
5
+ * - Static service registration
6
+ * - Consul integration
7
+ * - etcd integration
8
+ * - Automatic service refresh
9
+ * - Round-robin load balancing
10
+ * - Health-based filtering
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // Static service discovery
15
+ * const discovery = new ServiceDiscovery({ type: "static" });
16
+ *
17
+ * discovery.registerService({
18
+ * id: "user-service-1",
19
+ * name: "user-service",
20
+ * host: "user-service",
21
+ * port: 3001,
22
+ * health: "healthy",
23
+ * lastCheck: new Date(),
24
+ * });
25
+ *
26
+ * // Get a healthy instance
27
+ * const instance = discovery.getService("user-service");
28
+ * const client = new ServiceClient({
29
+ * name: "user-service",
30
+ * baseUrl: `http://${instance.host}:${instance.port}`,
31
+ * });
32
+ *
33
+ * // Or with Consul
34
+ * const discovery = new ServiceDiscovery({
35
+ * type: "consul",
36
+ * endpoint: "http://consul:8500",
37
+ * });
38
+ * await discovery.initialize();
39
+ * ```
40
+ */
41
+ export class ServiceDiscovery {
42
+ services = new Map();
43
+ roundRobinIndex = new Map();
44
+ refreshTimer;
45
+ config;
46
+ constructor(config) {
47
+ this.config = {
48
+ type: config.type,
49
+ endpoint: config.endpoint ?? "",
50
+ refreshInterval: config.refreshInterval ?? 30000,
51
+ debug: config.debug ?? false,
52
+ };
53
+ }
54
+ /**
55
+ * Initialize the service discovery
56
+ * For consul/etcd, this starts the refresh loop
57
+ */
58
+ async initialize() {
59
+ if (this.config.type === "static") {
60
+ // Static configuration - no auto-discovery
61
+ return;
62
+ }
63
+ // Initial refresh
64
+ await this.refresh();
65
+ // Start refresh loop
66
+ if (this.config.refreshInterval > 0) {
67
+ this.refreshTimer = setInterval(() => this.refresh(), this.config.refreshInterval);
68
+ }
69
+ }
70
+ /**
71
+ * Register a service instance (for static mode)
72
+ * @param service - Service instance to register
73
+ */
74
+ registerService(service) {
75
+ const instances = this.services.get(service.name) || [];
76
+ // Check if instance already exists
77
+ const existingIndex = instances.findIndex((i) => i.id === service.id);
78
+ if (existingIndex >= 0) {
79
+ instances[existingIndex] = service;
80
+ }
81
+ else {
82
+ instances.push(service);
83
+ }
84
+ this.services.set(service.name, instances);
85
+ if (this.config.debug) {
86
+ console.log(`[ServiceDiscovery] Registered ${service.name} (${service.id})`);
87
+ }
88
+ }
89
+ /**
90
+ * Deregister a service instance
91
+ * @param serviceName - Service name
92
+ * @param instanceId - Instance ID to remove
93
+ */
94
+ deregisterService(serviceName, instanceId) {
95
+ const instances = this.services.get(serviceName);
96
+ if (!instances)
97
+ return;
98
+ const filtered = instances.filter((i) => i.id !== instanceId);
99
+ this.services.set(serviceName, filtered);
100
+ if (this.config.debug) {
101
+ console.log(`[ServiceDiscovery] Deregistered ${serviceName} (${instanceId})`);
102
+ }
103
+ }
104
+ /**
105
+ * Get a healthy instance of a service (round-robin)
106
+ * @param name - Service name
107
+ * @returns A healthy service instance or null
108
+ */
109
+ getService(name) {
110
+ const instances = this.services.get(name);
111
+ if (!instances || instances.length === 0) {
112
+ return null;
113
+ }
114
+ // Filter to healthy instances only
115
+ const healthy = instances.filter((i) => i.health === "healthy");
116
+ if (healthy.length === 0) {
117
+ return null;
118
+ }
119
+ // Round-robin selection
120
+ const currentIndex = this.roundRobinIndex.get(name) ?? 0;
121
+ const instance = healthy[currentIndex % healthy.length];
122
+ this.roundRobinIndex.set(name, currentIndex + 1);
123
+ return instance;
124
+ }
125
+ /**
126
+ * Get all instances of a service
127
+ * @param name - Service name
128
+ * @param healthyOnly - Only return healthy instances (default: true)
129
+ */
130
+ getServiceInstances(name, healthyOnly = true) {
131
+ const instances = this.services.get(name) || [];
132
+ if (healthyOnly) {
133
+ return instances.filter((i) => i.health === "healthy");
134
+ }
135
+ return instances;
136
+ }
137
+ /**
138
+ * Get all registered services
139
+ */
140
+ getAllServices() {
141
+ return new Map(this.services);
142
+ }
143
+ /**
144
+ * List all registered service names
145
+ */
146
+ listServices() {
147
+ return Array.from(this.services.keys());
148
+ }
149
+ /**
150
+ * Update health status of a service instance
151
+ * @param serviceName - Service name
152
+ * @param instanceId - Instance ID
153
+ * @param health - New health status
154
+ */
155
+ updateHealth(serviceName, instanceId, health) {
156
+ const instances = this.services.get(serviceName);
157
+ if (!instances)
158
+ return false;
159
+ const instance = instances.find((i) => i.id === instanceId);
160
+ if (!instance)
161
+ return false;
162
+ instance.health = health;
163
+ instance.lastCheck = new Date();
164
+ if (this.config.debug) {
165
+ console.log(`[ServiceDiscovery] Updated ${serviceName} (${instanceId}) health to ${health}`);
166
+ }
167
+ return true;
168
+ }
169
+ /**
170
+ * Get service statistics
171
+ */
172
+ getStats() {
173
+ const stats = {};
174
+ for (const [name, instances] of this.services) {
175
+ stats[name] = {
176
+ total: instances.length,
177
+ healthy: instances.filter((i) => i.health === "healthy").length,
178
+ unhealthy: instances.filter((i) => i.health === "unhealthy").length,
179
+ };
180
+ }
181
+ return stats;
182
+ }
183
+ /**
184
+ * Stop the service discovery
185
+ */
186
+ stop() {
187
+ if (this.refreshTimer) {
188
+ clearInterval(this.refreshTimer);
189
+ this.refreshTimer = undefined;
190
+ }
191
+ }
192
+ /**
193
+ * Refresh service list from discovery backend
194
+ */
195
+ async refresh() {
196
+ try {
197
+ if (this.config.type === "consul") {
198
+ await this.refreshFromConsul();
199
+ }
200
+ else if (this.config.type === "etcd") {
201
+ await this.refreshFromEtcd();
202
+ }
203
+ }
204
+ catch (error) {
205
+ console.error("[ServiceDiscovery] Refresh failed:", error);
206
+ }
207
+ }
208
+ /**
209
+ * Refresh from Consul
210
+ */
211
+ async refreshFromConsul() {
212
+ if (!this.config.endpoint) {
213
+ throw new Error("Consul endpoint not configured");
214
+ }
215
+ try {
216
+ // Get list of services
217
+ const servicesResponse = await fetch(`${this.config.endpoint}/v1/catalog/services`);
218
+ const services = await servicesResponse.json();
219
+ // Get instances for each service
220
+ for (const serviceName of Object.keys(services)) {
221
+ const instances = await this.getConsulInstances(serviceName);
222
+ this.services.set(serviceName, instances);
223
+ }
224
+ if (this.config.debug) {
225
+ console.log(`[ServiceDiscovery] Refreshed ${this.services.size} services from Consul`);
226
+ }
227
+ }
228
+ catch (error) {
229
+ console.error("[ServiceDiscovery] Consul refresh failed:", error);
230
+ throw error;
231
+ }
232
+ }
233
+ /**
234
+ * Get instances from Consul for a specific service
235
+ */
236
+ async getConsulInstances(serviceName) {
237
+ const response = await fetch(`${this.config.endpoint}/v1/health/service/${serviceName}?passing=true`);
238
+ const data = (await response.json());
239
+ return data.map((entry) => ({
240
+ id: entry.Service.ID,
241
+ name: entry.Service.Service,
242
+ host: entry.Service.Address || entry.Node.Address,
243
+ port: entry.Service.Port,
244
+ metadata: entry.Service.Meta,
245
+ health: "healthy",
246
+ lastCheck: new Date(),
247
+ }));
248
+ }
249
+ /**
250
+ * Refresh from etcd
251
+ */
252
+ async refreshFromEtcd() {
253
+ if (!this.config.endpoint) {
254
+ throw new Error("etcd endpoint not configured");
255
+ }
256
+ // etcd v3 API implementation
257
+ console.log("[ServiceDiscovery] etcd integration requires etcd3 client library");
258
+ }
259
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @file middleware/index.ts
3
+ * @description Exports for ExpressoTS middleware
4
+ */
5
+ export * from "./request-logging.middleware.js";
@@ -0,0 +1,239 @@
1
+ /**
2
+ * @file request-logging.middleware.ts
3
+ * @description HTTP request/response logging middleware with context enrichment
4
+ * @module @expressots/adapter-express
5
+ *
6
+ * Features:
7
+ * - Request ID generation/extraction
8
+ * - Request/response timing
9
+ * - Slow request detection
10
+ * - Configurable verbosity levels
11
+ * - Body logging with redaction support
12
+ */
13
+ import { ContextManager, getFlowTracker, removeFlowTracker, } from "@expressots/core";
14
+ /**
15
+ * Default request logging configuration.
16
+ */
17
+ export function getDefaultRequestLoggingConfig() {
18
+ return {
19
+ verbosity: "normal",
20
+ logBody: false,
21
+ logHeaders: false,
22
+ logResponseBody: false,
23
+ slowRequestThreshold: 1000, // 1 second
24
+ skipPatterns: [/^\/health$/, /^\/ready$/, /^\/live$/, /^\/_health$/],
25
+ requestIdHeader: "x-request-id",
26
+ correlationIdHeader: "x-correlation-id",
27
+ logUserAgent: true,
28
+ logIp: true,
29
+ };
30
+ }
31
+ /**
32
+ * Create request logging middleware.
33
+ * @param logger - Logger instance to use
34
+ * @param config - Optional configuration
35
+ * @returns Express middleware function
36
+ * @public API
37
+ */
38
+ export function createRequestLoggingMiddleware(logger, config) {
39
+ const finalConfig = {
40
+ ...getDefaultRequestLoggingConfig(),
41
+ ...config,
42
+ };
43
+ return (req, res, next) => {
44
+ // Skip logging for configured patterns
45
+ if (finalConfig.skipPatterns.some((pattern) => pattern.test(req.path))) {
46
+ next();
47
+ return;
48
+ }
49
+ // Create HTTP context with custom header names
50
+ const httpContext = ContextManager.createHttpContext(req, {
51
+ requestIdHeader: finalConfig.requestIdHeader,
52
+ correlationIdHeader: finalConfig.correlationIdHeader,
53
+ });
54
+ // Set request/correlation ID headers for downstream services
55
+ res.setHeader(finalConfig.requestIdHeader, httpContext.requestId);
56
+ if (httpContext.correlationId) {
57
+ res.setHeader(finalConfig.correlationIdHeader, httpContext.correlationId);
58
+ }
59
+ // Create log context
60
+ const logContext = {
61
+ requestId: httpContext.requestId,
62
+ userId: httpContext.userId,
63
+ tenantId: httpContext.tenantId,
64
+ metadata: {
65
+ method: httpContext.method,
66
+ path: httpContext.path,
67
+ },
68
+ };
69
+ // Initialize flow tracker (if flow tracking is enabled)
70
+ const flowConfig = logger.getConfig()?.flow;
71
+ const flowTracker = getFlowTracker(httpContext.requestId, httpContext.method, httpContext.path, flowConfig);
72
+ // Log request start based on verbosity
73
+ logRequestStart(logger, httpContext, finalConfig);
74
+ // Capture response timing
75
+ const startTime = Date.now();
76
+ const startMemory = process.memoryUsage().heapUsed;
77
+ // Store error on request for later retrieval
78
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
79
+ req.__expressotsFlowError = undefined;
80
+ // Override res.end to capture response
81
+ const originalEnd = res.end;
82
+ let endCalled = false;
83
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
+ res.end = function (...args) {
85
+ // Prevent multiple calls
86
+ if (endCalled) {
87
+ return originalEnd.apply(this, args);
88
+ }
89
+ endCalled = true;
90
+ const duration = Date.now() - startTime;
91
+ const memoryDelta = process.memoryUsage().heapUsed - startMemory;
92
+ // Get error from request if available (set by controllers, guards, or error handlers)
93
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ const error = req.__expressotsFlowError;
95
+ // Finalize flow and get flow data (pass error if available)
96
+ const flow = flowTracker.finalize(res.statusCode, error);
97
+ // Log response with flow data
98
+ logRequestEnd(logger, httpContext, res, duration, memoryDelta, finalConfig, flow);
99
+ // Cleanup flow tracker
100
+ removeFlowTracker(httpContext.requestId);
101
+ // Call original end
102
+ return originalEnd.apply(this, args);
103
+ };
104
+ // Wrap next to capture errors passed to next()
105
+ const wrappedNext = (err) => {
106
+ if (err) {
107
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
108
+ req.__expressotsFlowError = err instanceof Error ? err : new Error(String(err));
109
+ }
110
+ next(err);
111
+ };
112
+ // Also hook into res.status() to capture error status codes
113
+ // This helps capture errors that Express error handlers set
114
+ const originalStatus = res.status.bind(res);
115
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
116
+ res.status = function (code) {
117
+ // If status is >= 400 and no error is stored yet, try to get it from Express error handling
118
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
119
+ if (code >= 400 && !req.__expressotsFlowError) {
120
+ // Check if there's an error in the response locals (Express error handlers sometimes put it there)
121
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
122
+ const errorFromLocals = res.locals?.error;
123
+ if (errorFromLocals) {
124
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
125
+ req.__expressotsFlowError =
126
+ errorFromLocals instanceof Error ? errorFromLocals : new Error(String(errorFromLocals));
127
+ }
128
+ }
129
+ return originalStatus(code);
130
+ };
131
+ // Run the rest of the middleware chain with context
132
+ ContextManager.runWithContext(logContext, () => {
133
+ wrappedNext();
134
+ });
135
+ };
136
+ }
137
+ /**
138
+ * Log request start.
139
+ */
140
+ function logRequestStart(logger, context, config) {
141
+ const { verbosity, logHeaders, logUserAgent, logIp } = config;
142
+ if (verbosity === "minimal") {
143
+ // Minimal: Just log that request started
144
+ logger.debug(`→ ${context.method} ${context.path}`, { requestId: context.requestId });
145
+ return;
146
+ }
147
+ // Build log data based on verbosity
148
+ const logData = {
149
+ requestId: context.requestId,
150
+ };
151
+ if (logIp && context.ip) {
152
+ logData.ip = context.ip;
153
+ }
154
+ if (logUserAgent && context.userAgent) {
155
+ logData.userAgent =
156
+ context.userAgent.length > 50
157
+ ? context.userAgent.substring(0, 50) + "..."
158
+ : context.userAgent;
159
+ }
160
+ if (context.userId) {
161
+ logData.userId = context.userId;
162
+ }
163
+ if (context.tenantId) {
164
+ logData.tenantId = context.tenantId;
165
+ }
166
+ if (verbosity === "detailed" || verbosity === "debug") {
167
+ if (logHeaders && context.headers) {
168
+ logData.headers = context.headers;
169
+ }
170
+ }
171
+ logger.info(`→ ${context.method} ${context.path}`, "request", logData);
172
+ }
173
+ /**
174
+ * Log request end.
175
+ */
176
+ function logRequestEnd(logger, context, res, duration, memoryDelta, config, flow) {
177
+ const { verbosity, slowRequestThreshold } = config;
178
+ const statusCode = res.statusCode;
179
+ // Determine log level based on status and duration
180
+ const isSlowRequest = duration >= slowRequestThreshold;
181
+ const isError = statusCode >= 400;
182
+ // Build log data
183
+ const logData = {
184
+ requestId: context.requestId,
185
+ status: statusCode,
186
+ duration: `${duration}ms`,
187
+ };
188
+ if (verbosity === "detailed" || verbosity === "debug") {
189
+ logData.memoryDelta = `${(memoryDelta / 1024).toFixed(1)}KB`;
190
+ }
191
+ if (context.userId) {
192
+ logData.userId = context.userId;
193
+ }
194
+ // Format message
195
+ const statusEmoji = isError ? "✗" : "✓";
196
+ const message = `← ${context.method} ${context.path} ${statusCode} ${statusEmoji} ${duration}ms`;
197
+ // Log with appropriate level and include flow data if available
198
+ if (isError && statusCode >= 500) {
199
+ logger.error(message, "request", { ...logData, flow });
200
+ }
201
+ else if (isError) {
202
+ logger.warn(message, "request", { ...logData, flow });
203
+ }
204
+ else if (isSlowRequest) {
205
+ logger.warn(`[SLOW] ${message}`, "request", {
206
+ ...logData,
207
+ slowRequestThreshold: `${slowRequestThreshold}ms`,
208
+ flow,
209
+ });
210
+ }
211
+ else if (verbosity !== "minimal") {
212
+ logger.info(message, "request", { ...logData, flow });
213
+ }
214
+ else {
215
+ // debug only takes 2 args: message and data
216
+ logger.debug(`[request] ${message}`, { ...logData, flow });
217
+ }
218
+ }
219
+ /**
220
+ * Express middleware that assigns a request ID to each request.
221
+ * Simpler alternative to full request logging.
222
+ * @param headerName - Header name for request ID (default: x-request-id)
223
+ * @returns Express middleware
224
+ * @public API
225
+ */
226
+ export function requestIdMiddleware(headerName = "x-request-id") {
227
+ return (req, res, next) => {
228
+ const existingId = req.headers[headerName.toLowerCase()];
229
+ const requestId = existingId || ContextManager.generateRequestId();
230
+ // Set on request for access by other middleware
231
+ req.requestId = requestId;
232
+ // Set on response header
233
+ res.setHeader(headerName, requestId);
234
+ // Run with context
235
+ ContextManager.runWithContext({ requestId }, () => {
236
+ next();
237
+ });
238
+ };
239
+ }
@@ -0,0 +1,37 @@
1
+ import { join } from "path";
2
+ /**
3
+ * Ejs defaults
4
+ * @type {EjsOptions}
5
+ * @constant
6
+ * @default
7
+ */
8
+ export const EJS_DEFAULTS = {
9
+ viewsDir: join(process.cwd(), "views"),
10
+ viewEngine: "ejs",
11
+ serverOptions: {},
12
+ };
13
+ /**
14
+ * Handlebars defaults
15
+ * @type {HandlebarsOptions}
16
+ * @constant
17
+ * @default
18
+ */
19
+ export const HANDLEBARS_DEFAULTS = {
20
+ viewEngine: "hbs",
21
+ viewsDir: join(process.cwd(), "views"),
22
+ partialsDir: join(process.cwd(), "views/partials"),
23
+ };
24
+ /**
25
+ * Default partials directory
26
+ */
27
+ export const DEFAULT_PARTIALS_DIR = join(process.cwd(), "views/partials");
28
+ /**
29
+ * Pug defaults
30
+ * @type {PugOptions}
31
+ * @constant
32
+ * @default
33
+ */
34
+ export const PUG_DEFAULTS = {
35
+ viewEngine: "pug",
36
+ viewsDir: join(process.cwd(), "views"),
37
+ };
@@ -0,0 +1,51 @@
1
+ import { Logger } from "@expressots/core";
2
+ import { packageResolver } from "./resolve-render.js";
3
+ import { DEFAULT_PARTIALS_DIR, EJS_DEFAULTS, HANDLEBARS_DEFAULTS, PUG_DEFAULTS, } from "./constants.js";
4
+ /**
5
+ * Set Ejs as the view engine
6
+ * @param {Application} app - The express application
7
+ * @param {EjsOptions} [options=EJS_DEFAULTS] - The ejs options
8
+ */
9
+ export async function setEngineEjs(app, options = EJS_DEFAULTS) {
10
+ packageResolver("ejs");
11
+ app.set("view engine", options.viewEngine || EJS_DEFAULTS.viewEngine);
12
+ app.set("views", options.viewsDir || EJS_DEFAULTS.viewsDir);
13
+ if (Array.isArray(options.viewsDir)) {
14
+ options.viewsDir.forEach((dir) => {
15
+ app.set("views", dir);
16
+ });
17
+ }
18
+ if (options.serverOptions) {
19
+ app.locals = {
20
+ ...app.locals,
21
+ ...options.serverOptions,
22
+ };
23
+ }
24
+ }
25
+ /**
26
+ * Set Handlebars as the view engine
27
+ * @param {express.Application} app - The express application
28
+ * @param {HandlebarsOptions} [options=HANDLEBARS_DEFAULTS] - The handlebars options
29
+ */
30
+ export async function setEngineHandlebars(app, options = HANDLEBARS_DEFAULTS) {
31
+ const logger = new Logger();
32
+ try {
33
+ const hbs = packageResolver("hbs");
34
+ hbs.registerPartials(options.partialsDir || DEFAULT_PARTIALS_DIR);
35
+ app.set("view engine", options.viewEngine || HANDLEBARS_DEFAULTS.viewEngine);
36
+ app.set("views", options.viewsDir || HANDLEBARS_DEFAULTS.viewsDir);
37
+ }
38
+ catch (error) {
39
+ logger.error(error.message, "handlebars-config");
40
+ }
41
+ }
42
+ /**
43
+ * Set Pug as the view engine
44
+ * @param {express.Application} app - The express application
45
+ * @param {PugOptions} [options=PUG_DEFAULTS] - The pug options
46
+ */
47
+ export async function setEnginePug(app, options = PUG_DEFAULTS) {
48
+ packageResolver("pug");
49
+ app.set("view engine", options.viewEngine || PUG_DEFAULTS.viewEngine);
50
+ app.set("views", options.viewsDir || PUG_DEFAULTS.viewsDir);
51
+ }
@@ -0,0 +1 @@
1
+ export { setEngineEjs, setEngineHandlebars, setEnginePug } from "./engine.js";
@@ -0,0 +1,30 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { Logger } from "@expressots/core";
3
+ /**
4
+ * Resolve package from the current working directory.
5
+ * @param packageName
6
+ * @param options
7
+ * @returns
8
+ */
9
+ export function packageResolver(packageName, ...options) {
10
+ const logger = new Logger();
11
+ try {
12
+ const hasPackage = require.resolve(packageName, {
13
+ paths: [process.cwd()],
14
+ });
15
+ if (hasPackage) {
16
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
17
+ const packageResolved = require(hasPackage);
18
+ if (typeof packageResolved === "function") {
19
+ return packageResolved(...options);
20
+ }
21
+ if (packageResolved.default && typeof packageResolved.default === "function") {
22
+ return packageResolved.default(...options);
23
+ }
24
+ return packageResolved;
25
+ }
26
+ }
27
+ catch (error) {
28
+ logger.warn(`Package [${packageName}] not installed. Please install it using your package manager.`, "package-resolver");
29
+ }
30
+ }
@@ -0,0 +1 @@
1
+ export { initializeStudio, stopStudio, isStudioEnabled, getStudioAgent, reportStudioRuntimeInfo, } from "./studio-integration.js";