@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.
- package/dist/config.env.js +37 -12
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/helpers/input.helper.d.ts +10 -1
- package/dist/core/common/helpers/input.helper.js +46 -4
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/helpers/model.helper.d.ts +4 -0
- package/dist/core/common/helpers/model.helper.js +22 -15
- package/dist/core/common/helpers/model.helper.js.map +1 -1
- package/dist/core/common/helpers/service.helper.d.ts +12 -0
- package/dist/core/common/helpers/service.helper.js +13 -5
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +1 -0
- package/dist/core/common/services/config.service.d.ts +75 -5
- package/dist/core/common/services/config.service.js +168 -4
- package/dist/core/common/services/config.service.js.map +1 -1
- package/dist/core/common/services/email.service.js +2 -2
- package/dist/core/common/services/email.service.js.map +1 -1
- package/dist/core/common/services/mailjet.service.js +4 -4
- package/dist/core/common/services/mailjet.service.js.map +1 -1
- package/dist/core/common/services/template.service.js +1 -1
- package/dist/core/common/services/template.service.js.map +1 -1
- package/dist/core/modules/user/core-user.service.d.ts +5 -3
- package/dist/core/modules/user/core-user.service.js +3 -3
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/server/common/services/cron-jobs.service.d.ts +3 -1
- package/dist/server/common/services/cron-jobs.service.js +5 -4
- package/dist/server/common/services/cron-jobs.service.js.map +1 -1
- package/dist/server/modules/auth/auth.service.d.ts +3 -1
- package/dist/server/modules/auth/auth.service.js +9 -4
- package/dist/server/modules/auth/auth.service.js.map +1 -1
- package/dist/server/modules/user/user.service.js +5 -3
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/server/server.controller.js +2 -2
- package/dist/server/server.controller.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +29 -28
- package/src/config.env.ts +39 -12
- package/src/core/common/helpers/input.helper.ts +68 -4
- package/src/core/common/helpers/model.helper.ts +26 -15
- package/src/core/common/helpers/service.helper.ts +25 -5
- package/src/core/common/interfaces/server-options.interface.ts +8 -0
- package/src/core/common/services/config.service.ts +378 -12
- package/src/core/common/services/email.service.ts +2 -2
- package/src/core/common/services/mailjet.service.ts +4 -4
- package/src/core/common/services/template.service.ts +1 -1
- package/src/core/modules/user/core-user.service.ts +5 -4
- package/src/server/common/services/cron-jobs.service.ts +3 -3
- package/src/server/modules/auth/auth.service.ts +7 -3
- package/src/server/modules/user/user.service.ts +5 -3
- 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": "
|
|
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:
|
|
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.
|
|
63
|
-
"@nestjs/common": "
|
|
64
|
-
"@nestjs/core": "
|
|
65
|
-
"@nestjs/graphql": "10.0.
|
|
66
|
-
"@nestjs/jwt": "
|
|
67
|
-
"@nestjs/mongoose": "9.
|
|
68
|
-
"@nestjs/passport": "
|
|
69
|
-
"@nestjs/platform-express": "
|
|
70
|
-
"@nestjs/schedule": "2.0
|
|
71
|
-
"apollo-server-core": "3.
|
|
72
|
-
"apollo-server-express": "3.
|
|
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.
|
|
82
|
+
"light-my-request": "5.1.0",
|
|
83
83
|
"lodash": "4.17.21",
|
|
84
|
-
"mongodb": "4.
|
|
85
|
-
"mongoose": "6.4.
|
|
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.
|
|
90
|
-
"nodemon": "2.0.
|
|
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.
|
|
96
|
+
"rxjs": "7.5.6"
|
|
96
97
|
},
|
|
97
98
|
"devDependencies": {
|
|
98
|
-
"@nestjs/testing": "
|
|
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.
|
|
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.
|
|
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.
|
|
109
|
-
"@typescript-eslint/parser": "5.30.
|
|
109
|
+
"@typescript-eslint/eslint-plugin": "5.30.6",
|
|
110
|
+
"@typescript-eslint/parser": "5.30.6",
|
|
110
111
|
"coffeescript": "2.7.0",
|
|
111
|
-
"eslint": "8.
|
|
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.
|
|
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.
|
|
126
|
+
"ts-jest": "28.0.7",
|
|
126
127
|
"ts-morph": "15.1.0",
|
|
127
|
-
"ts-node": "10.
|
|
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: '
|
|
26
|
-
pass: '
|
|
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: '
|
|
38
|
-
name: '
|
|
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: '
|
|
77
|
-
pass: '
|
|
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: '
|
|
89
|
-
name: '
|
|
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: '
|
|
128
|
-
pass: '
|
|
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: '
|
|
140
|
-
name: '
|
|
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(
|
|
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>(
|
|
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 ?
|
|
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] =
|
|
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 ?
|
|
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 (
|
|
195
|
-
arr.push(
|
|
196
|
-
} else if (
|
|
197
|
-
config.objectIdsToString ? arr.push(
|
|
198
|
-
} else if (typeof
|
|
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(
|
|
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 (
|
|
278
|
-
arr.push(
|
|
279
|
-
} else if (
|
|
280
|
-
config.objectIdsToString ? arr.push(
|
|
281
|
-
} else if (typeof
|
|
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(
|
|
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 =
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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
|
*/
|