@nest-yalc-2/app 2.2.1 → 2.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/package.json +10 -2
  2. package/src/__tests__/app-bootstrap-base.helper.spec.ts +86 -38
  3. package/src/__tests__/app-bootstrap-standalone.helper.spec.ts +35 -35
  4. package/src/__tests__/app-bootstrap.helper.spec.ts +162 -98
  5. package/src/__tests__/app-config.service.spec.ts +55 -55
  6. package/src/__tests__/app-context.service.spec.ts +28 -28
  7. package/src/__tests__/app.events.spec.ts +12 -12
  8. package/src/__tests__/app.helper.spec.ts +71 -204
  9. package/src/__tests__/base-app-module.helper.spec.ts +295 -231
  10. package/src/__tests__/base-app.controller.spec.ts +90 -90
  11. package/src/__tests__/base-app.service.spec.ts +39 -39
  12. package/src/__tests__/cls.module.spec.ts +33 -33
  13. package/src/__tests__/life-cycle-handler.service.spec.ts +57 -48
  14. package/src/__tests__/unwrap-result.interceptor.spec.ts +52 -52
  15. package/src/app-bootstrap-base.helper.ts +206 -206
  16. package/src/app-bootstrap-standalone.helper.ts +67 -67
  17. package/src/app-bootstrap.helper.js +9 -9
  18. package/src/app-bootstrap.helper.ts +279 -279
  19. package/src/app-config.service.ts +61 -61
  20. package/src/app-context.module.ts +6 -6
  21. package/src/app-context.service.ts +16 -16
  22. package/src/app-imports.factory.js +2 -2
  23. package/src/app-imports.factory.js.map +1 -1
  24. package/src/app-imports.factory.ts +321 -321
  25. package/src/app.events.ts +8 -8
  26. package/src/app.helper.ts +73 -73
  27. package/src/base-app-module.helper.d.ts +2 -2
  28. package/src/base-app-module.helper.js +8 -5
  29. package/src/base-app-module.helper.js.map +1 -1
  30. package/src/base-app-module.helper.ts +457 -453
  31. package/src/base-app.controller.ts +51 -51
  32. package/src/base-app.interface.ts +55 -55
  33. package/src/base-app.service.ts +33 -33
  34. package/src/cls.module.d.ts +2 -1
  35. package/src/cls.module.js.map +1 -1
  36. package/src/cls.module.ts +76 -75
  37. package/src/conf.type.ts +22 -22
  38. package/src/def.const.ts +33 -33
  39. package/src/global.enum.ts +6 -6
  40. package/src/life-cycle-handler.service.ts +66 -66
  41. package/src/unwrap-result.interceptor.ts +32 -32
  42. package/src/yalc-controller.interface.ts +6 -6
@@ -1,206 +1,206 @@
1
- import {
2
- DynamicModule,
3
- INestApplicationContext,
4
- Logger,
5
- LoggerService,
6
- Type,
7
- } from '@nestjs/common';
8
- import { ConfigService } from '@nestjs/config';
9
- // import { GqlExceptionFilter } from '@nestjs/graphql';
10
- import { NestFastifyApplication } from '@nestjs/platform-fastify';
11
- import type { IServiceConf } from './conf.type.js';
12
- import { SYSTEM_LOGGER_SERVICE } from './def.const.js';
13
- import { YalcDefaultAppModule } from './base-app-module.helper.js';
14
- import { ICreateOptions, INestCreateOptions } from './app-bootstrap.helper.js';
15
- import { EventModule } from '@nest-yalc-2/event-manager/event.module.js';
16
- import { LoggerServiceFactory } from '@nest-yalc-2/logger/logger.service.js';
17
- import { FastifyInstance } from 'fastify';
18
- import { getEnvLoggerLevels } from '@node-yalc/logger/logger.helper.js';
19
- import { globalPromiseTracker } from '@node-yalc/utils/promise.helper.js';
20
-
21
- /**
22
- * Side effect to be executed as soon as the module is imported
23
- */
24
- Logger.overrideLogger(getEnvLoggerLevels());
25
-
26
- export interface IGlobalOptions {
27
- extraImports?: NonNullable<DynamicModule['imports']>;
28
- eventModuleClass?: typeof EventModule;
29
- logger?: typeof LoggerServiceFactory;
30
-
31
- /**
32
- * This is used to avoid bootstrapping a multi-server app
33
- */
34
- skipMultiServerCheck?: boolean;
35
- }
36
-
37
- const bootstrappedApps: Set<any> = new Set();
38
-
39
- export const getBootstrappedApps = () => {
40
- return bootstrappedApps;
41
- };
42
-
43
- export const getMainBootstrappedApp = <
44
- TApp extends BaseAppBootstrap<
45
- NestFastifyApplication | INestApplicationContext
46
- >,
47
- >(): TApp | null => {
48
- if (getBootstrappedApps().size === 0) {
49
- return null;
50
- }
51
-
52
- return getBootstrappedApps().values().next().value;
53
- };
54
-
55
- export abstract class BaseAppBootstrap<
56
- TAppType extends NestFastifyApplication | INestApplicationContext,
57
- > {
58
- protected app?: TAppType;
59
- protected loggerService!: LoggerService;
60
- protected module: Type<any> | DynamicModule;
61
- protected isClosed = false;
62
-
63
- constructor(
64
- protected appAlias: string,
65
- protected readonly appModule: Type<any>,
66
- options?: { globalsOptions?: IGlobalOptions },
67
- ) {
68
- this.module = YalcDefaultAppModule.forRoot(
69
- this.appAlias,
70
- [appModule, ...(options?.globalsOptions?.extraImports ?? [])],
71
- options?.globalsOptions,
72
- );
73
-
74
- const bootstrappedApp = getMainBootstrappedApp();
75
-
76
- if (
77
- bootstrappedApp &&
78
- !options?.globalsOptions?.skipMultiServerCheck &&
79
- process.env.APP_SKIP_MULTISERVER_CHECK !== 'true'
80
- ) {
81
- throw new Error(
82
- `You are trying to bootstrap multiple servers (${bootstrappedApp.appAlias}) in the same process. This is not allowed. Use a different process for each server`,
83
- );
84
- }
85
-
86
- getBootstrappedApps().add(this);
87
- }
88
-
89
- /* istanbul ignore next */
90
- async initApp(options?: {
91
- createOptions?: INestCreateOptions;
92
- fastifyInstance?: FastifyInstance;
93
- }): Promise<this> {
94
- options; // extend this method in the child class
95
- return this;
96
- }
97
-
98
- setApp(app: TAppType) {
99
- this.app = app;
100
-
101
- /**
102
- * Monkey patch the close method to set the isClosed flag
103
- */
104
- const originalCloseFn = this.app.close.bind(this.app);
105
- this.app.close = async () => {
106
- const closeRes = await originalCloseFn();
107
- this.closeCleanup();
108
- return closeRes;
109
- };
110
-
111
- /**
112
- * Monkey patch the init method to set the isClosed flag
113
- */
114
- const originalInitFn = this.app.init.bind(this.app);
115
- this.app.init = async () => {
116
- this.isClosed = false;
117
- getBootstrappedApps().add(this);
118
- let initRes;
119
- try {
120
- initRes = await originalInitFn();
121
- } catch (error) {
122
- /* istanbul ignore next */
123
- this.closeCleanup();
124
- /* istanbul ignore next */
125
- throw error;
126
- }
127
- return initRes;
128
- };
129
-
130
- return this;
131
- }
132
-
133
- /**
134
- * This method is used to cleanup the app and remove it from the global set of bootstrapped apps
135
- */
136
- closeCleanup() {
137
- this.isClosed = true;
138
- getBootstrappedApps().delete(this);
139
- }
140
-
141
- isAppClosed() {
142
- return this.isClosed;
143
- }
144
-
145
- /* istanbul ignore next */
146
- getAppAlias() {
147
- return this.appAlias;
148
- }
149
-
150
- getConf() {
151
- const configService = this.getApp().get<ConfigService>(ConfigService);
152
- return configService.get<IServiceConf>(this.appAlias);
153
- }
154
-
155
- getApp() {
156
- /* istanbul ignore next */
157
- if (!this.app) {
158
- /* istanbul ignore next */
159
- throw new Error('This app is not initialized yet');
160
- }
161
-
162
- return this.app;
163
- }
164
-
165
- async closeApp() {
166
- await this.cleanup();
167
-
168
- await this.app?.close();
169
-
170
- this.closeCleanup();
171
- }
172
-
173
- async cleanup() {
174
- /**
175
- * When running behind a lambda, we have to await for all the promises that have been added to the global promise tracker
176
- * to avoid them being killed by the lambda
177
- * @see - https://stackoverflow.com/questions/64688812/running-tasks-in-aws-lambda-background
178
- */
179
- await globalPromiseTracker.waitForAll();
180
- }
181
-
182
- /**
183
- *
184
- * @returns The main module of the business logic (the one that is passed in the constructor)
185
- */
186
- /* istanbul ignore next */
187
- getAppModule() {
188
- return this.appModule;
189
- }
190
-
191
- /**
192
- *
193
- * @returns The global module that is used to bootstrap the app (YalcDefaultAppModule)
194
- */
195
- getModule() {
196
- return this.module;
197
- }
198
-
199
- async applyBootstrapGlobals(_options?: ICreateOptions) {
200
- this.loggerService = this.getApp().get(SYSTEM_LOGGER_SERVICE);
201
- this.loggerService.debug?.('Setting logger service...');
202
- this.getApp().useLogger(this.loggerService);
203
- Logger.overrideLogger(this.loggerService);
204
- return this;
205
- }
206
- }
1
+ import {
2
+ DynamicModule,
3
+ INestApplicationContext,
4
+ Logger,
5
+ LoggerService,
6
+ Type,
7
+ } from '@nestjs/common';
8
+ import { ConfigService } from '@nestjs/config';
9
+ // import { GqlExceptionFilter } from '@nestjs/graphql';
10
+ import { NestFastifyApplication } from '@nestjs/platform-fastify';
11
+ import type { IServiceConf } from './conf.type.js';
12
+ import { SYSTEM_LOGGER_SERVICE } from './def.const.js';
13
+ import { YalcDefaultAppModule } from './base-app-module.helper.js';
14
+ import { ICreateOptions, INestCreateOptions } from './app-bootstrap.helper.js';
15
+ import { EventModule } from '@nest-yalc-2/event-manager/event.module.js';
16
+ import { LoggerServiceFactory } from '@nest-yalc-2/logger/logger.service.js';
17
+ import { FastifyInstance } from 'fastify';
18
+ import { getEnvLoggerLevels } from '@node-yalc/logger/logger.helper.js';
19
+ import { globalPromiseTracker } from '@node-yalc/utils/promise.helper.js';
20
+
21
+ /**
22
+ * Side effect to be executed as soon as the module is imported
23
+ */
24
+ Logger.overrideLogger(getEnvLoggerLevels());
25
+
26
+ export interface IGlobalOptions {
27
+ extraImports?: NonNullable<DynamicModule['imports']>;
28
+ eventModuleClass?: typeof EventModule;
29
+ logger?: typeof LoggerServiceFactory;
30
+
31
+ /**
32
+ * This is used to avoid bootstrapping a multi-server app
33
+ */
34
+ skipMultiServerCheck?: boolean;
35
+ }
36
+
37
+ const bootstrappedApps: Set<any> = new Set();
38
+
39
+ export const getBootstrappedApps = () => {
40
+ return bootstrappedApps;
41
+ };
42
+
43
+ export const getMainBootstrappedApp = <
44
+ TApp extends BaseAppBootstrap<
45
+ NestFastifyApplication | INestApplicationContext
46
+ >,
47
+ >(): TApp | null => {
48
+ if (getBootstrappedApps().size === 0) {
49
+ return null;
50
+ }
51
+
52
+ return getBootstrappedApps().values().next().value;
53
+ };
54
+
55
+ export abstract class BaseAppBootstrap<
56
+ TAppType extends NestFastifyApplication | INestApplicationContext,
57
+ > {
58
+ protected app?: TAppType;
59
+ protected loggerService!: LoggerService;
60
+ protected module: Type<any> | DynamicModule;
61
+ protected isClosed = false;
62
+
63
+ constructor(
64
+ protected appAlias: string,
65
+ protected readonly appModule: Type<any>,
66
+ options?: { globalsOptions?: IGlobalOptions },
67
+ ) {
68
+ this.module = YalcDefaultAppModule.forRoot(
69
+ this.appAlias,
70
+ [appModule, ...(options?.globalsOptions?.extraImports ?? [])],
71
+ options?.globalsOptions,
72
+ );
73
+
74
+ const bootstrappedApp = getMainBootstrappedApp();
75
+
76
+ if (
77
+ bootstrappedApp &&
78
+ !options?.globalsOptions?.skipMultiServerCheck &&
79
+ process.env.APP_SKIP_MULTISERVER_CHECK !== 'true'
80
+ ) {
81
+ throw new Error(
82
+ `You are trying to bootstrap multiple servers (${bootstrappedApp.appAlias}) in the same process. This is not allowed. Use a different process for each server`,
83
+ );
84
+ }
85
+
86
+ getBootstrappedApps().add(this);
87
+ }
88
+
89
+ /* istanbul ignore next */
90
+ async initApp(options?: {
91
+ createOptions?: INestCreateOptions;
92
+ fastifyInstance?: FastifyInstance;
93
+ }): Promise<this> {
94
+ options; // extend this method in the child class
95
+ return this;
96
+ }
97
+
98
+ setApp(app: TAppType) {
99
+ this.app = app;
100
+
101
+ /**
102
+ * Monkey patch the close method to set the isClosed flag
103
+ */
104
+ const originalCloseFn = this.app.close.bind(this.app);
105
+ this.app.close = async () => {
106
+ const closeRes = await originalCloseFn();
107
+ this.closeCleanup();
108
+ return closeRes;
109
+ };
110
+
111
+ /**
112
+ * Monkey patch the init method to set the isClosed flag
113
+ */
114
+ const originalInitFn = this.app.init.bind(this.app);
115
+ this.app.init = async () => {
116
+ this.isClosed = false;
117
+ getBootstrappedApps().add(this);
118
+ let initRes;
119
+ try {
120
+ initRes = await originalInitFn();
121
+ } catch (error) {
122
+ /* istanbul ignore next */
123
+ this.closeCleanup();
124
+ /* istanbul ignore next */
125
+ throw error;
126
+ }
127
+ return initRes;
128
+ };
129
+
130
+ return this;
131
+ }
132
+
133
+ /**
134
+ * This method is used to cleanup the app and remove it from the global set of bootstrapped apps
135
+ */
136
+ closeCleanup() {
137
+ this.isClosed = true;
138
+ getBootstrappedApps().delete(this);
139
+ }
140
+
141
+ isAppClosed() {
142
+ return this.isClosed;
143
+ }
144
+
145
+ /* istanbul ignore next */
146
+ getAppAlias() {
147
+ return this.appAlias;
148
+ }
149
+
150
+ getConf() {
151
+ const configService = this.getApp().get<ConfigService>(ConfigService);
152
+ return configService.get<IServiceConf>(this.appAlias);
153
+ }
154
+
155
+ getApp() {
156
+ /* istanbul ignore next */
157
+ if (!this.app) {
158
+ /* istanbul ignore next */
159
+ throw new Error('This app is not initialized yet');
160
+ }
161
+
162
+ return this.app;
163
+ }
164
+
165
+ async closeApp() {
166
+ await this.cleanup();
167
+
168
+ await this.app?.close();
169
+
170
+ this.closeCleanup();
171
+ }
172
+
173
+ async cleanup() {
174
+ /**
175
+ * When running behind a lambda, we have to await for all the promises that have been added to the global promise tracker
176
+ * to avoid them being killed by the lambda
177
+ * @see - https://stackoverflow.com/questions/64688812/running-tasks-in-aws-lambda-background
178
+ */
179
+ await globalPromiseTracker.waitForAll();
180
+ }
181
+
182
+ /**
183
+ *
184
+ * @returns The main module of the business logic (the one that is passed in the constructor)
185
+ */
186
+ /* istanbul ignore next */
187
+ getAppModule() {
188
+ return this.appModule;
189
+ }
190
+
191
+ /**
192
+ *
193
+ * @returns The global module that is used to bootstrap the app (YalcDefaultAppModule)
194
+ */
195
+ getModule() {
196
+ return this.module;
197
+ }
198
+
199
+ async applyBootstrapGlobals(_options?: ICreateOptions) {
200
+ this.loggerService = this.getApp().get(SYSTEM_LOGGER_SERVICE);
201
+ this.loggerService.debug?.('Setting logger service...');
202
+ this.getApp().useLogger(this.loggerService);
203
+ Logger.overrideLogger(this.loggerService);
204
+ return this;
205
+ }
206
+ }
@@ -1,67 +1,67 @@
1
- import { INestApplicationContext } from '@nestjs/common';
2
- import { NestFactory } from '@nestjs/core';
3
- // import { GqlExceptionFilter } from '@nestjs/graphql';
4
- import { FastifyInstance } from 'fastify';
5
- import { envIsTrue } from '@node-yalc/utils/env.helper.js';
6
- import clc from 'cli-color';
7
- import {
8
- BaseAppBootstrap,
9
- IGlobalOptions,
10
- } from './app-bootstrap-base.helper.js';
11
- import { INestCreateOptions } from './app-bootstrap.helper.js';
12
- import { getEnvLoggerLevels } from '@node-yalc/logger/logger.helper.js';
13
-
14
- export class StandaloneAppBootstrap<
15
- TGlobalOptions extends IGlobalOptions = IGlobalOptions,
16
- > extends BaseAppBootstrap<INestApplicationContext> {
17
- constructor(appAlias: string, module: any, options?: TGlobalOptions) {
18
- super(appAlias, module, { globalsOptions: options });
19
- }
20
-
21
- async initApp(options?: {
22
- createOptions?: INestCreateOptions;
23
- fastifyInstance?: FastifyInstance;
24
- }) {
25
- await this.createApp({
26
- createOptions: options?.createOptions,
27
- });
28
-
29
- await this.applyBootstrapGlobals(options?.createOptions);
30
-
31
- await this.getApp().init();
32
-
33
- /* istanbul ignore next */
34
- if (envIsTrue(process.env.APP_DRY_RUN) === true) {
35
- /* istanbul ignore next */
36
- this.loggerService?.log('Dry run, exiting...');
37
- /* istanbul ignore next */
38
- await this.getApp().close();
39
- /* istanbul ignore next */
40
- process.exit(0);
41
- }
42
-
43
- return this;
44
- }
45
-
46
- async createApp(_options?: {
47
- createOptions?: INestCreateOptions;
48
- fastifyInstance?: FastifyInstance;
49
- }) {
50
- let app: INestApplicationContext;
51
- try {
52
- app = await NestFactory.createApplicationContext(this.module, {
53
- logger: getEnvLoggerLevels(),
54
- });
55
- } catch (err) {
56
- /* istanbul ignore next */
57
- this.closeCleanup();
58
- // eslint-disable-next-line no-console
59
- /* istanbul ignore next */
60
- console.error(clc.red('Failed to create app'), clc.red(err));
61
- /* istanbul ignore next */
62
- throw new Error('Process aborted');
63
- }
64
-
65
- return this.setApp(app);
66
- }
67
- }
1
+ import { INestApplicationContext } from '@nestjs/common';
2
+ import { NestFactory } from '@nestjs/core';
3
+ // import { GqlExceptionFilter } from '@nestjs/graphql';
4
+ import { FastifyInstance } from 'fastify';
5
+ import { envIsTrue } from '@node-yalc/utils/env.helper.js';
6
+ import clc from 'cli-color';
7
+ import {
8
+ BaseAppBootstrap,
9
+ IGlobalOptions,
10
+ } from './app-bootstrap-base.helper.js';
11
+ import { INestCreateOptions } from './app-bootstrap.helper.js';
12
+ import { getEnvLoggerLevels } from '@node-yalc/logger/logger.helper.js';
13
+
14
+ export class StandaloneAppBootstrap<
15
+ TGlobalOptions extends IGlobalOptions = IGlobalOptions,
16
+ > extends BaseAppBootstrap<INestApplicationContext> {
17
+ constructor(appAlias: string, module: any, options?: TGlobalOptions) {
18
+ super(appAlias, module, { globalsOptions: options });
19
+ }
20
+
21
+ async initApp(options?: {
22
+ createOptions?: INestCreateOptions;
23
+ fastifyInstance?: FastifyInstance;
24
+ }) {
25
+ await this.createApp({
26
+ createOptions: options?.createOptions,
27
+ });
28
+
29
+ await this.applyBootstrapGlobals(options?.createOptions);
30
+
31
+ await this.getApp().init();
32
+
33
+ /* istanbul ignore next */
34
+ if (envIsTrue(process.env.APP_DRY_RUN) === true) {
35
+ /* istanbul ignore next */
36
+ this.loggerService?.log('Dry run, exiting...');
37
+ /* istanbul ignore next */
38
+ await this.getApp().close();
39
+ /* istanbul ignore next */
40
+ process.exit(0);
41
+ }
42
+
43
+ return this;
44
+ }
45
+
46
+ async createApp(_options?: {
47
+ createOptions?: INestCreateOptions;
48
+ fastifyInstance?: FastifyInstance;
49
+ }) {
50
+ let app: INestApplicationContext;
51
+ try {
52
+ app = await NestFactory.createApplicationContext(this.module, {
53
+ logger: getEnvLoggerLevels(),
54
+ });
55
+ } catch (err) {
56
+ /* istanbul ignore next */
57
+ this.closeCleanup();
58
+ // eslint-disable-next-line no-console
59
+ /* istanbul ignore next */
60
+ console.error(clc.red('Failed to create app'), clc.red(err));
61
+ /* istanbul ignore next */
62
+ throw new Error('Process aborted');
63
+ }
64
+
65
+ return this.setApp(app);
66
+ }
67
+ }
@@ -127,17 +127,17 @@ export class AppBootstrap extends BaseAppBootstrap {
127
127
  apiPrefix = apiPrefix ? `/${apiPrefix}` : '';
128
128
  const domain = this.getConf()?.domain || 'localhost';
129
129
  await this.getApp().listen(port, host, async (_err, address) => {
130
- console.debug(`Server ${this.appAlias} listening on
131
- http://localhost:${port}${apiPrefix}/
132
- http://127.0.0.1:${port}${apiPrefix}/
133
- http://${domain}:${port}${apiPrefix}/
130
+ console.debug(`Server ${this.appAlias} listening on
131
+ http://localhost:${port}${apiPrefix}/
132
+ http://127.0.0.1:${port}${apiPrefix}/
133
+ http://${domain}:${port}${apiPrefix}/
134
134
  ${address}`);
135
135
  if (this.isSwaggerEnabled) {
136
- console.debug(`Swagger ${this.appAlias} listening on
137
- http://localhost:${port}${apiPrefix}/${this.swaggerPath}
138
- http://127.0.0.1:${port}${apiPrefix}/${this.swaggerPath}
139
- http://${domain}:${port}${apiPrefix}/${this.swaggerPath}
140
- ${address}/${this.swaggerPath}
136
+ console.debug(`Swagger ${this.appAlias} listening on
137
+ http://localhost:${port}${apiPrefix}/${this.swaggerPath}
138
+ http://127.0.0.1:${port}${apiPrefix}/${this.swaggerPath}
139
+ http://${domain}:${port}${apiPrefix}/${this.swaggerPath}
140
+ ${address}/${this.swaggerPath}
141
141
  JSON: http://localhost:${port}${apiPrefix}/${this.swaggerPath}/json`);
142
142
  }
143
143
  callback?.(port, host, domain);