UNPKG

10.4 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.RouterExecutionContext = void 0;
4const common_1 = require("@nestjs/common");
5const constants_1 = require("@nestjs/common/constants");
6const route_paramtypes_enum_1 = require("@nestjs/common/enums/route-paramtypes.enum");
7const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
8const constants_2 = require("../guards/constants");
9const context_utils_1 = require("../helpers/context-utils");
10const handler_metadata_storage_1 = require("../helpers/handler-metadata-storage");
11const constants_3 = require("../injector/constants");
12const router_response_controller_1 = require("./router-response-controller");
13class RouterExecutionContext {
14 constructor(paramsFactory, pipesContextCreator, pipesConsumer, guardsContextCreator, guardsConsumer, interceptorsContextCreator, interceptorsConsumer, applicationRef) {
15 this.paramsFactory = paramsFactory;
16 this.pipesContextCreator = pipesContextCreator;
17 this.pipesConsumer = pipesConsumer;
18 this.guardsContextCreator = guardsContextCreator;
19 this.guardsConsumer = guardsConsumer;
20 this.interceptorsContextCreator = interceptorsContextCreator;
21 this.interceptorsConsumer = interceptorsConsumer;
22 this.applicationRef = applicationRef;
23 this.handlerMetadataStorage = new handler_metadata_storage_1.HandlerMetadataStorage();
24 this.contextUtils = new context_utils_1.ContextUtils();
25 this.responseController = new router_response_controller_1.RouterResponseController(applicationRef);
26 }
27 create(instance, callback, methodName, moduleKey, requestMethod, contextId = constants_3.STATIC_CONTEXT, inquirerId) {
28 const contextType = 'http';
29 const { argsLength, fnHandleResponse, paramtypes, getParamsMetadata, httpStatusCode, responseHeaders, hasCustomHeaders, } = this.getMetadata(instance, callback, methodName, moduleKey, requestMethod, contextType);
30 const paramsOptions = this.contextUtils.mergeParamsMetatypes(getParamsMetadata(moduleKey, contextId, inquirerId), paramtypes);
31 const pipes = this.pipesContextCreator.create(instance, callback, moduleKey, contextId, inquirerId);
32 const guards = this.guardsContextCreator.create(instance, callback, moduleKey, contextId, inquirerId);
33 const interceptors = this.interceptorsContextCreator.create(instance, callback, moduleKey, contextId, inquirerId);
34 const fnCanActivate = this.createGuardsFn(guards, instance, callback, contextType);
35 const fnApplyPipes = this.createPipesFn(pipes, paramsOptions);
36 const handler = (args, req, res, next) => async () => {
37 fnApplyPipes && (await fnApplyPipes(args, req, res, next));
38 return callback.apply(instance, args);
39 };
40 return async (req, res, next) => {
41 const args = this.contextUtils.createNullArray(argsLength);
42 fnCanActivate && (await fnCanActivate([req, res, next]));
43 this.responseController.setStatus(res, httpStatusCode);
44 hasCustomHeaders &&
45 this.responseController.setHeaders(res, responseHeaders);
46 const result = await this.interceptorsConsumer.intercept(interceptors, [req, res, next], instance, callback, handler(args, req, res, next), contextType);
47 await fnHandleResponse(result, res, req);
48 };
49 }
50 getMetadata(instance, callback, methodName, moduleKey, requestMethod, contextType) {
51 const cacheMetadata = this.handlerMetadataStorage.get(instance, methodName);
52 if (cacheMetadata) {
53 return cacheMetadata;
54 }
55 const metadata = this.contextUtils.reflectCallbackMetadata(instance, methodName, constants_1.ROUTE_ARGS_METADATA) || {};
56 const keys = Object.keys(metadata);
57 const argsLength = this.contextUtils.getArgumentsLength(keys, metadata);
58 const paramtypes = this.contextUtils.reflectCallbackParamtypes(instance, methodName);
59 const contextFactory = this.contextUtils.getContextFactory(contextType, instance, callback);
60 const getParamsMetadata = (moduleKey, contextId = constants_3.STATIC_CONTEXT, inquirerId) => this.exchangeKeysForValues(keys, metadata, moduleKey, contextId, inquirerId, contextFactory);
61 const paramsMetadata = getParamsMetadata(moduleKey);
62 const isResponseHandled = this.isResponseHandled(instance, methodName, paramsMetadata);
63 const httpRedirectResponse = this.reflectRedirect(callback);
64 const fnHandleResponse = this.createHandleResponseFn(callback, isResponseHandled, httpRedirectResponse);
65 const httpCode = this.reflectHttpStatusCode(callback);
66 const httpStatusCode = httpCode
67 ? httpCode
68 : this.responseController.getStatusByMethod(requestMethod);
69 const responseHeaders = this.reflectResponseHeaders(callback);
70 const hasCustomHeaders = !shared_utils_1.isEmpty(responseHeaders);
71 const handlerMetadata = {
72 argsLength,
73 fnHandleResponse,
74 paramtypes,
75 getParamsMetadata,
76 httpStatusCode,
77 hasCustomHeaders,
78 responseHeaders,
79 };
80 this.handlerMetadataStorage.set(instance, methodName, handlerMetadata);
81 return handlerMetadata;
82 }
83 reflectRedirect(callback) {
84 return Reflect.getMetadata(constants_1.REDIRECT_METADATA, callback);
85 }
86 reflectHttpStatusCode(callback) {
87 return Reflect.getMetadata(constants_1.HTTP_CODE_METADATA, callback);
88 }
89 reflectRenderTemplate(callback) {
90 return Reflect.getMetadata(constants_1.RENDER_METADATA, callback);
91 }
92 reflectResponseHeaders(callback) {
93 return Reflect.getMetadata(constants_1.HEADERS_METADATA, callback) || [];
94 }
95 reflectSse(callback) {
96 return Reflect.getMetadata(constants_1.SSE_METADATA, callback);
97 }
98 exchangeKeysForValues(keys, metadata, moduleContext, contextId = constants_3.STATIC_CONTEXT, inquirerId, contextFactory) {
99 this.pipesContextCreator.setModuleContext(moduleContext);
100 return keys.map(key => {
101 const { index, data, pipes: pipesCollection } = metadata[key];
102 const pipes = this.pipesContextCreator.createConcreteContext(pipesCollection, contextId, inquirerId);
103 const type = this.contextUtils.mapParamType(key);
104 if (key.includes(constants_1.CUSTOM_ROUTE_AGRS_METADATA)) {
105 const { factory } = metadata[key];
106 const customExtractValue = this.contextUtils.getCustomFactory(factory, data, contextFactory);
107 return { index, extractValue: customExtractValue, type, data, pipes };
108 }
109 const numericType = Number(type);
110 const extractValue = (req, res, next) => this.paramsFactory.exchangeKeyForValue(numericType, data, {
111 req,
112 res,
113 next,
114 });
115 return { index, extractValue, type: numericType, data, pipes };
116 });
117 }
118 async getParamValue(value, { metatype, type, data, }, pipes) {
119 if (!shared_utils_1.isEmpty(pipes)) {
120 return this.pipesConsumer.apply(value, { metatype, type, data }, pipes);
121 }
122 return value;
123 }
124 isPipeable(type) {
125 return (type === route_paramtypes_enum_1.RouteParamtypes.BODY ||
126 type === route_paramtypes_enum_1.RouteParamtypes.QUERY ||
127 type === route_paramtypes_enum_1.RouteParamtypes.PARAM ||
128 type === route_paramtypes_enum_1.RouteParamtypes.FILE ||
129 type === route_paramtypes_enum_1.RouteParamtypes.FILES ||
130 shared_utils_1.isString(type));
131 }
132 createGuardsFn(guards, instance, callback, contextType) {
133 const canActivateFn = async (args) => {
134 const canActivate = await this.guardsConsumer.tryActivate(guards, args, instance, callback, contextType);
135 if (!canActivate) {
136 throw new common_1.ForbiddenException(constants_2.FORBIDDEN_MESSAGE);
137 }
138 };
139 return guards.length ? canActivateFn : null;
140 }
141 createPipesFn(pipes, paramsOptions) {
142 const pipesFn = async (args, req, res, next) => {
143 const resolveParamValue = async (param) => {
144 const { index, extractValue, type, data, metatype, pipes: paramPipes, } = param;
145 const value = extractValue(req, res, next);
146 args[index] = this.isPipeable(type)
147 ? await this.getParamValue(value, { metatype, type, data }, pipes.concat(paramPipes))
148 : value;
149 };
150 await Promise.all(paramsOptions.map(resolveParamValue));
151 };
152 return paramsOptions.length ? pipesFn : null;
153 }
154 createHandleResponseFn(callback, isResponseHandled, redirectResponse, httpStatusCode) {
155 const renderTemplate = this.reflectRenderTemplate(callback);
156 if (renderTemplate) {
157 return async (result, res) => {
158 return await this.responseController.render(result, res, renderTemplate);
159 };
160 }
161 if (redirectResponse && typeof redirectResponse.url === 'string') {
162 return async (result, res) => {
163 await this.responseController.redirect(result, res, redirectResponse);
164 };
165 }
166 const isSseHandler = !!this.reflectSse(callback);
167 if (isSseHandler) {
168 return async (result, res, req) => {
169 await this.responseController.sse(result, res.raw || res, req.raw || req);
170 };
171 }
172 return async (result, res) => {
173 result = await this.responseController.transformToResult(result);
174 !isResponseHandled &&
175 (await this.responseController.apply(result, res, httpStatusCode));
176 };
177 }
178 isResponseHandled(instance, methodName, paramsMetadata) {
179 const hasResponseOrNextDecorator = paramsMetadata.some(({ type }) => type === route_paramtypes_enum_1.RouteParamtypes.RESPONSE || type === route_paramtypes_enum_1.RouteParamtypes.NEXT);
180 const isPassthroughEnabled = this.contextUtils.reflectPassthrough(instance, methodName);
181 return hasResponseOrNextDecorator && !isPassthroughEnabled;
182 }
183}
184exports.RouterExecutionContext = RouterExecutionContext;