@expressots/adapter-express 3.0.0 → 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 +31 -5
- 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
|
@@ -26,11 +26,68 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.InversifyExpressServer = void 0;
|
|
27
27
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
28
28
|
const express_1 = __importStar(require("express"));
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
const
|
|
29
|
+
const core_1 = require("@expressots/core");
|
|
30
|
+
const guard_context_factory_js_1 = require("./guard-context-factory.js");
|
|
31
|
+
const base_middleware_js_1 = require("./base-middleware.js");
|
|
32
|
+
const utils_js_1 = require("./utils.js");
|
|
33
|
+
const validation_decorators_js_1 = require("./validation-decorators.js");
|
|
34
|
+
const constants_js_1 = require("./constants.js");
|
|
35
|
+
const httpResponseMessage_js_1 = require("./httpResponseMessage.js");
|
|
36
|
+
const decorators_js_1 = require("./decorators.js");
|
|
37
|
+
const conditional_middleware_js_1 = require("./conditional-middleware.js");
|
|
38
|
+
const middleware_composition_js_1 = require("./middleware-composition.js");
|
|
39
|
+
const guard_utils_js_1 = require("./guard-utils.js");
|
|
40
|
+
const guard_middleware_js_1 = require("./guard-middleware.js");
|
|
41
|
+
const interceptor_middleware_js_1 = require("./interceptor-middleware.js");
|
|
42
|
+
const http_context_store_js_1 = require("./http-context-store.js");
|
|
43
|
+
// Lazy-load route registry from @expressots/core. Static import because
|
|
44
|
+
// `getRouteRegistry` is part of the core's public surface; we just guard
|
|
45
|
+
// against it being undefined to keep this non-critical (suggestions are
|
|
46
|
+
// optional).
|
|
47
|
+
const core_2 = require("@expressots/core");
|
|
48
|
+
function getRouteRegistryModule() {
|
|
49
|
+
if (typeof core_2.getRouteRegistry !== "function")
|
|
50
|
+
return null;
|
|
51
|
+
return { getRouteRegistry: core_2.getRouteRegistry };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Properly join route path segments, handling:
|
|
55
|
+
* - Controller "/" + method "/users" = "/users"
|
|
56
|
+
* - Controller "/api" + method "users" = "/api/users"
|
|
57
|
+
* - Controller "/api/" + method "/users" = "/api/users"
|
|
58
|
+
* - Controller "/" + method "/" = "/"
|
|
59
|
+
*/
|
|
60
|
+
function joinRoutePaths(...segments) {
|
|
61
|
+
const parts = [];
|
|
62
|
+
for (const segment of segments) {
|
|
63
|
+
if (!segment || segment === "")
|
|
64
|
+
continue;
|
|
65
|
+
// For root path only, skip if we have parts
|
|
66
|
+
if (segment === "/" && parts.length > 0)
|
|
67
|
+
continue;
|
|
68
|
+
// Remove trailing slash
|
|
69
|
+
let cleaned = segment.endsWith("/") && segment.length > 1 ? segment.slice(0, -1) : segment;
|
|
70
|
+
// Handle leading slash
|
|
71
|
+
if (parts.length > 0) {
|
|
72
|
+
// Ensure leading slash for non-first segments
|
|
73
|
+
cleaned = cleaned.startsWith("/") ? cleaned : `/${cleaned}`;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// First segment - ensure starts with /
|
|
77
|
+
cleaned = cleaned.startsWith("/") ? cleaned : `/${cleaned}`;
|
|
78
|
+
}
|
|
79
|
+
if (cleaned && cleaned !== "/") {
|
|
80
|
+
parts.push(cleaned);
|
|
81
|
+
}
|
|
82
|
+
else if (parts.length === 0) {
|
|
83
|
+
parts.push("/");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (parts.length === 0)
|
|
87
|
+
return "/";
|
|
88
|
+
// Join and normalize double slashes
|
|
89
|
+
return parts.join("").replace(/\/+/g, "/");
|
|
90
|
+
}
|
|
34
91
|
class InversifyExpressServer {
|
|
35
92
|
/**
|
|
36
93
|
* Wrapper for the express server.
|
|
@@ -47,12 +104,12 @@ class InversifyExpressServer {
|
|
|
47
104
|
this._forceControllers = forceControllers;
|
|
48
105
|
this._router = customRouter || (0, express_1.Router)();
|
|
49
106
|
this._routingConfig = routingConfig || {
|
|
50
|
-
rootPath:
|
|
107
|
+
rootPath: constants_js_1.DEFAULT_ROUTING_ROOT_PATH,
|
|
51
108
|
};
|
|
52
109
|
this._app = customApp || (0, express_1.default)();
|
|
53
110
|
if (authProvider) {
|
|
54
111
|
this._AuthProvider = authProvider;
|
|
55
|
-
container.bind(
|
|
112
|
+
container.bind(constants_js_1.TYPE.AuthProvider).to(this._AuthProvider);
|
|
56
113
|
}
|
|
57
114
|
}
|
|
58
115
|
/**
|
|
@@ -85,46 +142,164 @@ class InversifyExpressServer {
|
|
|
85
142
|
* Applies all routes and configuration to the server, returning the express application.
|
|
86
143
|
*/
|
|
87
144
|
build() {
|
|
88
|
-
// The very first middleware to be invoked
|
|
89
|
-
//
|
|
90
|
-
//
|
|
145
|
+
// The very first middleware to be invoked: create an HttpContext per
|
|
146
|
+
// request and attach it via a WeakMap (see ./http-context-store).
|
|
147
|
+
// This is cheaper than the previous `Reflect.defineMetadata` call
|
|
148
|
+
// because it bypasses reflect-metadata's string-keyed map.
|
|
91
149
|
this._app.all("*", (req, res, next) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
150
|
+
this._createHttpContext(req, res, next)
|
|
151
|
+
.then((httpContext) => {
|
|
152
|
+
(0, http_context_store_js_1.setHttpContext)(req, httpContext);
|
|
95
153
|
next();
|
|
96
|
-
})
|
|
154
|
+
})
|
|
155
|
+
.catch(next);
|
|
97
156
|
});
|
|
98
157
|
// register server-level middleware before anything else
|
|
99
158
|
if (this._configFn) {
|
|
100
159
|
this._configFn.apply(undefined, [this._app]);
|
|
101
160
|
}
|
|
102
161
|
this.registerControllers();
|
|
162
|
+
this.registerNotFoundHandler();
|
|
103
163
|
// register error handlers after controllers
|
|
104
164
|
if (this._errorConfigFn) {
|
|
105
165
|
this._errorConfigFn.apply(undefined, [this._app]);
|
|
106
166
|
}
|
|
107
167
|
return this._app;
|
|
108
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Install a catch-all 404 handler that runs after every registered route.
|
|
171
|
+
*
|
|
172
|
+
* When the user has the suggestions feature enabled (default in development),
|
|
173
|
+
* this consults the route registry, computes "Did you mean ...?" suggestions
|
|
174
|
+
* via `getErrorHints` from `@expressots/core`, logs them through the framework
|
|
175
|
+
* Logger, and returns a structured RFC-7807-style JSON 404 instead of the
|
|
176
|
+
* default Express HTML.
|
|
177
|
+
*
|
|
178
|
+
* Users who want the legacy Express HTML 404 can opt out by configuring the
|
|
179
|
+
* Logger with `suggestions.enabled = false` (this also disables the JSON
|
|
180
|
+
* envelope so they can install their own 404 handler in the error-config fn).
|
|
181
|
+
*
|
|
182
|
+
* @private
|
|
183
|
+
*/
|
|
184
|
+
registerNotFoundHandler() {
|
|
185
|
+
this._app.use((req, res, next) => {
|
|
186
|
+
if (res.headersSent) {
|
|
187
|
+
return next();
|
|
188
|
+
}
|
|
189
|
+
const suggestionsConfig = this.resolveSuggestionsConfig();
|
|
190
|
+
if (!suggestionsConfig.enabled) {
|
|
191
|
+
return next();
|
|
192
|
+
}
|
|
193
|
+
const requestedPath = req.originalUrl || req.url;
|
|
194
|
+
const requestedMethod = req.method;
|
|
195
|
+
const hints = (0, core_1.getErrorHints)(new Error(`Route '${requestedMethod} ${requestedPath}' not found`), {
|
|
196
|
+
path: requestedPath,
|
|
197
|
+
method: requestedMethod,
|
|
198
|
+
statusCode: 404,
|
|
199
|
+
}, suggestionsConfig);
|
|
200
|
+
if (hints.length > 0) {
|
|
201
|
+
try {
|
|
202
|
+
const formatted = (0, core_1.formatSuggestions)(hints);
|
|
203
|
+
if (formatted) {
|
|
204
|
+
const logger = this.resolveLogger();
|
|
205
|
+
if (logger) {
|
|
206
|
+
logger.warn(`Route not found: ${requestedMethod} ${requestedPath}${formatted}`, "router-404");
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
// eslint-disable-next-line no-console
|
|
210
|
+
console.warn(`[router-404] Route not found: ${requestedMethod} ${requestedPath}${formatted}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// Suggestion logging is best-effort; never fail the request because of it.
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const routeSuggestion = hints.find((hint) => hint.type === "route");
|
|
219
|
+
const actionHint = hints.find((hint) => hint.type === "hint");
|
|
220
|
+
const body = {
|
|
221
|
+
type: "https://expressots.dev/errors/not-found",
|
|
222
|
+
title: "Route Not Found",
|
|
223
|
+
status: 404,
|
|
224
|
+
detail: `Route '${requestedMethod} ${requestedPath}' does not exist`,
|
|
225
|
+
instance: requestedPath,
|
|
226
|
+
timestamp: new Date().toISOString(),
|
|
227
|
+
};
|
|
228
|
+
if (routeSuggestion?.routes && routeSuggestion.routes.length > 0) {
|
|
229
|
+
body.suggestions = routeSuggestion.routes.map((suggestion) => ({
|
|
230
|
+
method: suggestion.route.method,
|
|
231
|
+
path: suggestion.route.fullPath || suggestion.route.path,
|
|
232
|
+
similarity: Math.round(suggestion.similarity * 100),
|
|
233
|
+
reason: suggestion.reason,
|
|
234
|
+
}));
|
|
235
|
+
}
|
|
236
|
+
else if (actionHint?.actions && actionHint.actions.length > 0) {
|
|
237
|
+
body.actions = actionHint.actions;
|
|
238
|
+
}
|
|
239
|
+
res.status(404).type("application/json").send(JSON.stringify(body));
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Resolve the user-configured suggestions config, falling back to the
|
|
244
|
+
* env-aware default when the Logger is not bound or has no overrides.
|
|
245
|
+
*
|
|
246
|
+
* @private
|
|
247
|
+
*/
|
|
248
|
+
resolveSuggestionsConfig() {
|
|
249
|
+
const fallback = (0, core_1.getDefaultSuggestionsConfig)();
|
|
250
|
+
const logger = this.resolveLogger();
|
|
251
|
+
if (!logger) {
|
|
252
|
+
return fallback;
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
const loggerConfig = logger.getConfig?.();
|
|
256
|
+
if (loggerConfig?.suggestions) {
|
|
257
|
+
return { ...fallback, ...loggerConfig.suggestions };
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
// Logger may not expose getConfig in older versions; fall through.
|
|
262
|
+
}
|
|
263
|
+
return fallback;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Resolve the framework Logger from DI when available.
|
|
267
|
+
*
|
|
268
|
+
* @private
|
|
269
|
+
*/
|
|
270
|
+
resolveLogger() {
|
|
271
|
+
try {
|
|
272
|
+
// The `Logger` symbol is the constructor itself in our DI bindings.
|
|
273
|
+
if (this._container.isBound(core_1.Logger)) {
|
|
274
|
+
return this._container.get(core_1.Logger);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
// not bound yet
|
|
279
|
+
}
|
|
280
|
+
return undefined;
|
|
281
|
+
}
|
|
109
282
|
registerControllers() {
|
|
110
283
|
// Fake HttpContext is needed during registration
|
|
111
|
-
this._container.bind(
|
|
112
|
-
|
|
284
|
+
this._container.bind(constants_js_1.TYPE.HttpContext).toConstantValue({});
|
|
285
|
+
// Initialize interceptor system if not already bound
|
|
286
|
+
this.initializeInterceptorSystem();
|
|
287
|
+
const constructors = (0, utils_js_1.getControllersFromMetadata)();
|
|
113
288
|
constructors.forEach((constructor) => {
|
|
114
289
|
const { name } = constructor;
|
|
115
|
-
if (this._container.isBoundNamed(
|
|
116
|
-
throw new Error((0,
|
|
290
|
+
if (this._container.isBoundNamed(constants_js_1.TYPE.Controller, name)) {
|
|
291
|
+
throw new Error((0, constants_js_1.DUPLICATED_CONTROLLER_NAME)(name));
|
|
117
292
|
}
|
|
118
293
|
this._container
|
|
119
|
-
.bind(
|
|
294
|
+
.bind(constants_js_1.TYPE.Controller)
|
|
120
295
|
.to(constructor)
|
|
121
296
|
.whenTargetNamed(name);
|
|
122
297
|
});
|
|
123
|
-
const controllers = (0,
|
|
298
|
+
const controllers = (0, utils_js_1.getControllersFromContainer)(this._container, this._forceControllers);
|
|
124
299
|
controllers.forEach((controller) => {
|
|
125
|
-
const controllerMetadata = (0,
|
|
126
|
-
const methodMetadata = (0,
|
|
127
|
-
const parameterMetadata = (0,
|
|
300
|
+
const controllerMetadata = (0, utils_js_1.getControllerMetadata)(controller.constructor);
|
|
301
|
+
const methodMetadata = (0, utils_js_1.getControllerMethodMetadata)(controller.constructor);
|
|
302
|
+
const parameterMetadata = (0, utils_js_1.getControllerParameterMetadata)(controller.constructor);
|
|
128
303
|
if (controllerMetadata && methodMetadata) {
|
|
129
304
|
const controllerMiddleware = this.resolveMiddleware(...controllerMetadata.middleware);
|
|
130
305
|
methodMetadata.forEach((metadata) => {
|
|
@@ -132,21 +307,168 @@ class InversifyExpressServer {
|
|
|
132
307
|
if (parameterMetadata) {
|
|
133
308
|
paramList = parameterMetadata[metadata.key] || [];
|
|
134
309
|
}
|
|
135
|
-
|
|
310
|
+
// Create base handler
|
|
311
|
+
let handler = this.handlerFactory(controllerMetadata.target.name, metadata.key, paramList, controller.constructor, // Pass controller constructor for metadata
|
|
312
|
+
metadata);
|
|
313
|
+
// Wrap handler with interceptor middleware if interceptors are defined
|
|
314
|
+
const interceptors = this.extractInterceptors(controller.constructor, metadata.key);
|
|
315
|
+
if (interceptors.length > 0 && this.isInterceptorSystemReady()) {
|
|
316
|
+
handler = this.wrapWithInterceptors(handler, controller.constructor, metadata.key);
|
|
317
|
+
}
|
|
136
318
|
const routeMiddleware = this.resolveMiddleware(...metadata.middleware);
|
|
137
|
-
|
|
319
|
+
// Determine version: method-level version overrides controller-level version
|
|
320
|
+
const version = metadata.version || controllerMetadata.version;
|
|
321
|
+
const versionPrefix = version ? `/${version}` : "";
|
|
322
|
+
// Properly join paths to avoid issues like "/api" + "users" = "/apiusers"
|
|
323
|
+
const routePath = joinRoutePaths(versionPrefix, controllerMetadata.path, metadata.path);
|
|
324
|
+
const fullPath = joinRoutePaths(this._routingConfig.rootPath, routePath);
|
|
325
|
+
// Register route for suggestions system (synchronous approach)
|
|
326
|
+
try {
|
|
327
|
+
const module = getRouteRegistryModule();
|
|
328
|
+
if (module && module.getRouteRegistry) {
|
|
329
|
+
const registry = module.getRouteRegistry();
|
|
330
|
+
registry.register(metadata.method, routePath, fullPath);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
// Route registry not available, skip registration (non-critical)
|
|
335
|
+
// This allows the app to work even if suggestions module isn't available
|
|
336
|
+
}
|
|
337
|
+
this._router[metadata.method](routePath, ...controllerMiddleware, ...routeMiddleware, handler);
|
|
138
338
|
});
|
|
139
339
|
}
|
|
140
340
|
});
|
|
141
341
|
this._app.use(this._routingConfig.rootPath, this._router);
|
|
142
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* Initialize the interceptor system by binding required components
|
|
345
|
+
* @private
|
|
346
|
+
*/
|
|
347
|
+
initializeInterceptorSystem() {
|
|
348
|
+
try {
|
|
349
|
+
// Bind InterceptorRegistry if not already bound
|
|
350
|
+
if (!this._container.isBound(core_1.InterceptorRegistry)) {
|
|
351
|
+
this._container.bind(core_1.InterceptorRegistry).toSelf().inSingletonScope();
|
|
352
|
+
}
|
|
353
|
+
// Bind InterceptorExecutor if not already bound
|
|
354
|
+
if (!this._container.isBound(core_1.InterceptorExecutor)) {
|
|
355
|
+
this._container.bind(core_1.InterceptorExecutor).toSelf().inSingletonScope();
|
|
356
|
+
}
|
|
357
|
+
// Bind InterceptorMiddleware if not already bound
|
|
358
|
+
if (!this._container.isBound(interceptor_middleware_js_1.InterceptorMiddleware)) {
|
|
359
|
+
this._container.bind(interceptor_middleware_js_1.InterceptorMiddleware).toSelf().inSingletonScope();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
catch {
|
|
363
|
+
// Interceptor system initialization failed (non-critical)
|
|
364
|
+
// Routes will work without interceptors
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Check if the interceptor system is properly initialized
|
|
369
|
+
* @private
|
|
370
|
+
*/
|
|
371
|
+
isInterceptorSystemReady() {
|
|
372
|
+
try {
|
|
373
|
+
return (this._container.isBound(core_1.InterceptorExecutor) &&
|
|
374
|
+
this._container.isBound(interceptor_middleware_js_1.InterceptorMiddleware));
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Extract interceptors from controller and method metadata
|
|
382
|
+
* @private
|
|
383
|
+
*/
|
|
384
|
+
extractInterceptors(controllerClass, methodName) {
|
|
385
|
+
try {
|
|
386
|
+
// Get controller-level interceptors
|
|
387
|
+
const controllerInterceptors = Reflect.getMetadata(core_1.INTERCEPTOR_METADATA_KEY.controllerInterceptors, controllerClass) || [];
|
|
388
|
+
// Get method-level interceptors
|
|
389
|
+
const methodInterceptors = Reflect.getMetadata(core_1.INTERCEPTOR_METADATA_KEY.methodInterceptors, controllerClass, methodName) || [];
|
|
390
|
+
// Combine: controller + method level
|
|
391
|
+
return [...controllerInterceptors, ...methodInterceptors];
|
|
392
|
+
}
|
|
393
|
+
catch {
|
|
394
|
+
return [];
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Wrap a handler with interceptor middleware
|
|
399
|
+
* @private
|
|
400
|
+
*/
|
|
401
|
+
wrapWithInterceptors(handler, controllerClass, methodName) {
|
|
402
|
+
try {
|
|
403
|
+
const interceptorMiddleware = (0, interceptor_middleware_js_1.createInterceptorMiddleware)(this._container, controllerClass, methodName, handler);
|
|
404
|
+
return interceptorMiddleware;
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
// Fall back to original handler if interceptor wrapping fails
|
|
408
|
+
return handler;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Checks if a middleware item is a class constructor (not an instance).
|
|
413
|
+
* Handles classes that extend ExpressoMiddleware (which has abstract use method).
|
|
414
|
+
* Note: Abstract methods don't exist at runtime, so we check for concrete implementations.
|
|
415
|
+
*/
|
|
416
|
+
isMiddlewareClass(middlewareItem) {
|
|
417
|
+
// Must be a function (class constructor)
|
|
418
|
+
if (typeof middlewareItem !== "function") {
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
// Must not be a conditional or composed middleware config
|
|
422
|
+
if ((0, conditional_middleware_js_1.isConditionalMiddleware)(middlewareItem) || (0, middleware_composition_js_1.isComposedMiddleware)(middlewareItem)) {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
// Must have a prototype
|
|
426
|
+
if (middlewareItem.prototype === undefined) {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
// Check if it has a 'use' method in its prototype
|
|
430
|
+
// Classes that extend ExpressoMiddleware must implement the abstract use() method
|
|
431
|
+
// so it will be in the prototype at runtime
|
|
432
|
+
const prototype = middlewareItem.prototype;
|
|
433
|
+
// Check for 'use' method directly in prototype (most common case)
|
|
434
|
+
if ("use" in prototype && typeof prototype.use === "function") {
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
// Also check prototype chain in case use() is defined in a parent class
|
|
438
|
+
// This handles cases where the method might be inherited (optimized: only if not found directly)
|
|
439
|
+
let currentPrototype = Object.getPrototypeOf(prototype);
|
|
440
|
+
while (currentPrototype && currentPrototype !== Object.prototype) {
|
|
441
|
+
if ("use" in currentPrototype &&
|
|
442
|
+
typeof currentPrototype.use === "function") {
|
|
443
|
+
return true;
|
|
444
|
+
}
|
|
445
|
+
currentPrototype = Object.getPrototypeOf(currentPrototype);
|
|
446
|
+
}
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
143
449
|
isExpressoMiddleware(middlewareItem) {
|
|
144
450
|
return (typeof middlewareItem === "object" &&
|
|
451
|
+
middlewareItem !== null &&
|
|
145
452
|
"use" in middlewareItem &&
|
|
146
|
-
typeof middlewareItem.use === "function"
|
|
453
|
+
typeof middlewareItem.use === "function" &&
|
|
454
|
+
!(0, conditional_middleware_js_1.isConditionalMiddleware)(middlewareItem) &&
|
|
455
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
456
|
+
!this.isMiddlewareClass(middlewareItem));
|
|
147
457
|
}
|
|
148
458
|
resolveMiddleware(...middleware) {
|
|
149
459
|
return middleware.map((middlewareItem) => {
|
|
460
|
+
// Handle composed middleware first (Phase 3: Middleware Composition)
|
|
461
|
+
if ((0, middleware_composition_js_1.isComposedMiddleware)(middlewareItem)) {
|
|
462
|
+
return this.createComposedMiddlewareHandler(middlewareItem);
|
|
463
|
+
}
|
|
464
|
+
// Handle conditional middleware
|
|
465
|
+
if ((0, conditional_middleware_js_1.isConditionalMiddleware)(middlewareItem)) {
|
|
466
|
+
return this.createConditionalMiddlewareHandler(middlewareItem);
|
|
467
|
+
}
|
|
468
|
+
// Handle class constructors (Phase 2: Class Reference Support)
|
|
469
|
+
if (this.isMiddlewareClass(middlewareItem)) {
|
|
470
|
+
return this.createLazyMiddlewareHandler(middlewareItem);
|
|
471
|
+
}
|
|
150
472
|
if (this.isExpressoMiddleware(middlewareItem)) {
|
|
151
473
|
return (req, res, next) => {
|
|
152
474
|
middlewareItem.use(req, res, next);
|
|
@@ -156,7 +478,7 @@ class InversifyExpressServer {
|
|
|
156
478
|
return middlewareItem;
|
|
157
479
|
}
|
|
158
480
|
const middlewareInstance = this._container.get(middlewareItem);
|
|
159
|
-
if (middlewareInstance instanceof
|
|
481
|
+
if (middlewareInstance instanceof base_middleware_js_1.BaseMiddleware) {
|
|
160
482
|
return (req, res, next) => {
|
|
161
483
|
const mReq = this._container.get(middlewareItem);
|
|
162
484
|
mReq.httpContext = this._getHttpContext(req);
|
|
@@ -166,6 +488,239 @@ class InversifyExpressServer {
|
|
|
166
488
|
return middlewareInstance;
|
|
167
489
|
});
|
|
168
490
|
}
|
|
491
|
+
/**
|
|
492
|
+
* Creates a lazy middleware handler for class constructors.
|
|
493
|
+
* Supports both container-bound middleware (via @provide()) and direct instantiation.
|
|
494
|
+
*
|
|
495
|
+
* Performance: Instances are created per-request to support request-scoped state.
|
|
496
|
+
* For better performance with stateless middleware, use container-bound middleware
|
|
497
|
+
* with proper scoping (singleton/request scope) via @provide().
|
|
498
|
+
*
|
|
499
|
+
* Note: If container resolution fails (e.g., base class missing @injectable()),
|
|
500
|
+
* falls back to direct instantiation for backward compatibility.
|
|
501
|
+
*/
|
|
502
|
+
createLazyMiddlewareHandler(MiddlewareClass) {
|
|
503
|
+
// Pre-check if container-bound at route registration time (performance optimization)
|
|
504
|
+
const isContainerBound = this._container.isBound(MiddlewareClass);
|
|
505
|
+
let containerResolutionFailed = false;
|
|
506
|
+
// Cache instance for non-container-bound middleware (singleton per handler)
|
|
507
|
+
// Container-bound middleware relies on container scoping (singleton/request scope)
|
|
508
|
+
let cachedInstance;
|
|
509
|
+
return (req, res, next) => {
|
|
510
|
+
try {
|
|
511
|
+
let instance;
|
|
512
|
+
// Try container resolution first if bound and not previously failed
|
|
513
|
+
if (isContainerBound && !containerResolutionFailed) {
|
|
514
|
+
try {
|
|
515
|
+
// Resolve from container (supports DI, scoping, etc.)
|
|
516
|
+
// Container handles singleton/request scope automatically
|
|
517
|
+
instance = this._container.get(MiddlewareClass);
|
|
518
|
+
}
|
|
519
|
+
catch (containerError) {
|
|
520
|
+
// Container resolution failed (e.g., base class missing @injectable())
|
|
521
|
+
// Mark as failed and fall back to direct instantiation
|
|
522
|
+
containerResolutionFailed = true;
|
|
523
|
+
try {
|
|
524
|
+
// Create and cache instance if not already cached
|
|
525
|
+
if (!cachedInstance) {
|
|
526
|
+
cachedInstance = new MiddlewareClass();
|
|
527
|
+
}
|
|
528
|
+
instance = cachedInstance;
|
|
529
|
+
}
|
|
530
|
+
catch (instantiationError) {
|
|
531
|
+
next(instantiationError);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
// Create instance directly (no DI support or container not available)
|
|
538
|
+
// Cache instance for reuse across requests (singleton per handler)
|
|
539
|
+
if (!cachedInstance) {
|
|
540
|
+
try {
|
|
541
|
+
cachedInstance = new MiddlewareClass();
|
|
542
|
+
}
|
|
543
|
+
catch (instantiationError) {
|
|
544
|
+
next(instantiationError);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
instance = cachedInstance;
|
|
549
|
+
}
|
|
550
|
+
// Execute middleware (supports both sync and async)
|
|
551
|
+
// The middleware's use() method should call next() itself
|
|
552
|
+
// We pass the next function directly - when middleware calls next(),
|
|
553
|
+
// it will continue the Express middleware chain (or the composition chain)
|
|
554
|
+
try {
|
|
555
|
+
const result = instance.use(req, res, next);
|
|
556
|
+
// Handle async middleware that returns a Promise
|
|
557
|
+
// If it returns a Promise, return it so the chain can await it
|
|
558
|
+
if (result !== undefined && result !== null) {
|
|
559
|
+
const resultObj = result;
|
|
560
|
+
if (typeof resultObj === "object" &&
|
|
561
|
+
resultObj !== null &&
|
|
562
|
+
"then" in resultObj &&
|
|
563
|
+
typeof resultObj.then === "function") {
|
|
564
|
+
// Return the Promise so the chain can await it
|
|
565
|
+
// The middleware should have already called next(), but the chain
|
|
566
|
+
// will wait for the Promise to resolve/reject
|
|
567
|
+
return result.catch((error) => {
|
|
568
|
+
// If the Promise rejects and next() wasn't called with error, call it now
|
|
569
|
+
next(error);
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
// Synchronous middleware - returns void, chain relies on next() being called
|
|
574
|
+
}
|
|
575
|
+
catch (useError) {
|
|
576
|
+
// If use() throws synchronously, pass error to next()
|
|
577
|
+
next(useError);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
catch (error) {
|
|
581
|
+
// Catch any other errors
|
|
582
|
+
next(error);
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Creates a request handler for conditional middleware.
|
|
588
|
+
* Evaluates the condition and executes the wrapped middleware if condition is true.
|
|
589
|
+
*/
|
|
590
|
+
createConditionalMiddlewareHandler(config) {
|
|
591
|
+
// Resolve the wrapped middleware once (at route registration time)
|
|
592
|
+
const wrappedMiddlewareHandlers = this.resolveMiddleware(config.middleware);
|
|
593
|
+
return async (req, res, next) => {
|
|
594
|
+
try {
|
|
595
|
+
// Evaluate the condition (supports both sync and async)
|
|
596
|
+
const conditionResult = await config.condition(req);
|
|
597
|
+
// Determine if middleware should execute based on condition and skipOnFalse flag
|
|
598
|
+
const shouldExecute = config.skipOnFalse !== false ? conditionResult : !conditionResult;
|
|
599
|
+
if (shouldExecute) {
|
|
600
|
+
// Condition met, execute the wrapped middleware
|
|
601
|
+
// The wrapped middleware handlers are already Express RequestHandlers,
|
|
602
|
+
// so we can execute them directly. They will call next() when done,
|
|
603
|
+
// which will continue to the next middleware in the route.
|
|
604
|
+
if (wrappedMiddlewareHandlers.length === 0) {
|
|
605
|
+
// No middleware to execute, just continue
|
|
606
|
+
next();
|
|
607
|
+
}
|
|
608
|
+
else if (wrappedMiddlewareHandlers.length === 1) {
|
|
609
|
+
// Single middleware, execute it directly
|
|
610
|
+
wrappedMiddlewareHandlers[0](req, res, next);
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
// Multiple middleware, execute them sequentially
|
|
614
|
+
await this.executeMiddlewareChain(wrappedMiddlewareHandlers, req, res, next);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
else {
|
|
618
|
+
// Condition not met, skip middleware and continue to next middleware in route
|
|
619
|
+
next();
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
catch (error) {
|
|
623
|
+
// If condition evaluation throws, pass error to error handler
|
|
624
|
+
next(error);
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Creates a request handler for composed middleware (Phase 3: Middleware Composition).
|
|
630
|
+
* Executes all middleware in the composition sequentially.
|
|
631
|
+
* Both 'combine' and 'sequence' types behave the same way - they execute middleware
|
|
632
|
+
* sequentially and propagate errors normally (Express handles errors via next(error)).
|
|
633
|
+
*
|
|
634
|
+
* @param config - ComposedMiddlewareConfig containing the middleware array and type
|
|
635
|
+
* @returns Express RequestHandler
|
|
636
|
+
*/
|
|
637
|
+
createComposedMiddlewareHandler(config) {
|
|
638
|
+
// Resolve all middleware in the composition to Express RequestHandlers
|
|
639
|
+
const resolvedHandlers = config.middleware.flatMap((mw) => this.resolveMiddleware(mw));
|
|
640
|
+
return async (req, res, next) => {
|
|
641
|
+
try {
|
|
642
|
+
if (resolvedHandlers.length === 0) {
|
|
643
|
+
// No middleware to execute, just continue
|
|
644
|
+
next();
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
// Execute all middleware sequentially
|
|
648
|
+
// Both 'combine' and 'sequence' use the same execution logic
|
|
649
|
+
// Express's error handling (via next(error)) naturally stops execution
|
|
650
|
+
await this.executeMiddlewareChain(resolvedHandlers, req, res, next);
|
|
651
|
+
}
|
|
652
|
+
catch (error) {
|
|
653
|
+
// If execution throws an error, pass it to Express error handler
|
|
654
|
+
next(error);
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Executes a chain of middleware handlers sequentially.
|
|
660
|
+
* Each middleware calls next() to proceed to the next one.
|
|
661
|
+
* Handles both synchronous and asynchronous middleware.
|
|
662
|
+
*/
|
|
663
|
+
executeMiddlewareChain(handlers, req, res, next) {
|
|
664
|
+
return new Promise((resolve, reject) => {
|
|
665
|
+
let index = 0;
|
|
666
|
+
const runNext = (err) => {
|
|
667
|
+
if (err) {
|
|
668
|
+
reject(err);
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
if (index >= handlers.length) {
|
|
672
|
+
// All middleware executed successfully, call Express next() to continue to route handler
|
|
673
|
+
next();
|
|
674
|
+
resolve();
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
const handler = handlers[index++];
|
|
678
|
+
try {
|
|
679
|
+
// Execute the handler
|
|
680
|
+
// Express middleware handlers can:
|
|
681
|
+
// 1. Call next() synchronously
|
|
682
|
+
// 2. Call next() asynchronously
|
|
683
|
+
// 3. Return a Promise
|
|
684
|
+
// 4. Return nothing (void)
|
|
685
|
+
const result = handler(req, res, (err) => {
|
|
686
|
+
if (err) {
|
|
687
|
+
reject(err);
|
|
688
|
+
}
|
|
689
|
+
else {
|
|
690
|
+
// Handler called next() successfully, proceed to next middleware
|
|
691
|
+
runNext();
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
// If handler returns a Promise, wait for it
|
|
695
|
+
// Note: Even if handler returns a Promise, it should still call next()
|
|
696
|
+
// But we handle the Promise in case it doesn't
|
|
697
|
+
// Check if result exists and is a Promise-like object (thenable)
|
|
698
|
+
if (result !== undefined && result !== null) {
|
|
699
|
+
const resultObj = result;
|
|
700
|
+
if (typeof resultObj === "object" &&
|
|
701
|
+
resultObj !== null &&
|
|
702
|
+
"then" in resultObj &&
|
|
703
|
+
typeof resultObj.then === "function") {
|
|
704
|
+
result
|
|
705
|
+
.then(() => {
|
|
706
|
+
// If Promise resolves and next wasn't called, proceed
|
|
707
|
+
if (index <= handlers.length) {
|
|
708
|
+
runNext();
|
|
709
|
+
}
|
|
710
|
+
})
|
|
711
|
+
.catch(reject);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
// If handler doesn't return a Promise and doesn't call next(),
|
|
715
|
+
// we rely on the handler to call next() itself
|
|
716
|
+
}
|
|
717
|
+
catch (error) {
|
|
718
|
+
reject(error);
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
runNext();
|
|
722
|
+
});
|
|
723
|
+
}
|
|
169
724
|
copyHeadersTo(headers, target) {
|
|
170
725
|
for (const name of Object.keys(headers)) {
|
|
171
726
|
const headerValue = headers[name];
|
|
@@ -186,43 +741,234 @@ class InversifyExpressServer {
|
|
|
186
741
|
res.sendStatus(message.statusCode);
|
|
187
742
|
}
|
|
188
743
|
}
|
|
189
|
-
handlerFactory(controllerName, key, parameterMetadata) {
|
|
190
|
-
|
|
744
|
+
handlerFactory(controllerName, key, parameterMetadata, controllerConstructor, methodMetadata) {
|
|
745
|
+
// Extract guards from controller and method metadata
|
|
746
|
+
const controllerGuards = controllerConstructor
|
|
747
|
+
? (0, guard_utils_js_1.getControllerGuards)(controllerConstructor)
|
|
748
|
+
: [];
|
|
749
|
+
const methodGuards = controllerConstructor ? (0, guard_utils_js_1.getMethodGuards)(controllerConstructor, key) : [];
|
|
750
|
+
const allGuards = [...controllerGuards, ...methodGuards];
|
|
751
|
+
// Create guard middleware if guards exist
|
|
752
|
+
let guardMiddleware = null;
|
|
753
|
+
if (allGuards.length > 0) {
|
|
191
754
|
try {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const { template, defaultData } = (0, decorators_1.getRenderMetadata)(controller, key);
|
|
199
|
-
if (template) {
|
|
200
|
-
const data = value || defaultData || {};
|
|
201
|
-
res.render(template, data);
|
|
755
|
+
// Check if guard system is initialized (use class identifiers, not strings)
|
|
756
|
+
if (this._container.isBound(core_1.GuardExecutor) &&
|
|
757
|
+
this._container.isBound(guard_context_factory_js_1.GuardContextFactory) &&
|
|
758
|
+
this._container.isBound(guard_middleware_js_1.GuardMiddleware)) {
|
|
759
|
+
const guardMiddlewareInstance = this._container.get(guard_middleware_js_1.GuardMiddleware);
|
|
760
|
+
guardMiddleware = guardMiddlewareInstance.execute;
|
|
202
761
|
}
|
|
203
|
-
|
|
204
|
-
|
|
762
|
+
}
|
|
763
|
+
catch (error) {
|
|
764
|
+
// Guard system not initialized, continue without guards
|
|
765
|
+
console.error("[Guard System] Failed to initialize:", error);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
// Create handler function
|
|
769
|
+
const handler = async (req, res, next) => {
|
|
770
|
+
try {
|
|
771
|
+
// Attach controller and method metadata to request for exception handler middleware
|
|
772
|
+
// This provides a reliable fallback if route stack extraction fails
|
|
773
|
+
if (controllerConstructor) {
|
|
774
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
775
|
+
req.__expressotsController = controllerConstructor;
|
|
776
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
777
|
+
req.__expressotsMethod = key;
|
|
778
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
779
|
+
req.__expressotsControllerName = controllerName;
|
|
780
|
+
// Attach guards to request for guard middleware
|
|
781
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
782
|
+
req.__expressotsControllerGuards = controllerGuards;
|
|
783
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
784
|
+
req.__expressotsMethodGuards = methodGuards;
|
|
205
785
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
786
|
+
// Execute guard middleware if guards exist
|
|
787
|
+
if (guardMiddleware && allGuards.length > 0) {
|
|
788
|
+
return guardMiddleware(req, res, async (err) => {
|
|
789
|
+
if (err) {
|
|
790
|
+
return next(err);
|
|
791
|
+
}
|
|
792
|
+
// Guards passed, continue to route handler
|
|
793
|
+
await this.executeRouteHandler(req, res, next, controllerName, key, parameterMetadata, controllerConstructor);
|
|
794
|
+
});
|
|
209
795
|
}
|
|
210
|
-
|
|
211
|
-
|
|
796
|
+
// No guards, execute route handler directly
|
|
797
|
+
await this.executeRouteHandler(req, res, next, controllerName, key, parameterMetadata, controllerConstructor);
|
|
798
|
+
}
|
|
799
|
+
catch (error) {
|
|
800
|
+
next(error);
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
return handler;
|
|
804
|
+
}
|
|
805
|
+
async executeRouteHandler(req, res, next, controllerName, key, parameterMetadata, controllerConstructor) {
|
|
806
|
+
// Get request ID for flow tracking
|
|
807
|
+
const requestContext = core_1.ContextManager.getCurrentContext();
|
|
808
|
+
const requestId = requestContext?.requestId;
|
|
809
|
+
const flowTracker = requestId ? (0, core_1.findFlowTracker)(requestId) : undefined;
|
|
810
|
+
const controllerStepName = `${controllerName}.${key}`;
|
|
811
|
+
try {
|
|
812
|
+
let args = this.extractParameters(req, res, next, parameterMetadata);
|
|
813
|
+
const httpContext = this._getHttpContext(req);
|
|
814
|
+
httpContext.container.bind(constants_js_1.TYPE.HttpContext).toConstantValue(httpContext);
|
|
815
|
+
// Validate parameters if validation service is enabled
|
|
816
|
+
const validationService = this.getValidationService();
|
|
817
|
+
if (validationService?.isEnabled() && controllerConstructor) {
|
|
818
|
+
// Check if there are actually validation metadata (has @validatedBody, @validatedQuery, etc.)
|
|
819
|
+
const validationMetadata = (0, validation_decorators_js_1.getValidationMetadata)(controllerConstructor, key);
|
|
820
|
+
const hasValidatedParams = validationMetadata.length > 0;
|
|
821
|
+
if (hasValidatedParams) {
|
|
822
|
+
// Start validation step only if there are validated parameters
|
|
823
|
+
if (flowTracker?.isEnabled()) {
|
|
824
|
+
flowTracker.startStep("validation", `Validation: ${controllerName}.${key}`);
|
|
825
|
+
}
|
|
826
|
+
const validatedArgs = await validationService.validateParameters(req, res, controllerConstructor, key, args);
|
|
827
|
+
if (validatedArgs === null) {
|
|
828
|
+
// Validation failed, response already sent
|
|
829
|
+
// Create a validation error to store on request
|
|
830
|
+
const validationError = new Error("Validation failed");
|
|
831
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
832
|
+
req.__expressotsFlowError = validationError;
|
|
833
|
+
if (flowTracker?.isEnabled()) {
|
|
834
|
+
flowTracker.failStep(validationError);
|
|
835
|
+
}
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
// End validation step
|
|
839
|
+
if (flowTracker?.isEnabled()) {
|
|
840
|
+
flowTracker.endStep("success");
|
|
841
|
+
}
|
|
842
|
+
args = validatedArgs;
|
|
212
843
|
}
|
|
213
|
-
else
|
|
214
|
-
|
|
215
|
-
|
|
844
|
+
else {
|
|
845
|
+
// No validation metadata, but validation service might still run smart detection
|
|
846
|
+
// Only track if smart detection actually finds something to validate
|
|
847
|
+
const validatedArgs = await validationService.validateParameters(req, res, controllerConstructor, key, args);
|
|
848
|
+
if (validatedArgs === null) {
|
|
849
|
+
// Smart detection found validation errors
|
|
850
|
+
return;
|
|
216
851
|
}
|
|
852
|
+
args = validatedArgs;
|
|
217
853
|
}
|
|
218
854
|
}
|
|
219
|
-
|
|
220
|
-
|
|
855
|
+
// Start controller step
|
|
856
|
+
if (flowTracker?.isEnabled()) {
|
|
857
|
+
flowTracker.startStep("controller", controllerStepName, {
|
|
858
|
+
controller: controllerName,
|
|
859
|
+
method: key,
|
|
860
|
+
});
|
|
221
861
|
}
|
|
222
|
-
|
|
862
|
+
// invoke controller's action
|
|
863
|
+
const controller = httpContext.container.getNamed(constants_js_1.TYPE.Controller, controllerName);
|
|
864
|
+
const value = await controller[key](...args);
|
|
865
|
+
// End controller step
|
|
866
|
+
if (flowTracker?.isEnabled()) {
|
|
867
|
+
flowTracker.endStep("success");
|
|
868
|
+
}
|
|
869
|
+
const { template, defaultData } = (0, decorators_js_1.getRenderMetadata)(controller, key);
|
|
870
|
+
if (template) {
|
|
871
|
+
const data = value || defaultData || {};
|
|
872
|
+
res.render(template, data);
|
|
873
|
+
}
|
|
874
|
+
else if (value instanceof httpResponseMessage_js_1.HttpResponseMessage) {
|
|
875
|
+
await this.handleHttpResponseMessage(value, res);
|
|
876
|
+
}
|
|
877
|
+
else if ((0, utils_js_1.instanceOfIHttpActionResult)(value)) {
|
|
878
|
+
const httpResponseMessage = await value.executeAsync();
|
|
879
|
+
await this.handleHttpResponseMessage(httpResponseMessage, res);
|
|
880
|
+
}
|
|
881
|
+
else if (value instanceof Function) {
|
|
882
|
+
value();
|
|
883
|
+
}
|
|
884
|
+
else if (!res.headersSent) {
|
|
885
|
+
// Smart response handling: Auto-404 for GET requests returning null/undefined
|
|
886
|
+
// This is a common pattern where null means "resource not found"
|
|
887
|
+
if (value === null || value === undefined) {
|
|
888
|
+
const method = req.method.toUpperCase();
|
|
889
|
+
// For GET requests, null/undefined typically means "not found"
|
|
890
|
+
// For DELETE requests, undefined means "successfully deleted" (204 No Content is already set)
|
|
891
|
+
if (method === "GET") {
|
|
892
|
+
// Extract resource info from path for helpful error message
|
|
893
|
+
const pathParts = req.path.split("/").filter(Boolean);
|
|
894
|
+
const resource = pathParts[pathParts.length - 2] || "Resource";
|
|
895
|
+
const id = req.params?.id || pathParts[pathParts.length - 1];
|
|
896
|
+
throw new core_1.NotFoundError(resource, id);
|
|
897
|
+
}
|
|
898
|
+
// For other methods (DELETE, PUT, PATCH), undefined is valid (204 No Content)
|
|
899
|
+
// The HttpStatusCodeMiddleware already sets appropriate status codes
|
|
900
|
+
if (method !== "DELETE" && method !== "PUT" && method !== "PATCH") {
|
|
901
|
+
// For POST or other methods with null/undefined, send empty response
|
|
902
|
+
res.end();
|
|
903
|
+
}
|
|
904
|
+
// For DELETE/PUT/PATCH, the middleware already set 204, just end the response
|
|
905
|
+
else {
|
|
906
|
+
res.end();
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
else {
|
|
910
|
+
// Try content negotiation if enabled
|
|
911
|
+
const cnMetadata = (0, utils_js_1.getContentNegotiationMetadata)(controller, key);
|
|
912
|
+
const contentNegotiationService = this.getContentNegotiationService();
|
|
913
|
+
if (contentNegotiationService?.isEnabled()) {
|
|
914
|
+
const handled = await contentNegotiationService.handleResponse(req, res, value, cnMetadata.accept || cnMetadata.produces);
|
|
915
|
+
if (handled) {
|
|
916
|
+
return; // Response already sent
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
// Fallback to default behavior (backward compatible)
|
|
920
|
+
res.send(value);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
catch (err) {
|
|
925
|
+
// Store error on request for flow tracking
|
|
926
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
927
|
+
req.__expressotsFlowError = err instanceof Error ? err : new Error(String(err));
|
|
928
|
+
// End controller step with failure if not already ended
|
|
929
|
+
if (flowTracker?.isEnabled()) {
|
|
930
|
+
const currentFlow = flowTracker.getFlow();
|
|
931
|
+
const lastStep = currentFlow.steps[currentFlow.steps.length - 1];
|
|
932
|
+
if (lastStep && lastStep.name === controllerStepName && lastStep.status === "success") {
|
|
933
|
+
// Step was already ended, don't end again
|
|
934
|
+
}
|
|
935
|
+
else {
|
|
936
|
+
flowTracker.failStep(err instanceof Error ? err : undefined);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
next(err);
|
|
940
|
+
}
|
|
223
941
|
}
|
|
224
942
|
_getHttpContext(req) {
|
|
225
|
-
return
|
|
943
|
+
return (0, http_context_store_js_1.getHttpContext)(req);
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Sets the content negotiation service instance.
|
|
947
|
+
* @param service - Content negotiation service instance
|
|
948
|
+
*/
|
|
949
|
+
setContentNegotiationService(service) {
|
|
950
|
+
this._contentNegotiationService = service;
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Gets the content negotiation service if available.
|
|
954
|
+
* @returns Content negotiation service or undefined
|
|
955
|
+
*/
|
|
956
|
+
getContentNegotiationService() {
|
|
957
|
+
return this._contentNegotiationService;
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* Sets the validation service instance.
|
|
961
|
+
* @param service - Validation service instance
|
|
962
|
+
*/
|
|
963
|
+
setValidationService(service) {
|
|
964
|
+
this._validationService = service;
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* Gets the validation service if available.
|
|
968
|
+
* @returns Validation service or undefined
|
|
969
|
+
*/
|
|
970
|
+
getValidationService() {
|
|
971
|
+
return this._validationService;
|
|
226
972
|
}
|
|
227
973
|
async _createHttpContext(req, res, next) {
|
|
228
974
|
const principal = await this._getCurrentUser(req, res, next);
|
|
@@ -236,8 +982,9 @@ class InversifyExpressServer {
|
|
|
236
982
|
};
|
|
237
983
|
}
|
|
238
984
|
async _getCurrentUser(req, res, next) {
|
|
239
|
-
if (
|
|
240
|
-
|
|
985
|
+
// Check if AuthProvider is available (either via constructor or bound via setupAuthorizationForExpress)
|
|
986
|
+
if (this._AuthProvider !== undefined || this._container.isBound(constants_js_1.TYPE.AuthProvider)) {
|
|
987
|
+
const authProvider = this._container.get(constants_js_1.TYPE.AuthProvider);
|
|
241
988
|
return authProvider.getUser(req, res, next);
|
|
242
989
|
}
|
|
243
990
|
return Promise.resolve({
|
|
@@ -254,28 +1001,28 @@ class InversifyExpressServer {
|
|
|
254
1001
|
}
|
|
255
1002
|
params.forEach(({ type, index, parameterName, injectRoot }) => {
|
|
256
1003
|
switch (type) {
|
|
257
|
-
case
|
|
1004
|
+
case constants_js_1.PARAMETER_TYPE.REQUEST:
|
|
258
1005
|
args[index] = req;
|
|
259
1006
|
break;
|
|
260
|
-
case
|
|
1007
|
+
case constants_js_1.PARAMETER_TYPE.NEXT:
|
|
261
1008
|
args[index] = next;
|
|
262
1009
|
break;
|
|
263
|
-
case
|
|
1010
|
+
case constants_js_1.PARAMETER_TYPE.PARAMS:
|
|
264
1011
|
args[index] = this.getParam(req, "params", injectRoot, parameterName);
|
|
265
1012
|
break;
|
|
266
|
-
case
|
|
1013
|
+
case constants_js_1.PARAMETER_TYPE.QUERY:
|
|
267
1014
|
args[index] = this.getParam(req, "query", injectRoot, parameterName);
|
|
268
1015
|
break;
|
|
269
|
-
case
|
|
1016
|
+
case constants_js_1.PARAMETER_TYPE.BODY:
|
|
270
1017
|
args[index] = req.body;
|
|
271
1018
|
break;
|
|
272
|
-
case
|
|
1019
|
+
case constants_js_1.PARAMETER_TYPE.HEADERS:
|
|
273
1020
|
args[index] = this.getParam(req, "headers", injectRoot, parameterName);
|
|
274
1021
|
break;
|
|
275
|
-
case
|
|
1022
|
+
case constants_js_1.PARAMETER_TYPE.COOKIES:
|
|
276
1023
|
args[index] = this.getParam(req, "cookies", injectRoot, parameterName);
|
|
277
1024
|
break;
|
|
278
|
-
case
|
|
1025
|
+
case constants_js_1.PARAMETER_TYPE.PRINCIPAL:
|
|
279
1026
|
args[index] = this._getPrincipal(req);
|
|
280
1027
|
break;
|
|
281
1028
|
default:
|