1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.ExternalContextCreator = void 0;
|
4 | const common_1 = require("@nestjs/common");
|
5 | const constants_1 = require("@nestjs/common/constants");
|
6 | const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
|
7 | const rxjs_1 = require("rxjs");
|
8 | const external_exception_filter_context_1 = require("../exceptions/external-exception-filter-context");
|
9 | const constants_2 = require("../guards/constants");
|
10 | const guards_consumer_1 = require("../guards/guards-consumer");
|
11 | const guards_context_creator_1 = require("../guards/guards-context-creator");
|
12 | const constants_3 = require("../injector/constants");
|
13 | const interceptors_consumer_1 = require("../interceptors/interceptors-consumer");
|
14 | const interceptors_context_creator_1 = require("../interceptors/interceptors-context-creator");
|
15 | const pipes_consumer_1 = require("../pipes/pipes-consumer");
|
16 | const pipes_context_creator_1 = require("../pipes/pipes-context-creator");
|
17 | const context_utils_1 = require("./context-utils");
|
18 | const external_proxy_1 = require("./external-proxy");
|
19 | const handler_metadata_storage_1 = require("./handler-metadata-storage");
|
20 | class ExternalContextCreator {
|
21 | constructor(guardsContextCreator, guardsConsumer, interceptorsContextCreator, interceptorsConsumer, modulesContainer, pipesContextCreator, pipesConsumer, filtersContextCreator) {
|
22 | this.guardsContextCreator = guardsContextCreator;
|
23 | this.guardsConsumer = guardsConsumer;
|
24 | this.interceptorsContextCreator = interceptorsContextCreator;
|
25 | this.interceptorsConsumer = interceptorsConsumer;
|
26 | this.modulesContainer = modulesContainer;
|
27 | this.pipesContextCreator = pipesContextCreator;
|
28 | this.pipesConsumer = pipesConsumer;
|
29 | this.filtersContextCreator = filtersContextCreator;
|
30 | this.contextUtils = new context_utils_1.ContextUtils();
|
31 | this.externalErrorProxy = new external_proxy_1.ExternalErrorProxy();
|
32 | this.handlerMetadataStorage = new handler_metadata_storage_1.HandlerMetadataStorage();
|
33 | }
|
34 | static fromContainer(container) {
|
35 | const guardsContextCreator = new guards_context_creator_1.GuardsContextCreator(container, container.applicationConfig);
|
36 | const guardsConsumer = new guards_consumer_1.GuardsConsumer();
|
37 | const interceptorsContextCreator = new interceptors_context_creator_1.InterceptorsContextCreator(container, container.applicationConfig);
|
38 | const interceptorsConsumer = new interceptors_consumer_1.InterceptorsConsumer();
|
39 | const pipesContextCreator = new pipes_context_creator_1.PipesContextCreator(container, container.applicationConfig);
|
40 | const pipesConsumer = new pipes_consumer_1.PipesConsumer();
|
41 | const filtersContextCreator = new external_exception_filter_context_1.ExternalExceptionFilterContext(container, container.applicationConfig);
|
42 | const externalContextCreator = new ExternalContextCreator(guardsContextCreator, guardsConsumer, interceptorsContextCreator, interceptorsConsumer, container.getModules(), pipesContextCreator, pipesConsumer, filtersContextCreator);
|
43 | externalContextCreator.container = container;
|
44 | return externalContextCreator;
|
45 | }
|
46 | create(instance, callback, methodName, metadataKey, paramsFactory, contextId = constants_3.STATIC_CONTEXT, inquirerId, options = {
|
47 | interceptors: true,
|
48 | guards: true,
|
49 | filters: true,
|
50 | }, contextType = 'http') {
|
51 | const module = this.getContextModuleKey(instance.constructor);
|
52 | const { argsLength, paramtypes, getParamsMetadata } = this.getMetadata(instance, methodName, metadataKey, paramsFactory, contextType);
|
53 | const pipes = this.pipesContextCreator.create(instance, callback, module, contextId, inquirerId);
|
54 | const guards = this.guardsContextCreator.create(instance, callback, module, contextId, inquirerId);
|
55 | const exceptionFilter = this.filtersContextCreator.create(instance, callback, module, contextId, inquirerId);
|
56 | const interceptors = options.interceptors
|
57 | ? this.interceptorsContextCreator.create(instance, callback, module, contextId, inquirerId)
|
58 | : [];
|
59 | const paramsMetadata = getParamsMetadata(module, contextId, inquirerId);
|
60 | const paramsOptions = paramsMetadata
|
61 | ? this.contextUtils.mergeParamsMetatypes(paramsMetadata, paramtypes)
|
62 | : [];
|
63 | const fnCanActivate = options.guards
|
64 | ? this.createGuardsFn(guards, instance, callback, contextType)
|
65 | : null;
|
66 | const fnApplyPipes = this.createPipesFn(pipes, paramsOptions);
|
67 | const handler = (initialArgs, ...args) => async () => {
|
68 | if (fnApplyPipes) {
|
69 | await fnApplyPipes(initialArgs, ...args);
|
70 | return callback.apply(instance, initialArgs);
|
71 | }
|
72 | return callback.apply(instance, args);
|
73 | };
|
74 | const target = async (...args) => {
|
75 | const initialArgs = this.contextUtils.createNullArray(argsLength);
|
76 | fnCanActivate && (await fnCanActivate(args));
|
77 | const result = await this.interceptorsConsumer.intercept(interceptors, args, instance, callback, handler(initialArgs, ...args), contextType);
|
78 | return this.transformToResult(result);
|
79 | };
|
80 | return options.filters
|
81 | ? this.externalErrorProxy.createProxy(target, exceptionFilter, contextType)
|
82 | : target;
|
83 | }
|
84 | getMetadata(instance, methodName, metadataKey, paramsFactory, contextType) {
|
85 | const cacheMetadata = this.handlerMetadataStorage.get(instance, methodName);
|
86 | if (cacheMetadata) {
|
87 | return cacheMetadata;
|
88 | }
|
89 | const metadata = this.contextUtils.reflectCallbackMetadata(instance, methodName, metadataKey || '') || {};
|
90 | const keys = Object.keys(metadata);
|
91 | const argsLength = this.contextUtils.getArgumentsLength(keys, metadata);
|
92 | const paramtypes = this.contextUtils.reflectCallbackParamtypes(instance, methodName);
|
93 | const contextFactory = this.contextUtils.getContextFactory(contextType, instance, instance[methodName]);
|
94 | const getParamsMetadata = (moduleKey, contextId = constants_3.STATIC_CONTEXT, inquirerId) => paramsFactory
|
95 | ? this.exchangeKeysForValues(keys, metadata, moduleKey, paramsFactory, contextId, inquirerId, contextFactory)
|
96 | : null;
|
97 | const handlerMetadata = {
|
98 | argsLength,
|
99 | paramtypes,
|
100 | getParamsMetadata,
|
101 | };
|
102 | this.handlerMetadataStorage.set(instance, methodName, handlerMetadata);
|
103 | return handlerMetadata;
|
104 | }
|
105 | getContextModuleKey(moduleCtor) {
|
106 | const emptyModuleKey = '';
|
107 | if (!moduleCtor) {
|
108 | return emptyModuleKey;
|
109 | }
|
110 | const moduleContainerEntries = this.modulesContainer.entries();
|
111 | for (const [key, moduleRef] of moduleContainerEntries) {
|
112 | if (moduleRef.hasProvider(moduleCtor)) {
|
113 | return key;
|
114 | }
|
115 | }
|
116 | return emptyModuleKey;
|
117 | }
|
118 | exchangeKeysForValues(keys, metadata, moduleContext, paramsFactory, contextId = constants_3.STATIC_CONTEXT, inquirerId, contextFactory = this.contextUtils.getContextFactory('http')) {
|
119 | this.pipesContextCreator.setModuleContext(moduleContext);
|
120 | return keys.map(key => {
|
121 | const { index, data, pipes: pipesCollection } = metadata[key];
|
122 | const pipes = this.pipesContextCreator.createConcreteContext(pipesCollection, contextId, inquirerId);
|
123 | const type = this.contextUtils.mapParamType(key);
|
124 | if (key.includes(constants_1.CUSTOM_ROUTE_ARGS_METADATA)) {
|
125 | const { factory } = metadata[key];
|
126 | const customExtractValue = this.contextUtils.getCustomFactory(factory, data, contextFactory);
|
127 | return { index, extractValue: customExtractValue, type, data, pipes };
|
128 | }
|
129 | const numericType = Number(type);
|
130 | const extractValue = (...args) => paramsFactory.exchangeKeyForValue(numericType, data, args);
|
131 | return { index, extractValue, type: numericType, data, pipes };
|
132 | });
|
133 | }
|
134 | createPipesFn(pipes, paramsOptions) {
|
135 | const pipesFn = async (args, ...params) => {
|
136 | const resolveParamValue = async (param) => {
|
137 | const { index, extractValue, type, data, metatype, pipes: paramPipes, } = param;
|
138 | const value = extractValue(...params);
|
139 | args[index] = await this.getParamValue(value, { metatype, type, data }, pipes.concat(paramPipes));
|
140 | };
|
141 | await Promise.all(paramsOptions.map(resolveParamValue));
|
142 | };
|
143 | return paramsOptions.length ? pipesFn : null;
|
144 | }
|
145 | async getParamValue(value, { metatype, type, data }, pipes) {
|
146 | return (0, shared_utils_1.isEmpty)(pipes)
|
147 | ? value
|
148 | : this.pipesConsumer.apply(value, { metatype, type, data }, pipes);
|
149 | }
|
150 | async transformToResult(resultOrDeferred) {
|
151 | if ((0, rxjs_1.isObservable)(resultOrDeferred)) {
|
152 | return (0, rxjs_1.lastValueFrom)(resultOrDeferred);
|
153 | }
|
154 | return resultOrDeferred;
|
155 | }
|
156 | createGuardsFn(guards, instance, callback, contextType) {
|
157 | const canActivateFn = async (args) => {
|
158 | const canActivate = await this.guardsConsumer.tryActivate(guards, args, instance, callback, contextType);
|
159 | if (!canActivate) {
|
160 | throw new common_1.ForbiddenException(constants_2.FORBIDDEN_MESSAGE);
|
161 | }
|
162 | };
|
163 | return guards.length ? canActivateFn : null;
|
164 | }
|
165 | registerRequestProvider(request, contextId) {
|
166 | this.container.registerRequestProvider(request, contextId);
|
167 | }
|
168 | }
|
169 | exports.ExternalContextCreator = ExternalContextCreator;
|