@lenne.tech/nest-server 8.6.15 → 8.6.16

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 (34) hide show
  1. package/dist/config.env.js +54 -0
  2. package/dist/config.env.js.map +1 -1
  3. package/dist/core/common/interfaces/cron-job-config.interface.d.ts +12 -0
  4. package/dist/core/common/interfaces/cron-job-config.interface.js +3 -0
  5. package/dist/core/common/interfaces/cron-job-config.interface.js.map +1 -0
  6. package/dist/core/common/interfaces/server-options.interface.d.ts +4 -0
  7. package/dist/core/common/services/core-cron-jobs.service.d.ts +15 -0
  8. package/dist/core/common/services/core-cron-jobs.service.js +54 -0
  9. package/dist/core/common/services/core-cron-jobs.service.js.map +1 -0
  10. package/dist/core/common/services/crud.service.d.ts +5 -1
  11. package/dist/core/common/services/crud.service.js +11 -5
  12. package/dist/core/common/services/crud.service.js.map +1 -1
  13. package/dist/core/common/types/falsy.type.d.ts +1 -0
  14. package/dist/core/common/types/falsy.type.js +3 -0
  15. package/dist/core/common/types/falsy.type.js.map +1 -0
  16. package/dist/index.d.ts +3 -0
  17. package/dist/index.js +3 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/server/common/services/cron-jobs.service.d.ts +7 -0
  20. package/dist/server/common/services/cron-jobs.service.js +31 -0
  21. package/dist/server/common/services/cron-jobs.service.js.map +1 -0
  22. package/dist/server/server.module.js +4 -0
  23. package/dist/server/server.module.js.map +1 -1
  24. package/dist/tsconfig.build.tsbuildinfo +1 -1
  25. package/package.json +5 -2
  26. package/src/config.env.ts +58 -0
  27. package/src/core/common/interfaces/cron-job-config.interface.ts +52 -0
  28. package/src/core/common/interfaces/server-options.interface.ts +9 -0
  29. package/src/core/common/services/core-cron-jobs.service.ts +101 -0
  30. package/src/core/common/services/crud.service.ts +17 -5
  31. package/src/core/common/types/falsy.type.ts +4 -0
  32. package/src/index.ts +3 -0
  33. package/src/server/common/services/cron-jobs.service.ts +26 -0
  34. package/src/server/server.module.ts +7 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nest-server",
3
- "version": "8.6.15",
3
+ "version": "8.6.16",
4
4
  "description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
5
5
  "keywords": [
6
6
  "node",
@@ -26,13 +26,14 @@
26
26
  "reinit": "rimraf package-lock.json && rimraf node_modules && npm cache clean --force && npm i && npm run test:e2e && npm run build",
27
27
  "reinit:force": "rimraf package-lock.json && rimraf node_modules && npm cache clean --force && npm i --force && npm run test:e2e",
28
28
  "reinit:legacy": "rimraf package-lock.json && rimraf node_modules && npm cache clean --force && npm i --legacy-peer-deps && npm run test:e2e",
29
- "start": "npm run start:dev",
29
+ "start": "npm run start:local",
30
30
  "stop": "./node_modules/.bin/pm2 delete nest",
31
31
  "start:pm2": "./node_modules/.bin/grunt",
32
32
  "start:prod": "./node_modules/.bin/grunt productive",
33
33
  "start:nodemon": "ts-node -r tsconfig-paths/register src/main.ts",
34
34
  "start:debug": "nodemon --config nodemon-debug.json",
35
35
  "start:dev": "nodemon",
36
+ "start:local": "NODE_ENV=local nodemon",
36
37
  "test": "NODE_ENV=local jest",
37
38
  "test:cov": "NODE_ENV=local jest --coverage",
38
39
  "test:debug": "NODE_ENV=local node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
@@ -66,6 +67,7 @@
66
67
  "@nestjs/mongoose": "9.1.1",
67
68
  "@nestjs/passport": "8.2.2",
68
69
  "@nestjs/platform-express": "8.4.7",
70
+ "@nestjs/schedule": "^2.0.1",
69
71
  "apollo-server-core": "3.9.0",
70
72
  "apollo-server-express": "3.9.0",
71
73
  "bcrypt": "5.0.1",
@@ -93,6 +95,7 @@
93
95
  },
94
96
  "devDependencies": {
95
97
  "@nestjs/testing": "8.4.7",
98
+ "@types/cron": "^2.0.0",
96
99
  "@types/ejs": "3.1.1",
97
100
  "@types/jest": "28.1.3",
98
101
  "@types/lodash": "4.14.182",
package/src/config.env.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { CronExpression } from '@nestjs/schedule';
1
2
  import { join } from 'path';
2
3
  import { IServerOptions } from './core/common/interfaces/server-options.interface';
3
4
 
@@ -5,6 +6,63 @@ import { IServerOptions } from './core/common/interfaces/server-options.interfac
5
6
  * Configuration for the different environments
6
7
  */
7
8
  const config: { [env: string]: IServerOptions } = {
9
+ // ===========================================================================
10
+ // Local environment
11
+ // ===========================================================================
12
+ local: {
13
+ cronJobs: {
14
+ sayHello: {
15
+ cronTime: CronExpression.EVERY_5_MINUTES,
16
+ timeZone: 'Europe/Berlin',
17
+ runOnInit: false,
18
+ },
19
+ },
20
+ email: {
21
+ smtp: {
22
+ auth: {
23
+ user: 'rebeca68@ethereal.email',
24
+ pass: 'v5WUScAN98AzGbRjpc',
25
+ },
26
+ host: 'smtp.ethereal.email',
27
+ port: 587,
28
+ secure: false,
29
+ },
30
+ mailjet: {
31
+ api_key_public: 'MAILJET_API_KEY_PUBLIC',
32
+ api_key_private: 'MAILJET_API_KEY_PRIVATE',
33
+ },
34
+ defaultSender: {
35
+ email: 'rebeca68@ethereal.email',
36
+ name: 'Rebeca Sixtyeight',
37
+ },
38
+ verificationLink: 'http://localhost:4200/user/verification',
39
+ passwordResetLink: 'http://localhost:4200/user/password-reset',
40
+ },
41
+ env: 'local',
42
+ execAfterInit: 'npm run docs:bootstrap',
43
+ graphQl: {
44
+ driver: {
45
+ debug: true,
46
+ introspection: true,
47
+ },
48
+ },
49
+ jwt: {
50
+ secret: 'SECRET_OR_PRIVATE_KEY_DEV',
51
+ },
52
+ mongoose: {
53
+ uri: 'mongodb://localhost/nest-server-dev',
54
+ },
55
+ port: 3000,
56
+ staticAssets: {
57
+ path: join(__dirname, '..', 'public'),
58
+ options: { prefix: '' },
59
+ },
60
+ templates: {
61
+ path: join(__dirname, 'templates'),
62
+ engine: 'ejs',
63
+ },
64
+ },
65
+
8
66
  // ===========================================================================
9
67
  // Development environment
10
68
  // ===========================================================================
@@ -0,0 +1,52 @@
1
+ import { CronExpression } from '@nestjs/schedule';
2
+ import { CronCommand } from 'cron';
3
+ import { Falsy } from '../types/falsy.type';
4
+
5
+ /**
6
+ * Interface for cron job configuration
7
+ */
8
+ export interface CronJobConfig {
9
+ /**
10
+ * The context within which to execute the onTick method. This defaults to the cronjob itself allowing you to call
11
+ * `this.stop()`. However, if you change this you'll have access to the functions and values within your context
12
+ * object.
13
+ */
14
+ context?: any;
15
+
16
+ /**
17
+ * The time to fire off your job. This can be in the form of cron syntax or a JS `Date` object.
18
+ */
19
+ cronTime: CronExpression | string | Date | Falsy;
20
+
21
+ /**
22
+ * A function that will fire when the job is complete, when it is stopped.
23
+ */
24
+ onComplete?: CronCommand | null;
25
+
26
+ /**
27
+ * This will immediately fire your `onTickfunction as soon as the requisit initialization has happened.
28
+ * This option is set to ``true``` by default.
29
+ */
30
+ runOnInit?: boolean;
31
+
32
+ /**
33
+ * Specify the timezone for the execution. This will modify the actual time relative to your timezone.
34
+ * If the timezone is invalid, an error is thrown. Can be any string accepted by luxon's `DateTime.setZone()`
35
+ * (https://moment.github.io/luxon/api-docs/index.html#datetimesetzone).
36
+ */
37
+ timeZone?: string;
38
+
39
+ /**
40
+ * If you have code that keeps the event loop running and want to stop the node process when that finishes
41
+ * regardless of the state of your cronjob, you can do so making use of this parameter. This is off by default and
42
+ * cron will run as if it needs to control the event loop. For more information take a look at
43
+ * timers#timers_timeout_unref from the NodeJS docs.
44
+ */
45
+ unrefTimeout?: boolean;
46
+
47
+ /**
48
+ * This allows you to specify the offset of your timezone rather than using the `timeZoneparam.
49
+ * Probably don't use both ``timeZone` andutcOffset`` together or weird things may happen.
50
+ */
51
+ utcOffset?: string | number;
52
+ }
@@ -3,13 +3,22 @@ import { GqlModuleAsyncOptions } from '@nestjs/graphql';
3
3
  import { JwtModuleOptions } from '@nestjs/jwt';
4
4
  import { MongooseModuleOptions } from '@nestjs/mongoose';
5
5
  import { ServeStaticOptions } from '@nestjs/platform-express/interfaces/serve-static-options.interface';
6
+ import { CronExpression } from '@nestjs/schedule';
6
7
  import * as SMTPTransport from 'nodemailer/lib/smtp-transport';
8
+ import { Falsy } from '../types/falsy.type';
9
+ import { CronJobConfig } from './cron-job-config.interface';
7
10
  import { MailjetOptions } from './mailjet-options.interface';
8
11
 
9
12
  /**
10
13
  * Options for the server
11
14
  */
12
15
  export interface IServerOptions {
16
+ /**
17
+ * Cron jobs configuration object with the name of the cron job function as key
18
+ * and the cron expression or config as value
19
+ */
20
+ cronJobs?: Record<string, CronExpression | string | Date | Falsy | CronJobConfig>;
21
+
13
22
  /**
14
23
  * SMTP and template configuration for sending emails
15
24
  */
@@ -0,0 +1,101 @@
1
+ import { CronExpression, SchedulerRegistry } from '@nestjs/schedule';
2
+ import { CronJob } from 'cron';
3
+ import { CronJobConfig } from '../interfaces/cron-job-config.interface';
4
+ import { Falsy } from '../types/falsy.type';
5
+
6
+ /**
7
+ * Cron jobs service to extend
8
+ */
9
+ export abstract class CoreCronJobs {
10
+ /**
11
+ * Config for cron jobs
12
+ */
13
+ config: {
14
+ [key: string]: any;
15
+ log: boolean;
16
+ };
17
+
18
+ // ===================================================================================================================
19
+ // Initializations
20
+ // ===================================================================================================================
21
+
22
+ /**
23
+ * Integrate services and init chron jobs
24
+ */
25
+ protected constructor(
26
+ protected schedulerRegistry: SchedulerRegistry,
27
+ protected cronJobs: Record<string, CronExpression | string | Date | Falsy | CronJobConfig>,
28
+ options?: { log?: boolean }
29
+ ) {
30
+ this.config = {
31
+ log: true,
32
+ ...options,
33
+ };
34
+ this.initCronJobs();
35
+ }
36
+
37
+ /**
38
+ * Init cron jobs
39
+ */
40
+ protected initCronJobs() {
41
+ // Get cron jobs
42
+ if (!this.cronJobs) {
43
+ return;
44
+ }
45
+
46
+ // Init cron jobs
47
+ for (const [name, CronExpressionOrConfig] of Object.entries(this.cronJobs)) {
48
+ // Check config
49
+ if (!CronExpressionOrConfig) {
50
+ continue;
51
+ }
52
+
53
+ // Prepare config
54
+ let config: CronExpression | string | Date | Falsy | CronJobConfig = CronExpressionOrConfig;
55
+ if (typeof config === 'string' || config instanceof Date) {
56
+ config = {
57
+ cronTime: config,
58
+ };
59
+ }
60
+
61
+ // Set defaults
62
+ config = {
63
+ timeZone: 'Europe/Berlin',
64
+ runOnInit: true,
65
+ ...config,
66
+ };
67
+
68
+ // Check if cron job should be activated
69
+ if (!config?.cronTime) {
70
+ continue;
71
+ }
72
+
73
+ // check if cron job exists
74
+ if (!this[name]) {
75
+ if (this.config.log) {
76
+ console.log('Missing cron job function ' + name);
77
+ }
78
+ continue;
79
+ }
80
+
81
+ // Init cron job
82
+ const job = new CronJob(
83
+ config.cronTime,
84
+ () => {
85
+ this[name]();
86
+ },
87
+ null,
88
+ true,
89
+ config.timeZone,
90
+ config.context,
91
+ config.runOnInit,
92
+ config.utcOffset,
93
+ config.unrefTimeout
94
+ );
95
+ this.schedulerRegistry.addCronJob(name, job);
96
+ if (this.config.log && this.schedulerRegistry.getCronJob(name)) {
97
+ console.log(`CronJob ${name} initialized with "${config.cronTime}"`);
98
+ }
99
+ }
100
+ }
101
+ }
@@ -1,4 +1,5 @@
1
1
  import { NotFoundException } from '@nestjs/common';
2
+ import { FilterQuery, QueryOptions } from 'mongoose';
2
3
  import { FilterArgs } from '../args/filter.args';
3
4
  import { merge } from '../helpers/config.helper';
4
5
  import { convertFilterArgsToQuery } from '../helpers/filter.helper';
@@ -12,7 +13,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
12
13
  * Create item
13
14
  */
14
15
  async create(input: any, serviceOptions?: ServiceOptions): Promise<T> {
15
- merge({ prepareInput: { create: true } }, serviceOptions);
16
+ serviceOptions = merge({ prepareInput: { create: true } }, serviceOptions);
16
17
  return this.process(
17
18
  async (data) => {
18
19
  const currentUserId = serviceOptions?.currentUser?.id;
@@ -36,13 +37,24 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
36
37
  /**
37
38
  * Get items via filter
38
39
  */
39
- async find(filterArgs?: FilterArgs, serviceOptions?: ServiceOptions): Promise<T[]> {
40
+ async find(
41
+ filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
42
+ serviceOptions?: ServiceOptions
43
+ ): Promise<T[]> {
40
44
  return this.process(
41
45
  async (data) => {
42
- const filterQuery = convertFilterArgsToQuery(data.input);
43
- return this.mainDbModel.find(filterQuery[0], null, filterQuery[1]).exec();
46
+ // Prepare filter query
47
+ const filterQuery = { filterQuery: data?.input?.filterQuery, queryOptions: data?.input?.queryOptions };
48
+ if (data?.input instanceof FilterArgs) {
49
+ const converted = convertFilterArgsToQuery(data.input);
50
+ filterQuery.filterQuery = converted[0];
51
+ filterQuery.queryOptions = converted[1];
52
+ }
53
+
54
+ // Find in DB
55
+ return this.mainDbModel.find(filterQuery.filterQuery, null, filterQuery.queryOptions).exec();
44
56
  },
45
- { input: filterArgs, serviceOptions }
57
+ { input: filter, serviceOptions }
46
58
  );
47
59
  }
48
60
 
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Falsy type for anything that is considered false if it occurs in a Boolean context
3
+ */
4
+ export type Falsy = false | 0 | '' | null | undefined;
package/src/index.ts CHANGED
@@ -34,6 +34,7 @@ export * from './core/common/inputs/single-filter.input';
34
34
  export * from './core/common/inputs/sort.input';
35
35
  export * from './core/common/interceptors/check-response.interceptor';
36
36
  export * from './core/common/interfaces/core-persistence-model.interface';
37
+ export * from './core/common/interfaces/cron-job-config.interface';
37
38
  export * from './core/common/interfaces/mailjet-options.interface';
38
39
  export * from './core/common/interfaces/prepare-input-options.interface';
39
40
  export * from './core/common/interfaces/prepare-output-options.interface';
@@ -48,12 +49,14 @@ export * from './core/common/scalars/any.scalar';
48
49
  export * from './core/common/scalars/date.scalar';
49
50
  export * from './core/common/scalars/json.scalar';
50
51
  export * from './core/common/services/config.service';
52
+ export * from './core/common/services/core-cron-jobs.service';
51
53
  export * from './core/common/services/crud.service';
52
54
  export * from './core/common/services/email.service';
53
55
  export * from './core/common/services/mailjet.service';
54
56
  export * from './core/common/services/module.service';
55
57
  export * from './core/common/services/template.service';
56
58
  export * from './core/common/types/core-model-constructor.type';
59
+ export * from './core/common/types/falsy.type';
57
60
  export * from './core/common/types/field-selection.type';
58
61
  export * from './core/common/types/ids.type';
59
62
  export * from './core/common/types/maybe-promise.type';
@@ -0,0 +1,26 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { SchedulerRegistry } from '@nestjs/schedule';
3
+ import envConfig from '../../../config.env';
4
+ import { CoreCronJobs } from '../../../core/common/services/core-cron-jobs.service';
5
+
6
+ @Injectable()
7
+ export class CronJobs extends CoreCronJobs {
8
+ // ===================================================================================================================
9
+ // Initializations
10
+ // ===================================================================================================================
11
+
12
+ /**
13
+ * Init cron jobs
14
+ */
15
+ constructor(protected schedulerRegistry: SchedulerRegistry) {
16
+ super(schedulerRegistry, envConfig.cronJobs, { log: true });
17
+ }
18
+
19
+ // ===================================================================================================================
20
+ // Cron jobs
21
+ // ===================================================================================================================
22
+
23
+ protected sayHello() {
24
+ console.log('Hello :)');
25
+ }
26
+ }
@@ -1,7 +1,9 @@
1
1
  import { Module } from '@nestjs/common';
2
+ import { ScheduleModule } from '@nestjs/schedule';
2
3
  import envConfig from '../config.env';
3
4
  import { CoreModule } from '../core.module';
4
5
  import { CoreAuthService } from '../core/modules/auth/services/core-auth.service';
6
+ import { CronJobs } from './common/services/cron-jobs.service';
5
7
  import { AuthModule } from './modules/auth/auth.module';
6
8
  import { FileModule } from './modules/file/file.module';
7
9
  import { ServerController } from './server.controller';
@@ -18,6 +20,9 @@ import { ServerController } from './server.controller';
18
20
  // Include CoreModule for standard processes
19
21
  CoreModule.forRoot(CoreAuthService, AuthModule.forRoot(envConfig.jwt), envConfig),
20
22
 
23
+ // Include cron job handling
24
+ ScheduleModule.forRoot(),
25
+
21
26
  // Include AuthModule for authorization handling,
22
27
  // which will also include UserModule
23
28
  AuthModule.forRoot(envConfig.jwt),
@@ -26,6 +31,8 @@ import { ServerController } from './server.controller';
26
31
  FileModule,
27
32
  ],
28
33
 
34
+ providers: [CronJobs],
35
+
29
36
  // Include REST controllers
30
37
  controllers: [ServerController],
31
38