UNPKG

11.5 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.NestApplicationContext = void 0;
4const common_1 = require("@nestjs/common");
5const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
6const iterare_1 = require("iterare");
7const constants_1 = require("./constants");
8const exceptions_1 = require("./errors/exceptions");
9const context_id_factory_1 = require("./helpers/context-id-factory");
10const hooks_1 = require("./hooks");
11const abstract_instance_resolver_1 = require("./injector/abstract-instance-resolver");
12const compiler_1 = require("./injector/compiler");
13const injector_1 = require("./injector/injector");
14const instance_links_host_1 = require("./injector/instance-links-host");
15/**
16 * @publicApi
17 */
18class NestApplicationContext extends abstract_instance_resolver_1.AbstractInstanceResolver {
19 get instanceLinksHost() {
20 if (!this._instanceLinksHost) {
21 this._instanceLinksHost = new instance_links_host_1.InstanceLinksHost(this.container);
22 }
23 return this._instanceLinksHost;
24 }
25 constructor(container, appOptions = {}, contextModule = null, scope = new Array()) {
26 super();
27 this.container = container;
28 this.appOptions = appOptions;
29 this.contextModule = contextModule;
30 this.scope = scope;
31 this.isInitialized = false;
32 this.logger = new common_1.Logger(NestApplicationContext.name, {
33 timestamp: true,
34 });
35 this.shouldFlushLogsOnOverride = false;
36 this.activeShutdownSignals = new Array();
37 this.moduleCompiler = new compiler_1.ModuleCompiler();
38 this.injector = new injector_1.Injector();
39 if (this.appOptions.preview) {
40 this.printInPreviewModeWarning();
41 }
42 }
43 selectContextModule() {
44 const modules = this.container.getModules().values();
45 this.contextModule = modules.next().value;
46 }
47 /**
48 * Allows navigating through the modules tree, for example, to pull out a specific instance from the selected module.
49 * @returns {INestApplicationContext}
50 */
51 select(moduleType) {
52 const modulesContainer = this.container.getModules();
53 const contextModuleCtor = this.contextModule.metatype;
54 const scope = this.scope.concat(contextModuleCtor);
55 const moduleTokenFactory = this.container.getModuleTokenFactory();
56 const { type, dynamicMetadata } = this.moduleCompiler.extractMetadata(moduleType);
57 const token = moduleTokenFactory.create(type, dynamicMetadata);
58 const selectedModule = modulesContainer.get(token);
59 if (!selectedModule) {
60 throw new exceptions_1.UnknownModuleException();
61 }
62 return new NestApplicationContext(this.container, this.appOptions, selectedModule, scope);
63 }
64 /**
65 * Retrieves an instance (or a list of instances) of either injectable or controller, otherwise, throws exception.
66 * @returns {TResult | Array<TResult>}
67 */
68 get(typeOrToken, options = { strict: false }) {
69 var _a;
70 return !(options && options.strict)
71 ? this.find(typeOrToken, options)
72 : this.find(typeOrToken, {
73 moduleId: (_a = this.contextModule) === null || _a === void 0 ? void 0 : _a.id,
74 each: options.each,
75 });
76 }
77 /**
78 * Resolves transient or request-scoped instance (or a list of instances) of either injectable or controller, otherwise, throws exception.
79 * @returns {Promise<TResult | Array<TResult>>}
80 */
81 resolve(typeOrToken, contextId = (0, context_id_factory_1.createContextId)(), options = { strict: false }) {
82 return this.resolvePerContext(typeOrToken, this.contextModule, contextId, options);
83 }
84 /**
85 * Registers the request/context object for a given context ID (DI container sub-tree).
86 * @returns {void}
87 */
88 registerRequestByContextId(request, contextId) {
89 this.container.registerRequestProvider(request, contextId);
90 }
91 /**
92 * Initializes the Nest application.
93 * Calls the Nest lifecycle events.
94 *
95 * @returns {Promise<this>} The NestApplicationContext instance as Promise
96 */
97 async init() {
98 if (this.isInitialized) {
99 return this;
100 }
101 await this.callInitHook();
102 await this.callBootstrapHook();
103 this.isInitialized = true;
104 return this;
105 }
106 /**
107 * Terminates the application
108 * @returns {Promise<void>}
109 */
110 async close(signal) {
111 await this.callDestroyHook();
112 await this.callBeforeShutdownHook(signal);
113 await this.dispose();
114 await this.callShutdownHook(signal);
115 this.unsubscribeFromProcessSignals();
116 }
117 /**
118 * Sets custom logger service.
119 * Flushes buffered logs if auto flush is on.
120 * @returns {void}
121 */
122 useLogger(logger) {
123 common_1.Logger.overrideLogger(logger);
124 if (this.shouldFlushLogsOnOverride) {
125 this.flushLogs();
126 }
127 }
128 /**
129 * Prints buffered logs and detaches buffer.
130 * @returns {void}
131 */
132 flushLogs() {
133 common_1.Logger.flush();
134 }
135 /**
136 * Define that it must flush logs right after defining a custom logger.
137 */
138 flushLogsOnOverride() {
139 this.shouldFlushLogsOnOverride = true;
140 }
141 /**
142 * Enables the usage of shutdown hooks. Will call the
143 * `onApplicationShutdown` function of a provider if the
144 * process receives a shutdown signal.
145 *
146 * @param {ShutdownSignal[]} [signals=[]] The system signals it should listen to
147 *
148 * @returns {this} The Nest application context instance
149 */
150 enableShutdownHooks(signals = []) {
151 if ((0, shared_utils_1.isEmpty)(signals)) {
152 signals = Object.keys(common_1.ShutdownSignal).map((key) => common_1.ShutdownSignal[key]);
153 }
154 else {
155 // given signals array should be unique because
156 // process shouldn't listen to the same signal more than once.
157 signals = Array.from(new Set(signals));
158 }
159 signals = (0, iterare_1.iterate)(signals)
160 .map((signal) => signal.toString().toUpperCase().trim())
161 // filter out the signals which is already listening to
162 .filter(signal => !this.activeShutdownSignals.includes(signal))
163 .toArray();
164 this.listenToShutdownSignals(signals);
165 return this;
166 }
167 async dispose() {
168 // Nest application context has no server
169 // to dispose, therefore just call a noop
170 return Promise.resolve();
171 }
172 /**
173 * Listens to shutdown signals by listening to
174 * process events
175 *
176 * @param {string[]} signals The system signals it should listen to
177 */
178 listenToShutdownSignals(signals) {
179 let receivedSignal = false;
180 const cleanup = async (signal) => {
181 try {
182 if (receivedSignal) {
183 // If we receive another signal while we're waiting
184 // for the server to stop, just ignore it.
185 return;
186 }
187 receivedSignal = true;
188 await this.callDestroyHook();
189 await this.callBeforeShutdownHook(signal);
190 await this.dispose();
191 await this.callShutdownHook(signal);
192 signals.forEach(sig => process.removeListener(sig, cleanup));
193 process.kill(process.pid, signal);
194 }
195 catch (err) {
196 common_1.Logger.error(constants_1.MESSAGES.ERROR_DURING_SHUTDOWN, err === null || err === void 0 ? void 0 : err.stack, NestApplicationContext.name);
197 process.exit(1);
198 }
199 };
200 this.shutdownCleanupRef = cleanup;
201 signals.forEach((signal) => {
202 this.activeShutdownSignals.push(signal);
203 process.on(signal, cleanup);
204 });
205 }
206 /**
207 * Unsubscribes from shutdown signals (process events)
208 */
209 unsubscribeFromProcessSignals() {
210 if (!this.shutdownCleanupRef) {
211 return;
212 }
213 this.activeShutdownSignals.forEach(signal => {
214 process.removeListener(signal, this.shutdownCleanupRef);
215 });
216 }
217 /**
218 * Calls the `onModuleInit` function on the registered
219 * modules and its children.
220 */
221 async callInitHook() {
222 const modulesSortedByDistance = this.getModulesToTriggerHooksOn();
223 for (const module of modulesSortedByDistance) {
224 await (0, hooks_1.callModuleInitHook)(module);
225 }
226 }
227 /**
228 * Calls the `onModuleDestroy` function on the registered
229 * modules and its children.
230 */
231 async callDestroyHook() {
232 const modulesSortedByDistance = this.getModulesToTriggerHooksOn();
233 for (const module of modulesSortedByDistance) {
234 await (0, hooks_1.callModuleDestroyHook)(module);
235 }
236 }
237 /**
238 * Calls the `onApplicationBootstrap` function on the registered
239 * modules and its children.
240 */
241 async callBootstrapHook() {
242 const modulesSortedByDistance = this.getModulesToTriggerHooksOn();
243 for (const module of modulesSortedByDistance) {
244 await (0, hooks_1.callModuleBootstrapHook)(module);
245 }
246 }
247 /**
248 * Calls the `onApplicationShutdown` function on the registered
249 * modules and children.
250 */
251 async callShutdownHook(signal) {
252 const modulesSortedByDistance = this.getModulesToTriggerHooksOn();
253 for (const module of modulesSortedByDistance) {
254 await (0, hooks_1.callAppShutdownHook)(module, signal);
255 }
256 }
257 /**
258 * Calls the `beforeApplicationShutdown` function on the registered
259 * modules and children.
260 */
261 async callBeforeShutdownHook(signal) {
262 const modulesSortedByDistance = this.getModulesToTriggerHooksOn();
263 for (const module of modulesSortedByDistance) {
264 await (0, hooks_1.callBeforeAppShutdownHook)(module, signal);
265 }
266 }
267 assertNotInPreviewMode(methodName) {
268 if (this.appOptions.preview) {
269 const error = `Calling the "${methodName}" in the preview mode is not supported.`;
270 this.logger.error(error);
271 throw new Error(error);
272 }
273 }
274 getModulesToTriggerHooksOn() {
275 var _a;
276 if (this._moduleRefsForHooksByDistance) {
277 return this._moduleRefsForHooksByDistance;
278 }
279 const modulesContainer = this.container.getModules();
280 const compareFn = (a, b) => b.distance - a.distance;
281 const modulesSortedByDistance = Array.from(modulesContainer.values()).sort(compareFn);
282 this._moduleRefsForHooksByDistance = ((_a = this.appOptions) === null || _a === void 0 ? void 0 : _a.preview)
283 ? modulesSortedByDistance.filter(moduleRef => moduleRef.initOnPreview)
284 : modulesSortedByDistance;
285 return this._moduleRefsForHooksByDistance;
286 }
287 printInPreviewModeWarning() {
288 this.logger.warn('------------------------------------------------');
289 this.logger.warn('Application is running in the PREVIEW mode!');
290 this.logger.warn('Providers/controllers will not be instantiated.');
291 this.logger.warn('------------------------------------------------');
292 }
293}
294exports.NestApplicationContext = NestApplicationContext;