1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.MiddlewareModule = void 0;
|
4 | const common_1 = require("@nestjs/common");
|
5 | const request_method_enum_1 = require("@nestjs/common/enums/request-method.enum");
|
6 | const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
|
7 | const invalid_middleware_exception_1 = require("../errors/exceptions/invalid-middleware.exception");
|
8 | const runtime_exception_1 = require("../errors/exceptions/runtime.exception");
|
9 | const context_id_factory_1 = require("../helpers/context-id-factory");
|
10 | const execution_context_host_1 = require("../helpers/execution-context-host");
|
11 | const constants_1 = require("../injector/constants");
|
12 | const request_constants_1 = require("../router/request/request-constants");
|
13 | const router_exception_filters_1 = require("../router/router-exception-filters");
|
14 | const router_proxy_1 = require("../router/router-proxy");
|
15 | const utils_1 = require("../router/utils");
|
16 | const builder_1 = require("./builder");
|
17 | const resolver_1 = require("./resolver");
|
18 | const route_info_path_extractor_1 = require("./route-info-path-extractor");
|
19 | const routes_mapper_1 = require("./routes-mapper");
|
20 | class MiddlewareModule {
|
21 | constructor() {
|
22 | this.routerProxy = new router_proxy_1.RouterProxy();
|
23 | this.exceptionFiltersCache = new WeakMap();
|
24 | this.logger = new common_1.Logger(MiddlewareModule.name);
|
25 | }
|
26 | async register(middlewareContainer, container, config, injector, httpAdapter, graphInspector, options) {
|
27 | this.appOptions = options;
|
28 | const appRef = container.getHttpAdapterRef();
|
29 | this.routerExceptionFilter = new router_exception_filters_1.RouterExceptionFilters(container, config, appRef);
|
30 | this.routesMapper = new routes_mapper_1.RoutesMapper(container);
|
31 | this.resolver = new resolver_1.MiddlewareResolver(middlewareContainer, injector);
|
32 | this.routeInfoPathExtractor = new route_info_path_extractor_1.RouteInfoPathExtractor(config);
|
33 | this.injector = injector;
|
34 | this.container = container;
|
35 | this.httpAdapter = httpAdapter;
|
36 | this.graphInspector = graphInspector;
|
37 | const modules = container.getModules();
|
38 | await this.resolveMiddleware(middlewareContainer, modules);
|
39 | }
|
40 | async resolveMiddleware(middlewareContainer, modules) {
|
41 | const moduleEntries = [...modules.entries()];
|
42 | const loadMiddlewareConfiguration = async ([moduleName, moduleRef]) => {
|
43 | await this.loadConfiguration(middlewareContainer, moduleRef, moduleName);
|
44 | await this.resolver.resolveInstances(moduleRef, moduleName);
|
45 | };
|
46 | await Promise.all(moduleEntries.map(loadMiddlewareConfiguration));
|
47 | }
|
48 | async loadConfiguration(middlewareContainer, moduleRef, moduleKey) {
|
49 | const { instance } = moduleRef;
|
50 | if (!instance.configure) {
|
51 | return;
|
52 | }
|
53 | const middlewareBuilder = new builder_1.MiddlewareBuilder(this.routesMapper, this.httpAdapter, this.routeInfoPathExtractor);
|
54 | try {
|
55 | await instance.configure(middlewareBuilder);
|
56 | }
|
57 | catch (err) {
|
58 | if (!this.appOptions.preview) {
|
59 | throw err;
|
60 | }
|
61 | const warningMessage = `Warning! "${moduleRef.name}" module exposes a "configure" method that throws an exception in the preview mode` +
|
62 | ` (possibly due to missing dependencies). Note: you can ignore this message, just be aware that some of those conditional middlewares will not be reflected in your graph.`;
|
63 | this.logger.warn(warningMessage);
|
64 | }
|
65 | if (!(middlewareBuilder instanceof builder_1.MiddlewareBuilder)) {
|
66 | return;
|
67 | }
|
68 | const config = middlewareBuilder.build();
|
69 | middlewareContainer.insertConfig(config, moduleKey);
|
70 | }
|
71 | async registerMiddleware(middlewareContainer, applicationRef) {
|
72 | const configs = middlewareContainer.getConfigurations();
|
73 | const registerAllConfigs = async (moduleKey, middlewareConfig) => {
|
74 | for (const config of middlewareConfig) {
|
75 | await this.registerMiddlewareConfig(middlewareContainer, config, moduleKey, applicationRef);
|
76 | }
|
77 | };
|
78 | const entriesSortedByDistance = [...configs.entries()].sort(([moduleA], [moduleB]) => {
|
79 | return (this.container.getModuleByKey(moduleA).distance -
|
80 | this.container.getModuleByKey(moduleB).distance);
|
81 | });
|
82 | for (const [moduleRef, moduleConfigurations] of entriesSortedByDistance) {
|
83 | await registerAllConfigs(moduleRef, [...moduleConfigurations]);
|
84 | }
|
85 | }
|
86 | async registerMiddlewareConfig(middlewareContainer, config, moduleKey, applicationRef) {
|
87 | const { forRoutes } = config;
|
88 | for (const routeInfo of forRoutes) {
|
89 | await this.registerRouteMiddleware(middlewareContainer, routeInfo, config, moduleKey, applicationRef);
|
90 | }
|
91 | }
|
92 | async registerRouteMiddleware(middlewareContainer, routeInfo, config, moduleKey, applicationRef) {
|
93 | var _a;
|
94 | const middlewareCollection = [].concat(config.middleware);
|
95 | const moduleRef = this.container.getModuleByKey(moduleKey);
|
96 | for (const metatype of middlewareCollection) {
|
97 | const collection = middlewareContainer.getMiddlewareCollection(moduleKey);
|
98 | const instanceWrapper = collection.get(metatype);
|
99 | if ((0, shared_utils_1.isUndefined)(instanceWrapper)) {
|
100 | throw new runtime_exception_1.RuntimeException();
|
101 | }
|
102 | if (instanceWrapper.isTransient) {
|
103 | return;
|
104 | }
|
105 | this.graphInspector.insertClassNode(moduleRef, instanceWrapper, 'middleware');
|
106 | const middlewareDefinition = {
|
107 | type: 'middleware',
|
108 | methodName: 'use',
|
109 | className: instanceWrapper.name,
|
110 | classNodeId: instanceWrapper.id,
|
111 | metadata: {
|
112 | key: routeInfo.path,
|
113 | path: routeInfo.path,
|
114 | requestMethod: (_a = request_method_enum_1.RequestMethod[routeInfo.method]) !== null && _a !== void 0 ? _a : 'ALL',
|
115 | version: routeInfo.version,
|
116 | },
|
117 | };
|
118 | this.graphInspector.insertEntrypointDefinition(middlewareDefinition, instanceWrapper.id);
|
119 | await this.bindHandler(instanceWrapper, applicationRef, routeInfo, moduleRef, collection);
|
120 | }
|
121 | }
|
122 | async bindHandler(wrapper, applicationRef, routeInfo, moduleRef, collection) {
|
123 | const { instance, metatype } = wrapper;
|
124 | if ((0, shared_utils_1.isUndefined)(instance === null || instance === void 0 ? void 0 : instance.use)) {
|
125 | throw new invalid_middleware_exception_1.InvalidMiddlewareException(metatype.name);
|
126 | }
|
127 | const isStatic = wrapper.isDependencyTreeStatic();
|
128 | if (isStatic) {
|
129 | const proxy = await this.createProxy(instance);
|
130 | return this.registerHandler(applicationRef, routeInfo, proxy);
|
131 | }
|
132 | const isTreeDurable = wrapper.isDependencyTreeDurable();
|
133 | await this.registerHandler(applicationRef, routeInfo, async (req, res, next) => {
|
134 | try {
|
135 | const contextId = this.getContextId(req, isTreeDurable);
|
136 | const contextInstance = await this.injector.loadPerContext(instance, moduleRef, collection, contextId);
|
137 | const proxy = await this.createProxy(contextInstance, contextId);
|
138 | return proxy(req, res, next);
|
139 | }
|
140 | catch (err) {
|
141 | let exceptionsHandler = this.exceptionFiltersCache.get(instance.use);
|
142 | if (!exceptionsHandler) {
|
143 | exceptionsHandler = this.routerExceptionFilter.create(instance, instance.use, undefined);
|
144 | this.exceptionFiltersCache.set(instance.use, exceptionsHandler);
|
145 | }
|
146 | const host = new execution_context_host_1.ExecutionContextHost([req, res, next]);
|
147 | exceptionsHandler.next(err, host);
|
148 | }
|
149 | });
|
150 | }
|
151 | async createProxy(instance, contextId = constants_1.STATIC_CONTEXT) {
|
152 | const exceptionsHandler = this.routerExceptionFilter.create(instance, instance.use, undefined, contextId);
|
153 | const middleware = instance.use.bind(instance);
|
154 | return this.routerProxy.createProxy(middleware, exceptionsHandler);
|
155 | }
|
156 | async registerHandler(applicationRef, routeInfo, proxy) {
|
157 | const { method } = routeInfo;
|
158 | const paths = this.routeInfoPathExtractor.extractPathsFrom(routeInfo);
|
159 | const isMethodAll = (0, utils_1.isRequestMethodAll)(method);
|
160 | const requestMethod = request_method_enum_1.RequestMethod[method];
|
161 | const router = await applicationRef.createMiddlewareFactory(method);
|
162 | const middlewareFunction = isMethodAll
|
163 | ? proxy
|
164 | : (req, res, next) => {
|
165 | if (applicationRef.getRequestMethod(req) === requestMethod) {
|
166 | return proxy(req, res, next);
|
167 | }
|
168 | return next();
|
169 | };
|
170 | paths.forEach(path => router(path, middlewareFunction));
|
171 | }
|
172 | getContextId(request, isTreeDurable) {
|
173 | const contextId = context_id_factory_1.ContextIdFactory.getByRequest(request);
|
174 | if (!request[request_constants_1.REQUEST_CONTEXT_ID]) {
|
175 | Object.defineProperty(request, request_constants_1.REQUEST_CONTEXT_ID, {
|
176 | value: contextId,
|
177 | enumerable: false,
|
178 | writable: false,
|
179 | configurable: false,
|
180 | });
|
181 | const requestProviderValue = isTreeDurable ? contextId.payload : request;
|
182 | this.container.registerRequestProvider(requestProviderValue, contextId);
|
183 | }
|
184 | return contextId;
|
185 | }
|
186 | }
|
187 | exports.MiddlewareModule = MiddlewareModule;
|