@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,211 @@
1
+ import { Console, Logger, getRouteRegistry, getErrorHints, getDefaultSuggestionsConfig, formatSuggestions, } from "@expressots/core";
2
+ import express from "express";
3
+ import { AppExpress } from "../application-express.js";
4
+ /**
5
+ * Create a new micro API instance
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const app = micro();
10
+ * app.get("/", () => "Hello World");
11
+ * app.listen(3000);
12
+ * ```
13
+ *
14
+ * @param config - Optional configuration
15
+ * @returns MicroApp instance
16
+ * @public API
17
+ */
18
+ export function micro(config) {
19
+ // Disable the log buffering from AppExpress since micro() doesn't use the banner system
20
+ // This restores normal console output for micro API users
21
+ AppExpress.disableBuffering();
22
+ const app = express();
23
+ const logger = new Logger();
24
+ const console = new Console();
25
+ const globalPrefix = config?.globalPrefix?.replace(/\/$/, "") || "";
26
+ let httpServer;
27
+ let errorHandler = null;
28
+ // Auto-enable JSON parsing by default
29
+ if (config?.autoParseJson !== false) {
30
+ app.use(express.json());
31
+ app.use(express.urlencoded({ extended: true }));
32
+ }
33
+ /**
34
+ * Wrap handler to auto-send return values
35
+ */
36
+ const wrapHandler = (handler) => {
37
+ return async (req, res, next) => {
38
+ try {
39
+ const result = await handler(req, res, next);
40
+ // If response already sent, don't send again
41
+ if (res.headersSent) {
42
+ return;
43
+ }
44
+ // Auto-send return values
45
+ if (result !== undefined) {
46
+ if (typeof result === "string") {
47
+ res.send(result);
48
+ }
49
+ else {
50
+ res.json(result);
51
+ }
52
+ }
53
+ }
54
+ catch (error) {
55
+ next(error);
56
+ }
57
+ };
58
+ };
59
+ /**
60
+ * Register a route with Express-style middleware ordering
61
+ */
62
+ const route = (method, path, ...handlers) => {
63
+ const fullPath = `${globalPrefix}${path.startsWith("/") ? path : `/${path}`}`;
64
+ const handler = handlers.pop();
65
+ const middleware = handlers;
66
+ app[method](fullPath, ...middleware, wrapHandler(handler));
67
+ logger.info(`Route ${method.toUpperCase()} '${fullPath}' registered`, "micro");
68
+ // Register in the suggestions engine so 404s can produce "Did you mean ...?"
69
+ try {
70
+ getRouteRegistry().register(method.toUpperCase(), fullPath, fullPath);
71
+ }
72
+ catch {
73
+ // Suggestions registry is optional; never fail registration because of it.
74
+ }
75
+ return microApp;
76
+ };
77
+ /**
78
+ * Install a catch-all 404 fallback that mirrors the behavior of the full
79
+ * inversify-express-server: log "Did you mean ...?" via the framework Logger
80
+ * and respond with a structured RFC-7807-style JSON body.
81
+ *
82
+ * Skipped entirely when the suggestion engine is disabled (the env-aware
83
+ * default disables it in NODE_ENV=production).
84
+ */
85
+ const installNotFoundHandler = () => {
86
+ app.use((req, res, next) => {
87
+ if (res.headersSent) {
88
+ return next();
89
+ }
90
+ const suggestionsConfig = getDefaultSuggestionsConfig();
91
+ if (!suggestionsConfig.enabled) {
92
+ return next();
93
+ }
94
+ const requestedPath = req.originalUrl || req.url;
95
+ const requestedMethod = req.method;
96
+ const hints = getErrorHints(new Error(`Route '${requestedMethod} ${requestedPath}' not found`), {
97
+ path: requestedPath,
98
+ method: requestedMethod,
99
+ statusCode: 404,
100
+ }, suggestionsConfig);
101
+ if (hints.length > 0) {
102
+ try {
103
+ const formatted = formatSuggestions(hints);
104
+ if (formatted) {
105
+ logger.warn(`Route not found: ${requestedMethod} ${requestedPath}${formatted}`, "router-404");
106
+ }
107
+ }
108
+ catch {
109
+ // best-effort logging
110
+ }
111
+ }
112
+ const routeSuggestion = hints.find((hint) => hint.type === "route");
113
+ const actionHint = hints.find((hint) => hint.type === "hint");
114
+ const body = {
115
+ type: "https://expressots.dev/errors/not-found",
116
+ title: "Route Not Found",
117
+ status: 404,
118
+ detail: `Route '${requestedMethod} ${requestedPath}' does not exist`,
119
+ instance: requestedPath,
120
+ timestamp: new Date().toISOString(),
121
+ };
122
+ if (routeSuggestion?.routes && routeSuggestion.routes.length > 0) {
123
+ body.suggestions = routeSuggestion.routes.map((suggestion) => ({
124
+ method: suggestion.route.method,
125
+ path: suggestion.route.fullPath || suggestion.route.path,
126
+ similarity: Math.round(suggestion.similarity * 100),
127
+ reason: suggestion.reason,
128
+ }));
129
+ }
130
+ else if (actionHint?.actions && actionHint.actions.length > 0) {
131
+ body.actions = actionHint.actions;
132
+ }
133
+ res.status(404).type("application/json").send(JSON.stringify(body));
134
+ });
135
+ };
136
+ /**
137
+ * Handle server shutdown gracefully
138
+ */
139
+ const handleExit = () => {
140
+ logger.info("Server shutting down", "micro");
141
+ process.exit(0);
142
+ };
143
+ const microApp = {
144
+ get: (path, ...handlers) => route("get", path, ...handlers),
145
+ post: (path, ...handlers) => route("post", path, ...handlers),
146
+ put: (path, ...handlers) => route("put", path, ...handlers),
147
+ patch: (path, ...handlers) => route("patch", path, ...handlers),
148
+ delete: (path, ...handlers) => route("delete", path, ...handlers),
149
+ use(...args) {
150
+ if (typeof args[0] === "string") {
151
+ app.use(args[0], ...args.slice(1));
152
+ }
153
+ else {
154
+ app.use(...args);
155
+ }
156
+ return microApp;
157
+ },
158
+ setErrorHandler(handler) {
159
+ errorHandler = handler;
160
+ return microApp;
161
+ },
162
+ async listen(port, appInfo) {
163
+ const normalizedPort = typeof port === "string" ? parseInt(port, 10) : port;
164
+ // Install the 404 fallback before the user error handler so unmatched
165
+ // routes get suggestions instead of falling through to the default
166
+ // Express HTML or - worse - to a regular middleware that arity-confused
167
+ // its way into running on every request.
168
+ installNotFoundHandler();
169
+ // Apply error handler last. Wrap it in a 4-arity function so that
170
+ // Express recognizes it as an error-handling middleware regardless of
171
+ // whether the user wrote `(err, req, res)` or `(err, req, res, next)`.
172
+ // Without this wrapper, Express would treat a 3-arg user handler as a
173
+ // regular middleware and run it on every request, which both swallows
174
+ // 404s and crashes when the user calls `res.status(...)` (positional
175
+ // `res` would actually be Express's `next`).
176
+ if (errorHandler) {
177
+ const userHandler = errorHandler;
178
+ const wrappedErrorHandler = (err, req, res, next) => userHandler(err, req, res, next);
179
+ app.use(wrappedErrorHandler);
180
+ }
181
+ return new Promise((resolve, reject) => {
182
+ httpServer = app.listen(normalizedPort, async () => {
183
+ const address = httpServer.address();
184
+ const actualPort = typeof address === "object" && address?.port ? address.port : normalizedPort;
185
+ if (config?.showBanner !== false) {
186
+ await console.messageServer(actualPort, "development", {
187
+ appName: appInfo?.appName || "ExpressoTS Micro",
188
+ appVersion: appInfo?.appVersion || "1.0.0",
189
+ });
190
+ }
191
+ // Handle graceful shutdown
192
+ ["SIGTERM", "SIGHUP", "SIGBREAK", "SIGQUIT", "SIGINT"].forEach((signal) => {
193
+ process.on(signal, handleExit);
194
+ });
195
+ resolve();
196
+ });
197
+ httpServer.on("error", (error) => {
198
+ logger.error(`Server error: ${error.message}`, "micro");
199
+ reject(error);
200
+ });
201
+ });
202
+ },
203
+ getHttpServer() {
204
+ return httpServer;
205
+ },
206
+ getApp() {
207
+ return app;
208
+ },
209
+ };
210
+ return microApp;
211
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Queue Integration for ExpressoTS Micro Template
3
+ */
4
+ export { RabbitMQConsumer } from "./rabbitmq-consumer.js";
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Load amqplib dynamically to avoid requiring it as a dependency
3
+ */
4
+ async function loadAmqpLib() {
5
+ try {
6
+ // `amqplib` is an OPTIONAL peer dep - it is intentionally not installed
7
+ // in this package's devDependencies. We route the specifier through a
8
+ // variable so TypeScript does not try to statically resolve it during
9
+ // build (TS treats variable-typed specifiers in `await import(...)` as
10
+ // `any` and skips the resolution check). Resolution happens at runtime
11
+ // in user apps that have actually installed amqplib.
12
+ const specifier = "amqplib";
13
+ const amqp = (await import(specifier));
14
+ return amqp;
15
+ }
16
+ catch {
17
+ throw new Error("amqplib is not installed. Install it with: npm install amqplib @types/amqplib");
18
+ }
19
+ }
20
+ /**
21
+ * RabbitMQ Consumer - Message queue consumer for RabbitMQ.
22
+ *
23
+ * Features:
24
+ * - Message consumption with handlers
25
+ * - Message publishing
26
+ * - Exchange support
27
+ * - Automatic reconnection
28
+ * - Prefetch control
29
+ * - Dead letter queue support
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * const orderQueue = new RabbitMQConsumer({
34
+ * url: process.env.RABBITMQ_URL,
35
+ * queue: "orders",
36
+ * prefetch: 10,
37
+ * });
38
+ *
39
+ * // Start consuming
40
+ * await orderQueue.consume(async (message) => {
41
+ * const order = message.body;
42
+ * console.log("Processing order:", order.id);
43
+ * await processOrder(order);
44
+ * });
45
+ *
46
+ * // Publish from HTTP endpoint
47
+ * app.Route.post("/orders", async (req, res) => {
48
+ * await orderQueue.publish(req.body);
49
+ * res.status(202).json({ message: "Order queued" });
50
+ * });
51
+ *
52
+ * // Graceful shutdown
53
+ * process.on("SIGTERM", async () => {
54
+ * await orderQueue.close();
55
+ * });
56
+ * ```
57
+ *
58
+ * Note: This implementation requires the 'amqplib' package.
59
+ * Install with: npm install amqplib @types/amqplib
60
+ */
61
+ export class RabbitMQConsumer {
62
+ // Using 'any' for AMQP types since amqplib is an optional peer dependency
63
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
64
+ connection = null;
65
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
66
+ channel = null;
67
+ config;
68
+ stats = {
69
+ messagesReceived: 0,
70
+ messagesProcessed: 0,
71
+ messagesFailed: 0,
72
+ messagesPublished: 0,
73
+ isConnected: false,
74
+ };
75
+ constructor(config) {
76
+ this.config = {
77
+ queue: config.queue,
78
+ url: config.url,
79
+ exchange: config.exchange ?? "",
80
+ exchangeType: config.exchangeType ?? "direct",
81
+ routingKey: config.routingKey ?? config.queue,
82
+ prefetch: config.prefetch ?? 1,
83
+ durable: config.durable ?? true,
84
+ concurrency: config.concurrency ?? 1,
85
+ autoAck: config.autoAck ?? true,
86
+ debug: config.debug ?? false,
87
+ };
88
+ }
89
+ /**
90
+ * Connect to RabbitMQ
91
+ */
92
+ async connect() {
93
+ if (this.connection)
94
+ return;
95
+ try {
96
+ const amqp = await loadAmqpLib();
97
+ this.connection = await amqp.connect(this.config.url);
98
+ this.channel = await this.connection.createChannel();
99
+ // Set prefetch
100
+ await this.channel.prefetch(this.config.prefetch);
101
+ // Declare queue
102
+ await this.channel.assertQueue(this.config.queue, {
103
+ durable: this.config.durable,
104
+ });
105
+ // Declare exchange if configured
106
+ if (this.config.exchange) {
107
+ await this.channel.assertExchange(this.config.exchange, this.config.exchangeType, {
108
+ durable: true,
109
+ });
110
+ // Bind queue to exchange
111
+ await this.channel.bindQueue(this.config.queue, this.config.exchange, this.config.routingKey);
112
+ }
113
+ this.stats.isConnected = true;
114
+ if (this.config.debug) {
115
+ console.log(`[RabbitMQ] Connected to ${this.config.url}, queue: ${this.config.queue}`);
116
+ }
117
+ // Handle connection close
118
+ this.connection.on("close", () => {
119
+ this.stats.isConnected = false;
120
+ console.log("[RabbitMQ] Connection closed");
121
+ });
122
+ this.connection.on("error", (err) => {
123
+ console.error("[RabbitMQ] Connection error:", err);
124
+ });
125
+ }
126
+ catch (error) {
127
+ console.error("[RabbitMQ] Failed to connect:", error);
128
+ throw error;
129
+ }
130
+ }
131
+ /**
132
+ * Start consuming messages
133
+ */
134
+ async consume(handler) {
135
+ await this.connect();
136
+ if (!this.channel) {
137
+ throw new Error("Channel not initialized");
138
+ }
139
+ await this.channel.consume(this.config.queue,
140
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
141
+ async (msg) => {
142
+ if (!msg)
143
+ return;
144
+ this.stats.messagesReceived++;
145
+ this.stats.lastMessageAt = new Date();
146
+ try {
147
+ // Parse message
148
+ const body = JSON.parse(msg.content.toString());
149
+ const queueMessage = {
150
+ id: msg.properties.messageId || Date.now().toString(36),
151
+ body,
152
+ headers: msg.properties.headers,
153
+ timestamp: new Date(msg.properties.timestamp || Date.now()),
154
+ receiveCount: msg.properties.headers?.["x-delivery-count"] || 1,
155
+ raw: msg,
156
+ };
157
+ if (this.config.debug) {
158
+ console.log(`[RabbitMQ] Received message:`, queueMessage.id);
159
+ }
160
+ // Process message
161
+ await handler(queueMessage);
162
+ this.stats.messagesProcessed++;
163
+ // Acknowledge
164
+ if (!this.config.autoAck && this.channel) {
165
+ this.channel.ack(msg);
166
+ }
167
+ }
168
+ catch (error) {
169
+ this.stats.messagesFailed++;
170
+ console.error("[RabbitMQ] Message processing failed:", error);
171
+ // Reject and requeue if not auto-ack
172
+ if (!this.config.autoAck && this.channel) {
173
+ this.channel.nack(msg, false, true);
174
+ }
175
+ }
176
+ }, { noAck: this.config.autoAck });
177
+ if (this.config.debug) {
178
+ console.log(`[RabbitMQ] Consuming from ${this.config.queue}`);
179
+ }
180
+ }
181
+ /**
182
+ * Publish a message to the queue
183
+ */
184
+ async publish(message) {
185
+ await this.connect();
186
+ if (!this.channel) {
187
+ throw new Error("Channel not initialized");
188
+ }
189
+ const content = Buffer.from(JSON.stringify(message));
190
+ const properties = {
191
+ messageId: Date.now().toString(36),
192
+ timestamp: Date.now(),
193
+ contentType: "application/json",
194
+ };
195
+ if (this.config.exchange) {
196
+ this.channel.publish(this.config.exchange, this.config.routingKey, content, properties);
197
+ }
198
+ else {
199
+ this.channel.sendToQueue(this.config.queue, content, properties);
200
+ }
201
+ this.stats.messagesPublished++;
202
+ if (this.config.debug) {
203
+ console.log(`[RabbitMQ] Published message to ${this.config.queue}`);
204
+ }
205
+ }
206
+ /**
207
+ * Close the connection
208
+ */
209
+ async close() {
210
+ if (this.channel) {
211
+ await this.channel.close();
212
+ this.channel = null;
213
+ }
214
+ if (this.connection) {
215
+ await this.connection.close();
216
+ this.connection = null;
217
+ }
218
+ this.stats.isConnected = false;
219
+ if (this.config.debug) {
220
+ console.log("[RabbitMQ] Connection closed");
221
+ }
222
+ }
223
+ /**
224
+ * Get consumer statistics
225
+ */
226
+ getStats() {
227
+ return { ...this.stats };
228
+ }
229
+ }
@@ -0,0 +1,180 @@
1
+ /**
2
+ * AWS Lambda Adapter for ExpressoTS Micro API
3
+ *
4
+ * Converts Lambda events to Express requests and responses.
5
+ */
6
+ /**
7
+ * Create an AWS Lambda handler from an Express app
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { createMicroAPI, awsLambdaAdapter } from "@expressots/adapter-express";
12
+ *
13
+ * const microAPI = createMicroAPI();
14
+ * const app = microAPI.build();
15
+ *
16
+ * app.Middleware.parse();
17
+ * app.Route.get("/", (req, res) => res.json({ message: "Hello Lambda!" }));
18
+ *
19
+ * export const handler = awsLambdaAdapter(app);
20
+ * ```
21
+ */
22
+ export function awsLambdaAdapter(app, config) {
23
+ const expressApp = "getExpressApp" in app && app.getExpressApp ? app.getExpressApp() : app;
24
+ const binaryTypes = config?.binaryContentTypes ?? [
25
+ "application/octet-stream",
26
+ "image/*",
27
+ "audio/*",
28
+ "video/*",
29
+ "font/*",
30
+ ];
31
+ const debug = config?.debug ?? false;
32
+ return async (event, context) => {
33
+ if (debug) {
34
+ console.log("[Lambda] Event:", JSON.stringify(event, null, 2));
35
+ }
36
+ // Parse body
37
+ let body;
38
+ if (event.body) {
39
+ let rawBody;
40
+ if (event.isBase64Encoded) {
41
+ rawBody = Buffer.from(event.body, "base64");
42
+ }
43
+ else {
44
+ rawBody = event.body;
45
+ }
46
+ // Parse JSON body if content-type is application/json
47
+ const contentType = event.headers?.["content-type"] || event.headers?.["Content-Type"] || "";
48
+ if (contentType.includes("application/json")) {
49
+ try {
50
+ const bodyStr = Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : rawBody;
51
+ body = JSON.parse(bodyStr);
52
+ }
53
+ catch {
54
+ // Keep as raw if JSON parsing fails
55
+ body = rawBody;
56
+ }
57
+ }
58
+ else {
59
+ body = rawBody;
60
+ }
61
+ }
62
+ // Build request URL
63
+ const queryString = event.queryStringParameters
64
+ ? "?" +
65
+ Object.entries(event.queryStringParameters)
66
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
67
+ .join("&")
68
+ : "";
69
+ const url = event.path + queryString;
70
+ // Build headers
71
+ const headers = {
72
+ ...event.headers,
73
+ };
74
+ // Add Lambda context to headers
75
+ headers["x-lambda-request-id"] = context.awsRequestId;
76
+ headers["x-lambda-function"] = context.functionName;
77
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
78
+ return new Promise((resolve, _reject) => {
79
+ // Create mock Express-compatible request object
80
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
81
+ const req = {
82
+ method: event.httpMethod,
83
+ url,
84
+ path: event.path,
85
+ headers,
86
+ body,
87
+ query: event.queryStringParameters || {},
88
+ params: {},
89
+ lambda: { event, context },
90
+ get: (name) => headers[name.toLowerCase()],
91
+ };
92
+ // Create mock Express-compatible response object
93
+ const chunks = [];
94
+ const responseHeaders = {};
95
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
+ const res = {
97
+ statusCode: 200,
98
+ setHeader: (name, value) => {
99
+ responseHeaders[name.toLowerCase()] = value;
100
+ },
101
+ getHeader: (name) => responseHeaders[name.toLowerCase()],
102
+ write: (chunk) => {
103
+ chunks.push(Buffer.from(chunk));
104
+ },
105
+ end: (chunk) => {
106
+ if (chunk) {
107
+ chunks.push(Buffer.from(chunk));
108
+ }
109
+ const bodyBuffer = Buffer.concat(chunks);
110
+ const contentType = responseHeaders["content-type"] || "";
111
+ const isBinary = binaryTypes.some((type) => {
112
+ if (type.endsWith("/*")) {
113
+ return contentType.startsWith(type.replace("/*", "/"));
114
+ }
115
+ return contentType === type;
116
+ });
117
+ const response = {
118
+ statusCode: res.statusCode,
119
+ headers: responseHeaders,
120
+ body: isBinary ? bodyBuffer.toString("base64") : bodyBuffer.toString("utf8"),
121
+ isBase64Encoded: isBinary,
122
+ };
123
+ if (debug) {
124
+ console.log("[Lambda] Response:", {
125
+ statusCode: response.statusCode,
126
+ headers: response.headers,
127
+ bodyLength: response.body.length,
128
+ });
129
+ }
130
+ resolve(response);
131
+ },
132
+ status: (code) => {
133
+ res.statusCode = code;
134
+ return res;
135
+ },
136
+ json: (data) => {
137
+ res.setHeader("content-type", "application/json");
138
+ res.end(JSON.stringify(data));
139
+ },
140
+ send: (data) => {
141
+ if (typeof data === "string") {
142
+ res.setHeader("content-type", "text/html");
143
+ res.end(data);
144
+ }
145
+ else if (Buffer.isBuffer(data)) {
146
+ res.end(data);
147
+ }
148
+ else {
149
+ res.json(data);
150
+ }
151
+ },
152
+ };
153
+ // Handle request through Express
154
+ try {
155
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
156
+ expressApp(req, res, (err) => {
157
+ if (err) {
158
+ console.error("[Lambda] Express error:", err);
159
+ resolve({
160
+ statusCode: 500,
161
+ headers: { "content-type": "application/json" },
162
+ body: JSON.stringify({ error: err.message }),
163
+ isBase64Encoded: false,
164
+ });
165
+ }
166
+ });
167
+ }
168
+ catch (error) {
169
+ const errorMessage = error instanceof Error ? error.message : String(error);
170
+ console.error("[Lambda] Handler error:", error);
171
+ resolve({
172
+ statusCode: 500,
173
+ headers: { "content-type": "application/json" },
174
+ body: JSON.stringify({ error: errorMessage }),
175
+ isBase64Encoded: false,
176
+ });
177
+ }
178
+ });
179
+ };
180
+ }