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