@lenne.tech/nest-server 3.3.0 → 3.3.1
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/core/common/helpers/graphql.helper.d.ts +4 -4
- package/dist/core/common/helpers/service.helper.d.ts +10 -5
- package/dist/core/common/helpers/service.helper.js +23 -7
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/common/interfaces/core-persistence-model.interface.d.ts +1 -0
- package/dist/core/common/interfaces/server-options.interface.d.ts +3 -15
- package/dist/core/common/models/core-model.model.d.ts +3 -3
- package/dist/core/common/models/core-model.model.js +5 -3
- package/dist/core/common/models/core-model.model.js.map +1 -1
- package/dist/core.module.js +2 -1
- package/dist/core.module.js.map +1 -1
- package/dist/server/common/models/persistence.model.d.ts +3 -2
- package/dist/server/common/models/persistence.model.js +2 -2
- package/dist/server/common/models/persistence.model.js.map +1 -1
- package/dist/server/modules/user/user.service.d.ts +3 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +26 -26
- package/src/core/common/helpers/service.helper.ts +63 -21
- package/src/core/common/interfaces/core-persistence-model.interface.ts +1 -0
- package/src/core/common/interfaces/server-options.interface.ts +3 -33
- package/src/core/common/models/core-model.model.ts +16 -6
- package/src/core/common/models/core-persistence.model.ts +1 -1
- package/src/core.module.ts +2 -1
- package/src/server/common/models/persistence.model.ts +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.1",
|
|
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",
|
|
@@ -52,11 +52,11 @@
|
|
|
52
52
|
"node": ">= 16.13.0"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@apollo/
|
|
56
|
-
"@apollo
|
|
55
|
+
"@apollo/gateway": "0.48.1",
|
|
56
|
+
"@nestjs/apollo": "10.0.2",
|
|
57
57
|
"@nestjs/common": "8.2.6",
|
|
58
58
|
"@nestjs/core": "8.2.6",
|
|
59
|
-
"@nestjs/graphql": "
|
|
59
|
+
"@nestjs/graphql": "10.0.2",
|
|
60
60
|
"@nestjs/jwt": "8.0.0",
|
|
61
61
|
"@nestjs/mongoose": "9.0.2",
|
|
62
62
|
"@nestjs/passport": "8.1.0",
|
|
@@ -67,22 +67,24 @@
|
|
|
67
67
|
"@types/jest": "27.4.0",
|
|
68
68
|
"@types/lodash": "4.14.178",
|
|
69
69
|
"@types/multer": "1.4.7",
|
|
70
|
-
"@types/node": "
|
|
70
|
+
"@types/node": "17.0.17",
|
|
71
71
|
"@types/node-mailjet": "3.3.8",
|
|
72
72
|
"@types/nodemailer": "6.4.4",
|
|
73
73
|
"@types/passport": "1.0.7",
|
|
74
74
|
"@types/supertest": "2.0.11",
|
|
75
|
-
"@typescript-eslint/eslint-plugin": "5.
|
|
76
|
-
"@typescript-eslint/parser": "5.
|
|
77
|
-
"apollo-server-core": "3.6.
|
|
78
|
-
"apollo-server-express": "3.6.
|
|
75
|
+
"@typescript-eslint/eslint-plugin": "5.11.0",
|
|
76
|
+
"@typescript-eslint/parser": "5.11.0",
|
|
77
|
+
"apollo-server-core": "3.6.3",
|
|
78
|
+
"apollo-server-express": "3.6.3",
|
|
79
79
|
"bcrypt": "5.0.1",
|
|
80
80
|
"class-transformer": "0.5.1",
|
|
81
81
|
"class-validator": "0.13.2",
|
|
82
82
|
"coffeescript": "2.6.1",
|
|
83
83
|
"ejs": "3.1.6",
|
|
84
|
-
"
|
|
85
|
-
"
|
|
84
|
+
"eslint": "8.9.0",
|
|
85
|
+
"eslint-config-prettier": "8.3.0",
|
|
86
|
+
"fastify": "3.27.1",
|
|
87
|
+
"graphql": "16.3.0",
|
|
86
88
|
"graphql-subscriptions": "2.0.0",
|
|
87
89
|
"grunt": "1.4.1",
|
|
88
90
|
"grunt-bg-shell": "2.3.3",
|
|
@@ -90,35 +92,33 @@
|
|
|
90
92
|
"grunt-contrib-watch": "1.1.0",
|
|
91
93
|
"grunt-sync": "0.8.2",
|
|
92
94
|
"husky": "7.0.4",
|
|
93
|
-
"jest": "27.
|
|
94
|
-
"json-to-graphql-query": "2.2.
|
|
95
|
-
"light-my-request": "4.7.
|
|
95
|
+
"jest": "27.5.1",
|
|
96
|
+
"json-to-graphql-query": "2.2.2",
|
|
97
|
+
"light-my-request": "4.7.1",
|
|
96
98
|
"lodash": "4.17.21",
|
|
97
|
-
"mongodb": "4.3.
|
|
98
|
-
"mongoose": "6.1
|
|
99
|
+
"mongodb": "4.3.1",
|
|
100
|
+
"mongoose": "6.2.1",
|
|
99
101
|
"multer": "1.4.4",
|
|
100
102
|
"node-mailjet": "3.3.5",
|
|
101
103
|
"nodemailer": "6.7.2",
|
|
102
104
|
"nodemon": "2.0.15",
|
|
103
105
|
"passport": "0.5.2",
|
|
104
106
|
"passport-jwt": "4.0.0",
|
|
107
|
+
"prettier": "2.5.1",
|
|
108
|
+
"pretty-quick": "3.1.3",
|
|
105
109
|
"reflect-metadata": "0.1.13",
|
|
106
110
|
"rimraf": "3.0.2",
|
|
107
|
-
"rxjs": "7.5.
|
|
111
|
+
"rxjs": "7.5.4",
|
|
108
112
|
"supertest": "6.2.2",
|
|
113
|
+
"ts-jest": "27.1.3",
|
|
109
114
|
"ts-morph": "13.0.3",
|
|
110
|
-
"ts-node": "10.
|
|
111
|
-
"tsconfig-paths": "3.12.0"
|
|
115
|
+
"ts-node": "10.5.0",
|
|
116
|
+
"tsconfig-paths": "3.12.0",
|
|
117
|
+
"typescript": "4.5.5"
|
|
112
118
|
},
|
|
113
119
|
"devDependencies": {
|
|
114
|
-
"eslint": "8.7.0",
|
|
115
|
-
"eslint-config-prettier": "8.3.0",
|
|
116
120
|
"find-file-up": "2.0.1",
|
|
117
|
-
"pm2": "5.1.2"
|
|
118
|
-
"prettier": "2.5.1",
|
|
119
|
-
"pretty-quick": "3.1.3",
|
|
120
|
-
"ts-jest": "27.1.3",
|
|
121
|
-
"typescript": "4.5.5"
|
|
121
|
+
"pm2": "5.1.2"
|
|
122
122
|
},
|
|
123
123
|
"jest": {
|
|
124
124
|
"collectCoverage": true,
|
|
@@ -10,24 +10,44 @@ export class ServiceHelper {
|
|
|
10
10
|
/**
|
|
11
11
|
* Prepare input before save
|
|
12
12
|
*/
|
|
13
|
-
static async prepareInput(
|
|
14
|
-
input:
|
|
13
|
+
static async prepareInput<T = any>(
|
|
14
|
+
input: T,
|
|
15
15
|
currentUser: { [key: string]: any; id: string },
|
|
16
|
-
options: {
|
|
17
|
-
|
|
16
|
+
options: {
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
create?: boolean;
|
|
19
|
+
clone?: boolean;
|
|
20
|
+
getNewArray?: boolean;
|
|
21
|
+
removeUndefined?: boolean;
|
|
22
|
+
} = {}
|
|
23
|
+
): Promise<T> {
|
|
18
24
|
// Configuration
|
|
19
25
|
const config = {
|
|
20
26
|
checkRoles: false,
|
|
21
27
|
clone: false,
|
|
22
28
|
create: false,
|
|
29
|
+
getNewArray: false,
|
|
23
30
|
removeUndefined: false,
|
|
24
31
|
...options,
|
|
25
32
|
};
|
|
26
33
|
|
|
34
|
+
// Check input
|
|
35
|
+
if (typeof input !== 'object') {
|
|
36
|
+
return input;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Process array
|
|
40
|
+
if (Array.isArray(input)) {
|
|
41
|
+
const processedArray = input.map(
|
|
42
|
+
async (item) => await ServiceHelper.prepareInput(item, currentUser, options)
|
|
43
|
+
) as any;
|
|
44
|
+
return config.getNewArray ? processedArray : input;
|
|
45
|
+
}
|
|
46
|
+
|
|
27
47
|
// Clone input
|
|
28
48
|
if (config.clone) {
|
|
29
|
-
if (input.mapDeep && typeof input.mapDeep === 'function') {
|
|
30
|
-
input = Object.getPrototypeOf(input).mapDeep(input);
|
|
49
|
+
if ((input as Record<string, any>).mapDeep && typeof (input as any).mapDeep === 'function') {
|
|
50
|
+
input = await Object.getPrototypeOf(input).mapDeep(input);
|
|
31
51
|
} else {
|
|
32
52
|
input = _.cloneDeep(input);
|
|
33
53
|
}
|
|
@@ -39,32 +59,36 @@ export class ServiceHelper {
|
|
|
39
59
|
}
|
|
40
60
|
|
|
41
61
|
// Process roles
|
|
42
|
-
if (
|
|
62
|
+
if (
|
|
63
|
+
config.checkRoles &&
|
|
64
|
+
(input as Record<string, any>).roles &&
|
|
65
|
+
(!currentUser?.hasRole || !currentUser.hasRole(RoleEnum.ADMIN))
|
|
66
|
+
) {
|
|
43
67
|
if (!(currentUser as any)?.roles) {
|
|
44
68
|
throw new UnauthorizedException('Missing roles of current user');
|
|
45
69
|
} else {
|
|
46
|
-
const allowedRoles = _.intersection(input.roles, (currentUser as any).roles);
|
|
47
|
-
if (allowedRoles.length !== input.roles.length) {
|
|
48
|
-
const missingRoles = _.difference(input.roles, (currentUser as any).roles);
|
|
70
|
+
const allowedRoles = _.intersection((input as Record<string, any>).roles, (currentUser as any).roles);
|
|
71
|
+
if (allowedRoles.length !== (input as Record<string, any>).roles.length) {
|
|
72
|
+
const missingRoles = _.difference((input as Record<string, any>).roles, (currentUser as any).roles);
|
|
49
73
|
throw new UnauthorizedException('Current user not allowed setting roles: ' + missingRoles);
|
|
50
74
|
}
|
|
51
|
-
input.roles = allowedRoles;
|
|
75
|
+
(input as Record<string, any>).roles = allowedRoles;
|
|
52
76
|
}
|
|
53
77
|
}
|
|
54
78
|
|
|
55
79
|
// Hash password
|
|
56
|
-
if (input.password) {
|
|
57
|
-
input.password = await bcrypt.hash((input as any).password, 10);
|
|
80
|
+
if ((input as Record<string, any>).password) {
|
|
81
|
+
(input as Record<string, any>).password = await bcrypt.hash((input as any).password, 10);
|
|
58
82
|
}
|
|
59
83
|
|
|
60
84
|
// Set creator
|
|
61
85
|
if (config.create && currentUser) {
|
|
62
|
-
input.createdBy = currentUser.id;
|
|
86
|
+
(input as Record<string, any>).createdBy = currentUser.id;
|
|
63
87
|
}
|
|
64
88
|
|
|
65
89
|
// Set updater
|
|
66
90
|
if (currentUser) {
|
|
67
|
-
input.updatedBy = currentUser.id;
|
|
91
|
+
(input as Record<string, any>).updatedBy = currentUser.id;
|
|
68
92
|
}
|
|
69
93
|
|
|
70
94
|
// Return prepared input
|
|
@@ -74,22 +98,40 @@ export class ServiceHelper {
|
|
|
74
98
|
/**
|
|
75
99
|
* Prepare output before return
|
|
76
100
|
*/
|
|
77
|
-
static async prepareOutput<T =
|
|
101
|
+
static async prepareOutput<T = { [key: string]: any; map: (...args: any[]) => any }>(
|
|
78
102
|
output: any,
|
|
79
|
-
options: {
|
|
80
|
-
|
|
103
|
+
options: {
|
|
104
|
+
[key: string]: any;
|
|
105
|
+
clone?: boolean;
|
|
106
|
+
getNewArray?: boolean;
|
|
107
|
+
removeUndefined?: boolean;
|
|
108
|
+
targetModel?: new (...args: any[]) => T;
|
|
109
|
+
} = {}
|
|
110
|
+
): Promise<T | T[] | any> {
|
|
81
111
|
// Configuration
|
|
82
112
|
const config = {
|
|
83
113
|
clone: false,
|
|
114
|
+
getNewArray: false,
|
|
84
115
|
removeUndefined: false,
|
|
85
116
|
targetModel: undefined,
|
|
86
117
|
...options,
|
|
87
118
|
};
|
|
88
119
|
|
|
120
|
+
// Check output
|
|
121
|
+
if (typeof output !== 'object') {
|
|
122
|
+
return output;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Process array
|
|
126
|
+
if (Array.isArray(output)) {
|
|
127
|
+
const processedArray = output.map(async (item) => await ServiceHelper.prepareOutput(item, options)) as any;
|
|
128
|
+
return config.getNewArray ? processedArray : output;
|
|
129
|
+
}
|
|
130
|
+
|
|
89
131
|
// Clone output
|
|
90
132
|
if (config.clone) {
|
|
91
|
-
if (output.
|
|
92
|
-
output = Object.getPrototypeOf(output).
|
|
133
|
+
if (output.mapDeep && typeof output.mapDeep === 'function') {
|
|
134
|
+
output = await Object.getPrototypeOf(output).mapDeep(output);
|
|
93
135
|
} else {
|
|
94
136
|
output = _.cloneDeep(output);
|
|
95
137
|
}
|
|
@@ -97,7 +139,7 @@ export class ServiceHelper {
|
|
|
97
139
|
|
|
98
140
|
// Map output if target model exist
|
|
99
141
|
if (config.targetModel) {
|
|
100
|
-
output = (config.targetModel as any).map(output);
|
|
142
|
+
output = await (config.targetModel as any).map(output);
|
|
101
143
|
}
|
|
102
144
|
|
|
103
145
|
// Remove password if exists
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ApolloDriverConfig } from '@nestjs/apollo';
|
|
2
2
|
import { JwtModuleOptions } from '@nestjs/jwt';
|
|
3
|
+
import { MongooseModuleOptions } from '@nestjs/mongoose/dist/interfaces/mongoose-options.interface';
|
|
3
4
|
import { ServeStaticOptions } from '@nestjs/platform-express/interfaces/serve-static-options.interface';
|
|
4
5
|
import * as SMTPTransport from 'nodemailer/lib/smtp-transport';
|
|
5
|
-
import { MongooseModuleOptions } from '@nestjs/mongoose/dist/interfaces/mongoose-options.interface';
|
|
6
6
|
import { MailjetOptions } from './mailjet-options.interface';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -20,37 +20,7 @@ export interface IServerOptions {
|
|
|
20
20
|
* see https://docs.nestjs.com/graphql/quick-start
|
|
21
21
|
* and https://www.apollographql.com/docs/apollo-server/api/apollo-server/
|
|
22
22
|
*/
|
|
23
|
-
graphQl?:
|
|
24
|
-
/**
|
|
25
|
-
* Autogenerated schema file
|
|
26
|
-
* e.g. 'schema.gql'
|
|
27
|
-
*/
|
|
28
|
-
autoSchemaFile?: string;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Function for context manipulation
|
|
32
|
-
* e.g. ({ req }) => ({ req })
|
|
33
|
-
*/
|
|
34
|
-
context?: (context: { [key: string]: any; req: any }) => { [key: string]: any; req: any };
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Enables and disables development mode helpers of apollo
|
|
38
|
-
* e.g. true
|
|
39
|
-
*/
|
|
40
|
-
debug?: boolean;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Determines whether or not to install subscription handlers
|
|
44
|
-
* e.g. true
|
|
45
|
-
*/
|
|
46
|
-
installSubscriptionHandlers?: boolean;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Enables and disables schema introspection
|
|
50
|
-
* e.g. true
|
|
51
|
-
*/
|
|
52
|
-
introspection?: boolean;
|
|
53
|
-
} & GqlModuleOptions;
|
|
23
|
+
graphQl?: ApolloDriverConfig;
|
|
54
24
|
|
|
55
25
|
/**
|
|
56
26
|
* Configuration of JavaScript Web Token (JWT) module
|
|
@@ -28,14 +28,19 @@ export abstract class CoreModel {
|
|
|
28
28
|
options: {
|
|
29
29
|
cloneDeep?: boolean;
|
|
30
30
|
funcAllowed?: boolean;
|
|
31
|
-
init?:
|
|
31
|
+
init?: any;
|
|
32
32
|
item?: T;
|
|
33
33
|
mapId?: boolean;
|
|
34
34
|
} = {}
|
|
35
35
|
): T {
|
|
36
|
+
const config = {
|
|
37
|
+
init: true,
|
|
38
|
+
...options,
|
|
39
|
+
};
|
|
40
|
+
|
|
36
41
|
const item = options.item || new this();
|
|
37
42
|
delete options.item;
|
|
38
|
-
return item.map(data,
|
|
43
|
+
return item.map(data, config);
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
/**
|
|
@@ -52,14 +57,19 @@ export abstract class CoreModel {
|
|
|
52
57
|
options: {
|
|
53
58
|
cloneDeep?: boolean;
|
|
54
59
|
funcAllowed?: boolean;
|
|
55
|
-
init?:
|
|
60
|
+
init?: any;
|
|
56
61
|
item?: T;
|
|
57
62
|
mapId?: boolean;
|
|
58
63
|
} = {}
|
|
59
64
|
): T {
|
|
65
|
+
const config = {
|
|
66
|
+
init: true,
|
|
67
|
+
...options,
|
|
68
|
+
};
|
|
69
|
+
|
|
60
70
|
const item = options.item || new this();
|
|
61
71
|
delete options.item;
|
|
62
|
-
return item.mapDeep(data,
|
|
72
|
+
return item.mapDeep(data, config);
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
/**
|
|
@@ -105,14 +115,14 @@ export abstract class CoreModel {
|
|
|
105
115
|
options: {
|
|
106
116
|
cloneDeep?: boolean;
|
|
107
117
|
funcAllowed?: boolean;
|
|
108
|
-
init?:
|
|
118
|
+
init?: any;
|
|
109
119
|
mapId?: boolean;
|
|
110
120
|
} = {}
|
|
111
121
|
): this {
|
|
112
122
|
const config = {
|
|
113
123
|
cloneDeep: true,
|
|
114
124
|
funcAllowed: false,
|
|
115
|
-
init:
|
|
125
|
+
init: undefined,
|
|
116
126
|
mapId: false,
|
|
117
127
|
...options,
|
|
118
128
|
};
|
|
@@ -87,7 +87,7 @@ export abstract class CorePersistenceModel extends CoreModel {
|
|
|
87
87
|
updatedAt: Date = undefined;
|
|
88
88
|
|
|
89
89
|
// ===========================================================================
|
|
90
|
-
//
|
|
90
|
+
// Methods
|
|
91
91
|
// ===========================================================================
|
|
92
92
|
|
|
93
93
|
/**
|
package/src/core.module.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { EmailService } from './core/common/services/email.service';
|
|
|
10
10
|
import { TemplateService } from './core/common/services/template.service';
|
|
11
11
|
import { MongooseModule } from '@nestjs/mongoose';
|
|
12
12
|
import { MailjetService } from './core/common/services/mailjet.service';
|
|
13
|
+
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Core module (dynamic)
|
|
@@ -106,7 +107,7 @@ export class CoreModule {
|
|
|
106
107
|
module: CoreModule,
|
|
107
108
|
imports: [
|
|
108
109
|
MongooseModule.forRoot(config.mongoose.uri, config.mongoose.options),
|
|
109
|
-
GraphQLModule.forRoot(config.graphQl),
|
|
110
|
+
GraphQLModule.forRoot<ApolloDriverConfig>(Object.assign({ driver: ApolloDriver }, config.graphQl)),
|
|
110
111
|
],
|
|
111
112
|
providers,
|
|
112
113
|
exports: [ConfigService, EmailService, TemplateService, MailjetService],
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Types } from 'mongoose';
|
|
1
2
|
import * as mongoose from 'mongoose';
|
|
2
3
|
import { Prop } from '@nestjs/mongoose';
|
|
3
4
|
import { Field, ObjectType } from '@nestjs/graphql';
|
|
@@ -24,7 +25,7 @@ export abstract class PersistenceModel extends CorePersistenceModel {
|
|
|
24
25
|
nullable: true,
|
|
25
26
|
})
|
|
26
27
|
@Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'User' })
|
|
27
|
-
createdBy?: User = undefined;
|
|
28
|
+
createdBy?: Types.ObjectId | User = undefined;
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* User who last updated the object
|
|
@@ -36,7 +37,7 @@ export abstract class PersistenceModel extends CorePersistenceModel {
|
|
|
36
37
|
nullable: true,
|
|
37
38
|
})
|
|
38
39
|
@Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'User' })
|
|
39
|
-
updatedBy?: User = undefined;
|
|
40
|
+
updatedBy?: Types.ObjectId | User = undefined;
|
|
40
41
|
|
|
41
42
|
// ===========================================================================
|
|
42
43
|
// Properties
|