1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.RouterExecutionContext = void 0;
|
4 | const common_1 = require("@nestjs/common");
|
5 | const constants_1 = require("@nestjs/common/constants");
|
6 | const route_paramtypes_enum_1 = require("@nestjs/common/enums/route-paramtypes.enum");
|
7 | const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
|
8 | const constants_2 = require("../guards/constants");
|
9 | const context_utils_1 = require("../helpers/context-utils");
|
10 | const handler_metadata_storage_1 = require("../helpers/handler-metadata-storage");
|
11 | const constants_3 = require("../injector/constants");
|
12 | const router_response_controller_1 = require("./router-response-controller");
|
13 | class 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 = !(0, 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 (!(0, 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 | (0, 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 && (0, shared_utils_1.isString)(redirectResponse.url)) {
|
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 (result, res, req) => {
|
169 | var _a;
|
170 | this.responseController.sse(result, res.raw || res, req.raw || req, { additionalHeaders: (_a = res.getHeaders) === null || _a === void 0 ? void 0 : _a.call(res) });
|
171 | };
|
172 | }
|
173 | return async (result, res) => {
|
174 | result = await this.responseController.transformToResult(result);
|
175 | !isResponseHandled &&
|
176 | (await this.responseController.apply(result, res, httpStatusCode));
|
177 | };
|
178 | }
|
179 | isResponseHandled(instance, methodName, paramsMetadata) {
|
180 | const hasResponseOrNextDecorator = paramsMetadata.some(({ type }) => type === route_paramtypes_enum_1.RouteParamtypes.RESPONSE || type === route_paramtypes_enum_1.RouteParamtypes.NEXT);
|
181 | const isPassthroughEnabled = this.contextUtils.reflectPassthrough(instance, methodName);
|
182 | return hasResponseOrNextDecorator && !isPassthroughEnabled;
|
183 | }
|
184 | }
|
185 | exports.RouterExecutionContext = RouterExecutionContext;
|