@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.
- package/README.md +39 -96
- package/lib/CHANGELOG.md +43 -0
- package/lib/README.md +39 -96
- package/lib/cjs/adapter-express/application-express.base.js +3 -1
- package/lib/cjs/adapter-express/application-express.js +1049 -85
- package/lib/cjs/adapter-express/express-utils/conditional-middleware.js +102 -0
- package/lib/cjs/adapter-express/express-utils/constants.js +17 -0
- package/lib/cjs/adapter-express/express-utils/content-negotiation-decorators.js +129 -0
- package/lib/cjs/adapter-express/express-utils/decorators.js +186 -49
- package/lib/cjs/adapter-express/express-utils/exception-filter-decorators.js +11 -0
- package/lib/cjs/adapter-express/express-utils/guard-context-factory.js +84 -0
- package/lib/cjs/adapter-express/express-utils/guard-middleware.js +115 -0
- package/lib/cjs/adapter-express/express-utils/guard-utils.js +18 -0
- package/lib/cjs/adapter-express/express-utils/http-context-store.js +15 -0
- package/lib/cjs/adapter-express/express-utils/http-status-middleware.js +37 -2
- package/lib/cjs/adapter-express/express-utils/index.js +67 -1
- package/lib/cjs/adapter-express/express-utils/interceptor-middleware.js +132 -0
- package/lib/cjs/adapter-express/express-utils/inversify-express-server.js +810 -63
- package/lib/cjs/adapter-express/express-utils/lazy-module-middleware.js +241 -0
- package/lib/cjs/adapter-express/express-utils/middleware-composition.js +95 -0
- package/lib/cjs/adapter-express/express-utils/permission-preloader.middleware.js +48 -0
- package/lib/cjs/adapter-express/express-utils/route-constraints.js +95 -0
- package/lib/cjs/adapter-express/express-utils/scope-extractor.interface.js +2 -0
- package/lib/cjs/adapter-express/express-utils/scope-extractor.js +66 -0
- package/lib/cjs/adapter-express/express-utils/setup-authorization.js +71 -0
- package/lib/cjs/adapter-express/express-utils/setup-event-system.js +113 -0
- package/lib/cjs/adapter-express/express-utils/setup-interceptors.js +103 -0
- package/lib/cjs/adapter-express/express-utils/setup-lazy-loading.js +228 -0
- package/lib/cjs/adapter-express/express-utils/utils.js +30 -12
- package/lib/cjs/adapter-express/express-utils/validation-decorators.js +205 -0
- package/lib/cjs/adapter-express/express-utils/validation-service.js +252 -0
- package/lib/cjs/adapter-express/index.js +7 -5
- package/lib/cjs/adapter-express/micro-api/application-express-micro-route.js +31 -1
- package/lib/cjs/adapter-express/micro-api/application-express-micro.js +11 -37
- package/lib/cjs/adapter-express/micro-api/gateway/circuit-breaker.js +174 -0
- package/lib/cjs/adapter-express/micro-api/gateway/index.js +11 -0
- package/lib/cjs/adapter-express/micro-api/gateway/service-proxy.js +214 -0
- package/lib/cjs/adapter-express/micro-api/index.js +27 -3
- package/lib/cjs/adapter-express/micro-api/micro.js +217 -0
- package/lib/cjs/adapter-express/micro-api/queue/index.js +8 -0
- package/lib/cjs/adapter-express/micro-api/queue/queue.interface.js +2 -0
- package/lib/cjs/adapter-express/micro-api/queue/rabbitmq-consumer.js +255 -0
- package/lib/cjs/adapter-express/micro-api/serverless/aws-lambda.adapter.js +183 -0
- package/lib/cjs/adapter-express/micro-api/serverless/cloudflare.adapter.js +158 -0
- package/lib/cjs/adapter-express/micro-api/serverless/index.js +12 -0
- package/lib/cjs/adapter-express/micro-api/serverless/vercel.adapter.js +102 -0
- package/lib/cjs/adapter-express/micro-api/service-mesh/index.js +10 -0
- package/lib/cjs/adapter-express/micro-api/service-mesh/service-client.js +194 -0
- package/lib/cjs/adapter-express/micro-api/service-mesh/service-discovery.js +261 -0
- package/lib/cjs/adapter-express/middleware/index.js +21 -0
- package/lib/cjs/adapter-express/middleware/request-logging.middleware.js +244 -0
- package/lib/cjs/adapter-express/render/engine.js +15 -15
- package/lib/cjs/adapter-express/render/index.js +5 -0
- package/lib/cjs/adapter-express/studio/index.js +9 -0
- package/lib/cjs/adapter-express/studio/studio-integration.js +214 -0
- package/lib/cjs/index.js +1 -1
- package/lib/cjs/types/adapter-express/application-express.base.d.ts +20 -7
- package/lib/cjs/types/adapter-express/application-express.d.ts +273 -32
- package/lib/cjs/types/adapter-express/express-utils/base-middleware.d.ts +2 -2
- package/lib/cjs/types/adapter-express/express-utils/conditional-middleware.d.ts +97 -0
- package/lib/cjs/types/adapter-express/express-utils/constants.d.ts +13 -0
- package/lib/cjs/types/adapter-express/express-utils/content-negotiation-decorators.d.ts +94 -0
- package/lib/cjs/types/adapter-express/express-utils/decorators.d.ts +54 -6
- package/lib/cjs/types/adapter-express/express-utils/exception-filter-decorators.d.ts +6 -0
- package/lib/cjs/types/adapter-express/express-utils/guard-context-factory.d.ts +17 -0
- package/lib/cjs/types/adapter-express/express-utils/guard-middleware.d.ts +22 -0
- package/lib/cjs/types/adapter-express/express-utils/guard-utils.d.ts +11 -0
- package/lib/cjs/types/adapter-express/express-utils/http-context-store.d.ts +20 -0
- package/lib/cjs/types/adapter-express/express-utils/httpResponseMessage.d.ts +1 -1
- package/lib/cjs/types/adapter-express/express-utils/index.d.ts +30 -2
- package/lib/cjs/types/adapter-express/express-utils/interceptor-middleware.d.ts +40 -0
- package/lib/cjs/types/adapter-express/express-utils/interfaces.d.ts +42 -5
- package/lib/cjs/types/adapter-express/express-utils/inversify-express-server.d.ts +114 -2
- package/lib/cjs/types/adapter-express/express-utils/lazy-module-middleware.d.ts +122 -0
- package/lib/cjs/types/adapter-express/express-utils/middleware-composition.d.ts +85 -0
- package/lib/cjs/types/adapter-express/express-utils/permission-preloader.middleware.d.ts +10 -0
- package/lib/cjs/types/adapter-express/express-utils/route-constraints.d.ts +89 -0
- package/lib/cjs/types/adapter-express/express-utils/scope-extractor.d.ts +21 -0
- package/lib/cjs/types/adapter-express/express-utils/scope-extractor.interface.d.ts +12 -0
- package/lib/cjs/types/adapter-express/express-utils/setup-authorization.d.ts +34 -0
- package/lib/cjs/types/adapter-express/express-utils/setup-event-system.d.ts +118 -0
- package/lib/cjs/types/adapter-express/express-utils/setup-interceptors.d.ts +115 -0
- package/lib/cjs/types/adapter-express/express-utils/setup-lazy-loading.d.ts +123 -0
- package/lib/cjs/types/adapter-express/express-utils/utils.d.ts +17 -2
- package/lib/cjs/types/adapter-express/express-utils/validation-decorators.d.ts +145 -0
- package/lib/cjs/types/adapter-express/express-utils/validation-service.d.ts +88 -0
- package/lib/cjs/types/adapter-express/index.d.ts +6 -4
- package/lib/cjs/types/adapter-express/micro-api/application-express-micro-route.d.ts +25 -14
- package/lib/cjs/types/adapter-express/micro-api/application-express-micro.d.ts +3 -10
- package/lib/cjs/types/adapter-express/micro-api/gateway/circuit-breaker.d.ts +111 -0
- package/lib/cjs/types/adapter-express/micro-api/gateway/index.d.ts +5 -0
- package/lib/cjs/types/adapter-express/micro-api/gateway/service-proxy.d.ts +83 -0
- package/lib/cjs/types/adapter-express/micro-api/index.d.ts +7 -1
- package/lib/cjs/types/adapter-express/micro-api/micro.d.ts +66 -0
- package/lib/cjs/types/adapter-express/micro-api/queue/index.d.ts +5 -0
- package/lib/cjs/types/adapter-express/micro-api/queue/queue.interface.d.ts +60 -0
- package/lib/cjs/types/adapter-express/micro-api/queue/rabbitmq-consumer.d.ts +86 -0
- package/lib/cjs/types/adapter-express/micro-api/serverless/aws-lambda.adapter.d.ts +77 -0
- package/lib/cjs/types/adapter-express/micro-api/serverless/cloudflare.adapter.d.ts +64 -0
- package/lib/cjs/types/adapter-express/micro-api/serverless/index.d.ts +6 -0
- package/lib/cjs/types/adapter-express/micro-api/serverless/vercel.adapter.d.ts +56 -0
- package/lib/cjs/types/adapter-express/micro-api/service-mesh/index.d.ts +5 -0
- package/lib/cjs/types/adapter-express/micro-api/service-mesh/service-client.d.ts +122 -0
- package/lib/cjs/types/adapter-express/micro-api/service-mesh/service-discovery.d.ts +150 -0
- package/lib/cjs/types/adapter-express/middleware/index.d.ts +5 -0
- package/lib/cjs/types/adapter-express/middleware/request-logging.middleware.d.ts +65 -0
- package/lib/cjs/types/adapter-express/render/index.d.ts +1 -0
- package/lib/cjs/types/adapter-express/studio/index.d.ts +1 -0
- package/lib/cjs/types/adapter-express/studio/studio-integration.d.ts +92 -0
- package/lib/cjs/types/index.d.ts +1 -1
- package/lib/esm/adapter-express/application-express.base.js +24 -0
- package/lib/esm/adapter-express/application-express.js +1300 -0
- package/lib/esm/adapter-express/application-express.types.js +1 -0
- package/lib/esm/adapter-express/express-utils/base-middleware.js +19 -0
- package/lib/esm/adapter-express/express-utils/conditional-middleware.js +96 -0
- package/lib/esm/adapter-express/express-utils/constants.js +63 -0
- package/lib/esm/adapter-express/express-utils/content/httpContent.js +6 -0
- package/lib/esm/adapter-express/express-utils/content-negotiation-decorators.js +120 -0
- package/lib/esm/adapter-express/express-utils/decorators.js +575 -0
- package/lib/esm/adapter-express/express-utils/exception-filter-decorators.js +6 -0
- package/lib/esm/adapter-express/express-utils/guard-context-factory.js +83 -0
- package/lib/esm/adapter-express/express-utils/guard-middleware.js +115 -0
- package/lib/esm/adapter-express/express-utils/guard-utils.js +14 -0
- package/lib/esm/adapter-express/express-utils/http-context-store.js +10 -0
- package/lib/esm/adapter-express/express-utils/http-status-middleware.js +116 -0
- package/lib/esm/adapter-express/express-utils/httpResponseMessage.js +29 -0
- package/lib/esm/adapter-express/express-utils/index.js +24 -0
- package/lib/esm/adapter-express/express-utils/interceptor-middleware.js +130 -0
- package/lib/esm/adapter-express/express-utils/interfaces.js +1 -0
- package/lib/esm/adapter-express/express-utils/inversify-express-server.js +1031 -0
- package/lib/esm/adapter-express/express-utils/lazy-module-middleware.js +236 -0
- package/lib/esm/adapter-express/express-utils/middleware-composition.js +89 -0
- package/lib/esm/adapter-express/express-utils/permission-preloader.middleware.js +45 -0
- package/lib/esm/adapter-express/express-utils/resolver-multer.js +30 -0
- package/lib/esm/adapter-express/express-utils/route-constraints.js +91 -0
- package/lib/esm/adapter-express/express-utils/scope-extractor.interface.js +1 -0
- package/lib/esm/adapter-express/express-utils/scope-extractor.js +63 -0
- package/lib/esm/adapter-express/express-utils/setup-authorization.js +68 -0
- package/lib/esm/adapter-express/express-utils/setup-event-system.js +110 -0
- package/lib/esm/adapter-express/express-utils/setup-interceptors.js +100 -0
- package/lib/esm/adapter-express/express-utils/setup-lazy-loading.js +225 -0
- package/lib/esm/adapter-express/express-utils/utils.js +68 -0
- package/lib/esm/adapter-express/express-utils/validation-decorators.js +199 -0
- package/lib/esm/adapter-express/express-utils/validation-service.js +251 -0
- package/lib/esm/adapter-express/index.js +7 -0
- package/lib/esm/adapter-express/micro-api/application-express-micro-container.js +48 -0
- package/lib/esm/adapter-express/micro-api/application-express-micro-route.js +128 -0
- package/lib/esm/adapter-express/micro-api/application-express-micro.js +161 -0
- package/lib/esm/adapter-express/micro-api/gateway/circuit-breaker.js +174 -0
- package/lib/esm/adapter-express/micro-api/gateway/index.js +5 -0
- package/lib/esm/adapter-express/micro-api/gateway/service-proxy.js +210 -0
- package/lib/esm/adapter-express/micro-api/index.js +10 -0
- package/lib/esm/adapter-express/micro-api/micro.js +211 -0
- package/lib/esm/adapter-express/micro-api/queue/index.js +4 -0
- package/lib/esm/adapter-express/micro-api/queue/queue.interface.js +1 -0
- package/lib/esm/adapter-express/micro-api/queue/rabbitmq-consumer.js +229 -0
- package/lib/esm/adapter-express/micro-api/serverless/aws-lambda.adapter.js +180 -0
- package/lib/esm/adapter-express/micro-api/serverless/cloudflare.adapter.js +155 -0
- package/lib/esm/adapter-express/micro-api/serverless/index.js +6 -0
- package/lib/esm/adapter-express/micro-api/serverless/vercel.adapter.js +99 -0
- package/lib/esm/adapter-express/micro-api/service-mesh/index.js +5 -0
- package/lib/esm/adapter-express/micro-api/service-mesh/service-client.js +191 -0
- package/lib/esm/adapter-express/micro-api/service-mesh/service-discovery.js +259 -0
- package/lib/esm/adapter-express/middleware/index.js +5 -0
- package/lib/esm/adapter-express/middleware/request-logging.middleware.js +239 -0
- package/lib/esm/adapter-express/render/constants.js +37 -0
- package/lib/esm/adapter-express/render/engine.js +51 -0
- package/lib/esm/adapter-express/render/index.js +1 -0
- package/lib/esm/adapter-express/render/resolve-render.js +30 -0
- package/lib/esm/adapter-express/studio/index.js +1 -0
- package/lib/esm/adapter-express/studio/studio-integration.js +184 -0
- package/lib/esm/index.mjs +1 -0
- package/lib/esm/package.json +3 -0
- package/lib/esm/types/adapter-express/application-express.base.d.ts +77 -0
- package/lib/esm/types/adapter-express/application-express.d.ts +411 -0
- package/lib/esm/types/adapter-express/application-express.types.d.ts +23 -0
- package/lib/esm/types/adapter-express/express-utils/base-middleware.d.ts +8 -0
- package/lib/esm/types/adapter-express/express-utils/conditional-middleware.d.ts +97 -0
- package/lib/esm/types/adapter-express/express-utils/constants.d.ts +57 -0
- package/lib/esm/types/adapter-express/express-utils/content/httpContent.d.ts +6 -0
- package/lib/esm/types/adapter-express/express-utils/content-negotiation-decorators.d.ts +94 -0
- package/lib/esm/types/adapter-express/express-utils/decorators.d.ts +257 -0
- package/lib/esm/types/adapter-express/express-utils/exception-filter-decorators.d.ts +6 -0
- package/lib/esm/types/adapter-express/express-utils/guard-context-factory.d.ts +17 -0
- package/lib/esm/types/adapter-express/express-utils/guard-middleware.d.ts +22 -0
- package/lib/esm/types/adapter-express/express-utils/guard-utils.d.ts +11 -0
- package/lib/esm/types/adapter-express/express-utils/http-context-store.d.ts +20 -0
- package/lib/esm/types/adapter-express/express-utils/http-status-middleware.d.ts +26 -0
- package/lib/esm/types/adapter-express/express-utils/httpResponseMessage.d.ts +14 -0
- package/lib/esm/types/adapter-express/express-utils/index.d.ts +30 -0
- package/lib/esm/types/adapter-express/express-utils/interceptor-middleware.d.ts +40 -0
- package/lib/esm/types/adapter-express/express-utils/interfaces.d.ts +115 -0
- package/lib/esm/types/adapter-express/express-utils/inversify-express-server.d.ts +172 -0
- package/lib/esm/types/adapter-express/express-utils/lazy-module-middleware.d.ts +122 -0
- package/lib/esm/types/adapter-express/express-utils/middleware-composition.d.ts +85 -0
- package/lib/esm/types/adapter-express/express-utils/permission-preloader.middleware.d.ts +10 -0
- package/lib/esm/types/adapter-express/express-utils/resolver-multer.d.ts +7 -0
- package/lib/esm/types/adapter-express/express-utils/route-constraints.d.ts +89 -0
- package/lib/esm/types/adapter-express/express-utils/scope-extractor.d.ts +21 -0
- package/lib/esm/types/adapter-express/express-utils/scope-extractor.interface.d.ts +12 -0
- package/lib/esm/types/adapter-express/express-utils/setup-authorization.d.ts +34 -0
- package/lib/esm/types/adapter-express/express-utils/setup-event-system.d.ts +118 -0
- package/lib/esm/types/adapter-express/express-utils/setup-interceptors.d.ts +115 -0
- package/lib/esm/types/adapter-express/express-utils/setup-lazy-loading.d.ts +123 -0
- package/lib/esm/types/adapter-express/express-utils/utils.d.ts +24 -0
- package/lib/esm/types/adapter-express/express-utils/validation-decorators.d.ts +145 -0
- package/lib/esm/types/adapter-express/express-utils/validation-service.d.ts +88 -0
- package/lib/esm/types/adapter-express/index.d.ts +7 -0
- package/lib/esm/types/adapter-express/micro-api/application-express-micro-container.d.ts +47 -0
- package/lib/esm/types/adapter-express/micro-api/application-express-micro-route.d.ts +104 -0
- package/lib/esm/types/adapter-express/micro-api/application-express-micro.d.ts +72 -0
- package/lib/esm/types/adapter-express/micro-api/gateway/circuit-breaker.d.ts +111 -0
- package/lib/esm/types/adapter-express/micro-api/gateway/index.d.ts +5 -0
- package/lib/esm/types/adapter-express/micro-api/gateway/service-proxy.d.ts +83 -0
- package/lib/esm/types/adapter-express/micro-api/index.d.ts +7 -0
- package/lib/esm/types/adapter-express/micro-api/micro.d.ts +66 -0
- package/lib/esm/types/adapter-express/micro-api/queue/index.d.ts +5 -0
- package/lib/esm/types/adapter-express/micro-api/queue/queue.interface.d.ts +60 -0
- package/lib/esm/types/adapter-express/micro-api/queue/rabbitmq-consumer.d.ts +86 -0
- package/lib/esm/types/adapter-express/micro-api/serverless/aws-lambda.adapter.d.ts +77 -0
- package/lib/esm/types/adapter-express/micro-api/serverless/cloudflare.adapter.d.ts +64 -0
- package/lib/esm/types/adapter-express/micro-api/serverless/index.d.ts +6 -0
- package/lib/esm/types/adapter-express/micro-api/serverless/vercel.adapter.d.ts +56 -0
- package/lib/esm/types/adapter-express/micro-api/service-mesh/index.d.ts +5 -0
- package/lib/esm/types/adapter-express/micro-api/service-mesh/service-client.d.ts +122 -0
- package/lib/esm/types/adapter-express/micro-api/service-mesh/service-discovery.d.ts +150 -0
- package/lib/esm/types/adapter-express/middleware/index.d.ts +5 -0
- package/lib/esm/types/adapter-express/middleware/request-logging.middleware.d.ts +65 -0
- package/lib/esm/types/adapter-express/render/constants.d.ts +26 -0
- package/lib/esm/types/adapter-express/render/engine.d.ts +20 -0
- package/lib/esm/types/adapter-express/render/index.d.ts +5 -0
- package/lib/esm/types/adapter-express/render/resolve-render.d.ts +7 -0
- package/lib/esm/types/adapter-express/studio/index.d.ts +1 -0
- package/lib/esm/types/adapter-express/studio/studio-integration.d.ts +92 -0
- package/lib/esm/types/index.d.ts +1 -0
- package/lib/package.json +156 -146
- package/package.json +156 -146
- package/lib/cjs/di/di.interfaces.js +0 -10
- 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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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
|
+
}
|