@lenne.tech/nest-server 8.6.27 → 9.0.0

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 (50) hide show
  1. package/dist/config.env.js +37 -12
  2. package/dist/config.env.js.map +1 -1
  3. package/dist/core/common/helpers/input.helper.d.ts +10 -1
  4. package/dist/core/common/helpers/input.helper.js +46 -4
  5. package/dist/core/common/helpers/input.helper.js.map +1 -1
  6. package/dist/core/common/helpers/model.helper.d.ts +4 -0
  7. package/dist/core/common/helpers/model.helper.js +22 -15
  8. package/dist/core/common/helpers/model.helper.js.map +1 -1
  9. package/dist/core/common/helpers/service.helper.d.ts +12 -0
  10. package/dist/core/common/helpers/service.helper.js +13 -5
  11. package/dist/core/common/helpers/service.helper.js.map +1 -1
  12. package/dist/core/common/interfaces/server-options.interface.d.ts +1 -0
  13. package/dist/core/common/services/config.service.d.ts +75 -5
  14. package/dist/core/common/services/config.service.js +168 -4
  15. package/dist/core/common/services/config.service.js.map +1 -1
  16. package/dist/core/common/services/email.service.js +2 -2
  17. package/dist/core/common/services/email.service.js.map +1 -1
  18. package/dist/core/common/services/mailjet.service.js +4 -4
  19. package/dist/core/common/services/mailjet.service.js.map +1 -1
  20. package/dist/core/common/services/template.service.js +1 -1
  21. package/dist/core/common/services/template.service.js.map +1 -1
  22. package/dist/core/modules/user/core-user.service.d.ts +5 -3
  23. package/dist/core/modules/user/core-user.service.js +3 -3
  24. package/dist/core/modules/user/core-user.service.js.map +1 -1
  25. package/dist/server/common/services/cron-jobs.service.d.ts +3 -1
  26. package/dist/server/common/services/cron-jobs.service.js +5 -4
  27. package/dist/server/common/services/cron-jobs.service.js.map +1 -1
  28. package/dist/server/modules/auth/auth.service.d.ts +3 -1
  29. package/dist/server/modules/auth/auth.service.js +9 -4
  30. package/dist/server/modules/auth/auth.service.js.map +1 -1
  31. package/dist/server/modules/user/user.service.js +5 -3
  32. package/dist/server/modules/user/user.service.js.map +1 -1
  33. package/dist/server/server.controller.js +2 -2
  34. package/dist/server/server.controller.js.map +1 -1
  35. package/dist/tsconfig.build.tsbuildinfo +1 -1
  36. package/package.json +29 -28
  37. package/src/config.env.ts +39 -12
  38. package/src/core/common/helpers/input.helper.ts +68 -4
  39. package/src/core/common/helpers/model.helper.ts +26 -15
  40. package/src/core/common/helpers/service.helper.ts +25 -5
  41. package/src/core/common/interfaces/server-options.interface.ts +8 -0
  42. package/src/core/common/services/config.service.ts +378 -12
  43. package/src/core/common/services/email.service.ts +2 -2
  44. package/src/core/common/services/mailjet.service.ts +4 -4
  45. package/src/core/common/services/template.service.ts +1 -1
  46. package/src/core/modules/user/core-user.service.ts +5 -4
  47. package/src/server/common/services/cron-jobs.service.ts +3 -3
  48. package/src/server/modules/auth/auth.service.ts +7 -3
  49. package/src/server/modules/user/user.service.ts +5 -3
  50. package/src/server/server.controller.ts +2 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nest-server",
3
- "version": "8.6.27",
3
+ "version": "9.0.0",
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",
@@ -18,7 +18,7 @@
18
18
  "build:pack": "npm pack && echo 'use file:/ROOT_PATH_TO_TGZ_FILE to integrate the package'",
19
19
  "docs": "npm run docs:ci && open ./public/index.html",
20
20
  "docs:bootstrap": "node extras/update-spectaql-version.mjs && npx -y spectaql ./spectaql.yml",
21
- "docs:ci": "ts-node ./scripts/init-server.ts && npm run docs:boostrap",
21
+ "docs:ci": "ts-node ./scripts/init-server.ts && npm run docs:bootstrap",
22
22
  "format": "prettier --write 'src/**/*.ts'",
23
23
  "format:staged": "pretty-quick --staged",
24
24
  "lint": "eslint \"{src,tests}/**/*.ts\" --fix",
@@ -59,17 +59,17 @@
59
59
  },
60
60
  "dependencies": {
61
61
  "@apollo/gateway": "2.0.5",
62
- "@nestjs/apollo": "10.0.16",
63
- "@nestjs/common": "8.4.7",
64
- "@nestjs/core": "8.4.7",
65
- "@nestjs/graphql": "10.0.16",
66
- "@nestjs/jwt": "8.0.1",
67
- "@nestjs/mongoose": "9.1.1",
68
- "@nestjs/passport": "8.2.2",
69
- "@nestjs/platform-express": "8.4.7",
70
- "@nestjs/schedule": "2.0.1",
71
- "apollo-server-core": "3.9.0",
72
- "apollo-server-express": "3.9.0",
62
+ "@nestjs/apollo": "10.0.17",
63
+ "@nestjs/common": "9.0.3",
64
+ "@nestjs/core": "9.0.3",
65
+ "@nestjs/graphql": "10.0.18",
66
+ "@nestjs/jwt": "9.0.0",
67
+ "@nestjs/mongoose": "9.2.0",
68
+ "@nestjs/passport": "9.0.0",
69
+ "@nestjs/platform-express": "9.0.3",
70
+ "@nestjs/schedule": "2.1.0",
71
+ "apollo-server-core": "3.10.0",
72
+ "apollo-server-express": "3.10.0",
73
73
  "bcrypt": "5.0.1",
74
74
  "class-transformer": "0.5.1",
75
75
  "class-validator": "0.13.2",
@@ -79,36 +79,37 @@
79
79
  "graphql-upload": "15.0.2",
80
80
  "js-sha256": "0.9.0",
81
81
  "json-to-graphql-query": "2.2.4",
82
- "light-my-request": "5.0.0",
82
+ "light-my-request": "5.1.0",
83
83
  "lodash": "4.17.21",
84
- "mongodb": "4.7.0",
85
- "mongoose": "6.4.2",
84
+ "mongodb": "4.8.0",
85
+ "mongoose": "6.4.4",
86
86
  "mongoose-gridfs": "1.3.0",
87
87
  "multer": "1.4.5-lts.1",
88
88
  "node-mailjet": "5.0.1",
89
- "nodemailer": "6.7.6",
90
- "nodemon": "2.0.18",
89
+ "nodemailer": "6.7.7",
90
+ "nodemon": "2.0.19",
91
91
  "passport": "0.6.0",
92
92
  "passport-jwt": "4.0.0",
93
93
  "reflect-metadata": "0.1.13",
94
+ "rfdc": "1.3.0",
94
95
  "rimraf": "3.0.2",
95
- "rxjs": "7.5.5"
96
+ "rxjs": "7.5.6"
96
97
  },
97
98
  "devDependencies": {
98
- "@nestjs/testing": "8.4.7",
99
+ "@nestjs/testing": "9.0.3",
99
100
  "@types/cron": "2.0.0",
100
101
  "@types/ejs": "3.1.1",
101
- "@types/jest": "28.1.4",
102
+ "@types/jest": "28.1.6",
102
103
  "@types/lodash": "4.14.182",
103
104
  "@types/multer": "1.4.7",
104
- "@types/node": "18.0.1",
105
+ "@types/node": "18.0.5",
105
106
  "@types/nodemailer": "6.4.4",
106
107
  "@types/passport": "1.0.9",
107
108
  "@types/supertest": "2.0.12",
108
- "@typescript-eslint/eslint-plugin": "5.30.4",
109
- "@typescript-eslint/parser": "5.30.4",
109
+ "@typescript-eslint/eslint-plugin": "5.30.6",
110
+ "@typescript-eslint/parser": "5.30.6",
110
111
  "coffeescript": "2.7.0",
111
- "eslint": "8.19.0",
112
+ "eslint": "8.20.0",
112
113
  "eslint-config-prettier": "8.5.0",
113
114
  "find-file-up": "2.0.1",
114
115
  "grunt": "1.5.3",
@@ -117,14 +118,14 @@
117
118
  "grunt-contrib-watch": "1.1.0",
118
119
  "grunt-sync": "0.8.2",
119
120
  "husky": "8.0.1",
120
- "jest": "28.1.2",
121
+ "jest": "28.1.3",
121
122
  "pm2": "5.2.0",
122
123
  "prettier": "2.7.1",
123
124
  "pretty-quick": "3.1.3",
124
125
  "supertest": "6.2.4",
125
- "ts-jest": "28.0.5",
126
+ "ts-jest": "28.0.7",
126
127
  "ts-morph": "15.1.0",
127
- "ts-node": "10.8.2",
128
+ "ts-node": "10.9.1",
128
129
  "tsconfig-paths": "4.0.0",
129
130
  "typescript": "4.7.4"
130
131
  },
package/src/config.env.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { CronExpression } from '@nestjs/schedule';
2
2
  import { join } from 'path';
3
+ import { merge } from './core/common/helpers/config.helper';
3
4
  import { IServerOptions } from './core/common/interfaces/server-options.interface';
4
5
 
5
6
  /**
@@ -22,8 +23,8 @@ const config: { [env: string]: IServerOptions } = {
22
23
  email: {
23
24
  smtp: {
24
25
  auth: {
25
- user: 'rebeca68@ethereal.email',
26
- pass: 'v5WUScAN98AzGbRjpc',
26
+ user: 'sandra98@ethereal.email',
27
+ pass: 'JCQQdz8xJEfBSewahK',
27
28
  },
28
29
  host: 'smtp.ethereal.email',
29
30
  port: 587,
@@ -34,8 +35,8 @@ const config: { [env: string]: IServerOptions } = {
34
35
  api_key_private: 'MAILJET_API_KEY_PRIVATE',
35
36
  },
36
37
  defaultSender: {
37
- email: 'rebeca68@ethereal.email',
38
- name: 'Rebeca Sixtyeight',
38
+ email: 'sandra98@ethereal.email',
39
+ name: 'Sandra Klein',
39
40
  },
40
41
  verificationLink: 'http://localhost:4200/user/verification',
41
42
  passwordResetLink: 'http://localhost:4200/user/password-reset',
@@ -51,6 +52,7 @@ const config: { [env: string]: IServerOptions } = {
51
52
  jwt: {
52
53
  secret: 'SECRET_OR_PRIVATE_KEY_DEV',
53
54
  },
55
+ loadLocalConfig: false,
54
56
  mongoose: {
55
57
  uri: 'mongodb://localhost/nest-server-dev',
56
58
  },
@@ -73,8 +75,8 @@ const config: { [env: string]: IServerOptions } = {
73
75
  email: {
74
76
  smtp: {
75
77
  auth: {
76
- user: 'rebeca68@ethereal.email',
77
- pass: 'v5WUScAN98AzGbRjpc',
78
+ user: 'sandra98@ethereal.email',
79
+ pass: 'JCQQdz8xJEfBSewahK',
78
80
  },
79
81
  host: 'smtp.ethereal.email',
80
82
  port: 587,
@@ -85,8 +87,8 @@ const config: { [env: string]: IServerOptions } = {
85
87
  api_key_private: 'MAILJET_API_KEY_PRIVATE',
86
88
  },
87
89
  defaultSender: {
88
- email: 'rebeca68@ethereal.email',
89
- name: 'Rebeca Sixtyeight',
90
+ email: 'sandra98@ethereal.email',
91
+ name: 'Sandra Klein',
90
92
  },
91
93
  verificationLink: 'http://localhost:4200/user/verification',
92
94
  passwordResetLink: 'http://localhost:4200/user/password-reset',
@@ -102,6 +104,7 @@ const config: { [env: string]: IServerOptions } = {
102
104
  jwt: {
103
105
  secret: 'SECRET_OR_PRIVATE_KEY_DEV',
104
106
  },
107
+ loadLocalConfig: false,
105
108
  mongoose: {
106
109
  uri: 'mongodb://localhost/nest-server-dev',
107
110
  },
@@ -124,8 +127,8 @@ const config: { [env: string]: IServerOptions } = {
124
127
  email: {
125
128
  smtp: {
126
129
  auth: {
127
- user: 'rebeca68@ethereal.email',
128
- pass: 'v5WUScAN98AzGbRjpc',
130
+ user: 'sandra98@ethereal.email',
131
+ pass: 'JCQQdz8xJEfBSewahK',
129
132
  },
130
133
  host: 'smtp.ethereal.email',
131
134
  port: 587,
@@ -136,8 +139,8 @@ const config: { [env: string]: IServerOptions } = {
136
139
  api_key_private: 'MAILJET_API_KEY_PRIVATE',
137
140
  },
138
141
  defaultSender: {
139
- email: 'rebeca68@ethereal.email',
140
- name: 'Rebeca Sixtyeight',
142
+ email: 'sandra98@ethereal.email',
143
+ name: 'Sandra Klein',
141
144
  },
142
145
  verificationLink: 'http://localhost:4200/user/verification',
143
146
  passwordResetLink: 'http://localhost:4200/user/password-reset',
@@ -153,6 +156,7 @@ const config: { [env: string]: IServerOptions } = {
153
156
  jwt: {
154
157
  secret: 'SECRET_OR_PRIVATE_KEY_PROD',
155
158
  },
159
+ loadLocalConfig: false,
156
160
  mongoose: {
157
161
  uri: 'mongodb://localhost/nest-server-prod',
158
162
  },
@@ -178,6 +182,29 @@ const env = process.env['NODE' + '_ENV'] || 'development';
178
182
  const envConfig = config[env] || config.development;
179
183
  console.info('Configured for: ' + envConfig.env + (env !== envConfig.env ? ' (requested: ' + env + ')' : ''));
180
184
 
185
+ // Merge with localConfig (e.g. config.json)
186
+ if (envConfig.loadLocalConfig) {
187
+ let localConfig;
188
+ if (typeof envConfig.loadLocalConfig === 'string') {
189
+ localConfig = require(envConfig.loadLocalConfig);
190
+ merge(envConfig, localConfig);
191
+ } else {
192
+ try {
193
+ // get config from src directory
194
+ localConfig = require(__dirname + '/config.json');
195
+ merge(envConfig, localConfig);
196
+ } catch {
197
+ try {
198
+ // if not found try to find in project directory
199
+ localConfig = require(__dirname + '/../config.json');
200
+ merge(envConfig, localConfig);
201
+ } catch (e) {
202
+ // No config.json found => nothing to do
203
+ }
204
+ }
205
+ }
206
+ }
207
+
181
208
  /**
182
209
  * Export envConfig as default
183
210
  */
@@ -3,6 +3,7 @@ import { plainToInstance } from 'class-transformer';
3
3
  import { validate } from 'class-validator';
4
4
  import { ValidatorOptions } from 'class-validator/types/validation/ValidatorOptions';
5
5
  import * as _ from 'lodash';
6
+ import * as rfdc from 'rfdc';
6
7
  import { checkRestricted } from '../decorators/restricted.decorator';
7
8
  import { ProcessType } from '../enums/process-type.enum';
8
9
  import { RoleEnum } from '../enums/role.enum';
@@ -196,7 +197,7 @@ export function assignPlain(target: Record<any, any>, ...args: Record<any, any>[
196
197
  ? // Return item if not an object
197
198
  item
198
199
  : // Return cloned record with undefined properties removed
199
- filterProperties(JSON.parse(JSON.stringify(item)), (prop) => prop !== undefined)
200
+ filterProperties(clone(item, { circles: false }), (prop) => prop !== undefined)
200
201
  )
201
202
  );
202
203
  }
@@ -297,6 +298,44 @@ export async function check(
297
298
  return value;
298
299
  }
299
300
 
301
+ /**
302
+ * Clone object
303
+ * @param object Any object
304
+ * @param options Finetuning of rfdc cloning
305
+ * @param options.proto Copy prototype properties as well as own properties into the new object.
306
+ * It's marginally faster to allow enumerable properties on the prototype to be copied into the
307
+ * cloned object (not onto it's prototype, directly onto the object).
308
+ * @param options.circles Keeping track of circular references will slow down performance with an additional 25% overhead.
309
+ * Even if an object doesn't have any circular references, the tracking overhead is the cost.
310
+ * By default if an object with a circular reference is passed to rfdc, it will throw
311
+ * (similar to how JSON.stringify would throw). Use the circles option to detect and preserve
312
+ * circular references in the object. If performance is important, try removing the circular
313
+ * reference from the object (set to undefined) and then add it back manually after cloning
314
+ * instead of using this option.
315
+ */
316
+ export function clone(object: any, options?: { proto?: boolean; circles?: boolean }) {
317
+ const config = {
318
+ proto: false,
319
+ circles: true,
320
+ ...options,
321
+ };
322
+ try {
323
+ return rfdc(config)(object);
324
+ } catch (e) {
325
+ console.debug(e);
326
+ if (!config.circles) {
327
+ try {
328
+ return rfdc({ ...config, ...{ circles: true } })(object);
329
+ } catch (e) {
330
+ console.debug(e);
331
+ return _.clone(object);
332
+ }
333
+ } else {
334
+ return _.clone(object);
335
+ }
336
+ }
337
+ }
338
+
300
339
  /**
301
340
  * Combines objects to a new single plain object and ignores undefined
302
341
  */
@@ -304,6 +343,19 @@ export function combinePlain(...args: Record<any, any>[]): any {
304
343
  return assignPlain({}, ...args);
305
344
  }
306
345
 
346
+ /**
347
+ * Get deep frozen object
348
+ */
349
+ export function deepFreeze(object: any) {
350
+ if (typeof object !== 'object') {
351
+ return object;
352
+ }
353
+ for (const [key, value] of Object.entries(object)) {
354
+ object[key] = deepFreeze(value);
355
+ }
356
+ return Object.freeze(object);
357
+ }
358
+
307
359
  /**
308
360
  * Standard error function
309
361
  */
@@ -327,7 +379,6 @@ export function filterProperties<T = Record<string, any>>(
327
379
 
328
380
  /**
329
381
  * Get plain copy of object
330
- * @param element
331
382
  */
332
383
  export function getPlain(object: any) {
333
384
  return JSON.parse(JSON.stringify(object));
@@ -512,11 +563,24 @@ export function match(expression: any, cases: Record<any, any>): any {
512
563
  /**
513
564
  * Map values into specific type
514
565
  */
515
- export function mapClass<T>(values: Partial<T>, ctor: new () => T, cloneDeep = true): T {
566
+ export function mapClass<T>(
567
+ values: Partial<T>,
568
+ ctor: new () => T,
569
+ options?: {
570
+ cloneDeep?: boolean;
571
+ circle?: boolean;
572
+ proto?: boolean;
573
+ }
574
+ ): T {
575
+ const config = {
576
+ cloneDeep: true,
577
+ circles: false,
578
+ proto: false,
579
+ };
516
580
  const instance = new ctor();
517
581
 
518
582
  return Object.keys(instance).reduce((obj, key) => {
519
- obj[key] = cloneDeep ? _.cloneDeep(values[key]) : values[key];
583
+ obj[key] = config.cloneDeep ? clone(values[key], { circles: config.circles, proto: config.proto }) : values[key];
520
584
  return obj;
521
585
  }, instance);
522
586
  }
@@ -1,6 +1,6 @@
1
1
  import { plainToInstance } from 'class-transformer';
2
- import * as _ from 'lodash';
3
2
  import { Types } from 'mongoose';
3
+ import { clone } from './input.helper';
4
4
 
5
5
  /**
6
6
  * Helper class for models
@@ -63,15 +63,19 @@ export function prepareMap<T = Record<string, any>>(
63
63
  target: T,
64
64
  options: {
65
65
  cloneDeep?: boolean;
66
+ circles?: boolean;
66
67
  funcAllowed?: boolean;
67
68
  mapId?: boolean;
69
+ proto?: boolean;
68
70
  } = {}
69
71
  ): Partial<T> | Record<string, any> {
70
72
  // Set config
71
73
  const config = {
72
74
  cloneDeep: true,
75
+ circles: true,
73
76
  funcAllowed: false,
74
77
  mapId: false,
78
+ proto: false,
75
79
  ...options,
76
80
  };
77
81
 
@@ -85,7 +89,10 @@ export function prepareMap<T = Record<string, any>>(
85
89
  source[key] !== undefined &&
86
90
  (config.funcAllowed || typeof (source[key] !== 'function'))
87
91
  ) {
88
- result[key] = source[key] !== 'function' && config.cloneDeep ? _.cloneDeep(source[key]) : source[key];
92
+ result[key] =
93
+ source[key] !== 'function' && config.cloneDeep
94
+ ? clone(source[key], { circles: config.circles, proto: config.proto })
95
+ : source[key];
89
96
  } else if (key === 'id' && !config.mapId) {
90
97
  result['id'] = source[key];
91
98
  }
@@ -102,21 +109,25 @@ export function map<T = Record<string, any>>(
102
109
  target: T,
103
110
  options: {
104
111
  cloneDeep?: boolean;
112
+ circles?: boolean;
105
113
  funcAllowed?: boolean;
106
114
  mapId?: boolean;
115
+ proto?: boolean;
107
116
  } = {}
108
117
  ): T {
109
118
  // Set config
110
119
  const config = {
111
120
  cloneDeep: true,
121
+ circles: false,
112
122
  funcAllowed: false,
113
123
  mapId: false,
124
+ proto: false,
114
125
  ...options,
115
126
  };
116
127
 
117
128
  // Check source
118
129
  if (!source || typeof source !== 'object' || Array.isArray(source)) {
119
- return config.cloneDeep ? _.cloneDeep(target) : target;
130
+ return config.cloneDeep ? clone(target, { circles: config.circles, proto: config.proto }) : target;
120
131
  }
121
132
 
122
133
  // Prepare source
@@ -191,18 +202,18 @@ export function mapClasses<T = Record<string, any>>(
191
202
  if (Array.isArray(value)) {
192
203
  const arr = [];
193
204
  for (const item of value) {
194
- if (value instanceof targetClass) {
195
- arr.push(value);
196
- } else if (value instanceof Types.ObjectId) {
197
- config.objectIdsToString ? arr.push(value.toHexString()) : arr.push(value);
198
- } else if (typeof value === 'object') {
205
+ if (item instanceof targetClass) {
206
+ arr.push(item);
207
+ } else if (item instanceof Types.ObjectId) {
208
+ config.objectIdsToString ? arr.push(item.toHexString()) : arr.push(item);
209
+ } else if (typeof item === 'object') {
199
210
  if (targetClass.map) {
200
211
  arr.push(targetClass.map(item));
201
212
  } else {
202
213
  arr.push(plainToInstance(targetClass, item));
203
214
  }
204
215
  } else {
205
- arr.push(value);
216
+ arr.push(item);
206
217
  }
207
218
  }
208
219
  target[prop] = arr as any;
@@ -274,18 +285,18 @@ export async function mapClassesAsync<T = Record<string, any>>(
274
285
  if (Array.isArray(value)) {
275
286
  const arr = [];
276
287
  for (const item of value) {
277
- if (value instanceof targetClass) {
278
- arr.push(value);
279
- } else if (value instanceof Types.ObjectId) {
280
- config.objectIdsToString ? arr.push(value.toHexString()) : arr.push(value);
281
- } else if (typeof value === 'object') {
288
+ if (item instanceof targetClass) {
289
+ arr.push(item);
290
+ } else if (item instanceof Types.ObjectId) {
291
+ config.objectIdsToString ? arr.push(item.toHexString()) : arr.push(item);
292
+ } else if (typeof item === 'object') {
282
293
  if (targetClass.map) {
283
294
  arr.push(await targetClass.map(item));
284
295
  } else {
285
296
  arr.push(plainToInstance(targetClass, item));
286
297
  }
287
298
  } else {
288
- arr.push(value);
299
+ arr.push(item);
289
300
  }
290
301
  }
291
302
  target[prop] = arr as any;
@@ -4,12 +4,13 @@ import { plainToInstance } from 'class-transformer';
4
4
  import { sha256 } from 'js-sha256';
5
5
  import * as _ from 'lodash';
6
6
  import { Types } from 'mongoose';
7
- import envConfig from '../../../config.env';
8
7
  import { RoleEnum } from '../enums/role.enum';
9
8
  import { PrepareInputOptions } from '../interfaces/prepare-input-options.interface';
10
9
  import { PrepareOutputOptions } from '../interfaces/prepare-output-options.interface';
11
10
  import { ResolveSelector } from '../interfaces/resolve-selector.interface';
12
11
  import { ServiceOptions } from '../interfaces/service-options.interface';
12
+ import { ConfigService } from '../services/config.service';
13
+ import { clone } from './input.helper';
13
14
 
14
15
  /**
15
16
  * Helper class for services
@@ -24,10 +25,13 @@ export default class ServiceHelper {
24
25
  currentUser: { [key: string]: any; id: string },
25
26
  options: {
26
27
  [key: string]: any;
28
+ checkRoles?: boolean;
27
29
  create?: boolean;
28
30
  clone?: boolean;
29
31
  getNewArray?: boolean;
30
32
  removeUndefined?: boolean;
33
+ sha256?: boolean;
34
+ targetModel?: new (...args: any[]) => T;
31
35
  } = {}
32
36
  ): Promise<T> {
33
37
  return prepareInput(input, currentUser, options);
@@ -42,6 +46,8 @@ export default class ServiceHelper {
42
46
  [key: string]: any;
43
47
  clone?: boolean;
44
48
  getNewArray?: boolean;
49
+ objectIdsToStrings?: boolean;
50
+ removeSecrets?: boolean;
45
51
  removeUndefined?: boolean;
46
52
  targetModel?: new (...args: any[]) => T;
47
53
  } = {}
@@ -59,10 +65,13 @@ export async function prepareInput<T = any>(
59
65
  options: {
60
66
  [key: string]: any;
61
67
  checkRoles?: boolean;
68
+ circles?: boolean;
62
69
  create?: boolean;
63
70
  clone?: boolean;
64
71
  getNewArray?: boolean;
72
+ proto?: boolean;
65
73
  removeUndefined?: boolean;
74
+ sha256?: boolean;
66
75
  targetModel?: new (...args: any[]) => T;
67
76
  } = {}
68
77
  ): Promise<T> {
@@ -70,9 +79,12 @@ export async function prepareInput<T = any>(
70
79
  const config = {
71
80
  checkRoles: false,
72
81
  clone: false,
82
+ circles: false,
73
83
  create: false,
74
84
  getNewArray: false,
85
+ proto: false,
75
86
  removeUndefined: true,
87
+ sha256: ConfigService.configFastButReadOnly.sha256,
76
88
  ...options,
77
89
  };
78
90
 
@@ -98,7 +110,7 @@ export async function prepareInput<T = any>(
98
110
  if ((input as Record<string, any>).mapDeep && typeof (input as any).mapDeep === 'function') {
99
111
  input = await Object.getPrototypeOf(input).mapDeep(input);
100
112
  } else {
101
- input = _.cloneDeep(input);
113
+ input = clone(input, { circles: config.circles, proto: config.proto });
102
114
  }
103
115
  }
104
116
 
@@ -134,7 +146,7 @@ export async function prepareInput<T = any>(
134
146
  if ((input as any).password) {
135
147
  // Check if the password was transmitted encrypted
136
148
  // If not, the password is encrypted to enable future encrypted and unencrypted transmissions
137
- if (envConfig.sha256 && !/^[a-f0-9]{64}$/i.test((input as any).password)) {
149
+ if (config.sha256 && !/^[a-f0-9]{64}$/i.test((input as any).password)) {
138
150
  (input as any).password = sha256((input as any).password);
139
151
  }
140
152
 
@@ -164,8 +176,10 @@ export async function prepareOutput<T = { [key: string]: any; map: (...args: any
164
176
  options: {
165
177
  [key: string]: any;
166
178
  clone?: boolean;
179
+ circles?: boolean;
167
180
  getNewArray?: boolean;
168
181
  objectIdsToStrings?: boolean;
182
+ proto?: boolean;
169
183
  removeSecrets?: boolean;
170
184
  removeUndefined?: boolean;
171
185
  targetModel?: new (...args: any[]) => T;
@@ -174,8 +188,10 @@ export async function prepareOutput<T = { [key: string]: any; map: (...args: any
174
188
  // Configuration
175
189
  const config = {
176
190
  clone: false,
191
+ circles: false,
177
192
  getNewArray: false,
178
193
  objectIdsToStrings: true,
194
+ proto: false,
179
195
  removeSecrets: true,
180
196
  removeUndefined: false,
181
197
  targetModel: undefined,
@@ -204,7 +220,7 @@ export async function prepareOutput<T = { [key: string]: any; map: (...args: any
204
220
  if (output.mapDeep && typeof output.mapDeep === 'function') {
205
221
  output = await Object.getPrototypeOf(output).mapDeep(output);
206
222
  } else {
207
- output = _.cloneDeep(output);
223
+ output = clone(output, { circles: config.circles, proto: config.proto });
208
224
  }
209
225
  }
210
226
 
@@ -259,9 +275,11 @@ export function prepareServiceOptions(
259
275
  serviceOptions: ServiceOptions,
260
276
  options?: {
261
277
  clone?: boolean;
278
+ circles?: boolean;
262
279
  inputType?: any;
263
280
  outputType?: any;
264
281
  subFieldSelection?: string;
282
+ proto?: boolean;
265
283
  prepareInput?: PrepareInputOptions;
266
284
  prepareOutput?: PrepareOutputOptions;
267
285
  }
@@ -269,12 +287,14 @@ export function prepareServiceOptions(
269
287
  // Set default values
270
288
  const config = {
271
289
  clone: true,
290
+ circles: true,
291
+ proto: false,
272
292
  ...options,
273
293
  };
274
294
 
275
295
  // Clone
276
296
  if (serviceOptions && config.clone) {
277
- serviceOptions = _.cloneDeep(serviceOptions);
297
+ serviceOptions = clone(serviceOptions, { circles: config.circles, proto: config.proto });
278
298
  }
279
299
 
280
300
  // Init if not exists
@@ -128,6 +128,14 @@ export interface IServerOptions {
128
128
  secretOrPrivateKey?: string;
129
129
  } & JwtModuleOptions;
130
130
 
131
+ /**
132
+ * Load local configuration
133
+ * false: no local configuration is loaded,
134
+ * true: it tries to load ./config.json or ../config.json,
135
+ * string: path to configuration
136
+ */
137
+ loadLocalConfig?: boolean | string;
138
+
131
139
  /**
132
140
  * Configuration for Mongoose
133
141
  */