@smartsoft001/nestjs 2.76.0 → 2.80.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/package.json +2 -2
- package/src/index.js +9 -0
- package/src/index.js.map +1 -0
- package/src/lib/auth/index.js +6 -0
- package/src/lib/auth/index.js.map +1 -0
- package/src/lib/auth/jwt.strategy.d.ts +11 -0
- package/src/lib/auth/jwt.strategy.js +30 -0
- package/src/lib/auth/jwt.strategy.js.map +1 -0
- package/src/lib/auth/permission.service.d.ts +18 -0
- package/src/lib/auth/permission.service.js +40 -0
- package/src/lib/auth/permission.service.js.map +1 -0
- package/src/lib/decorators/index.js +5 -0
- package/src/lib/decorators/index.js.map +1 -0
- package/src/lib/decorators/user/{user.decorator.ts → user.decorator.d.ts} +1 -6
- package/src/lib/decorators/user/user.decorator.js +29 -0
- package/src/lib/decorators/user/user.decorator.js.map +1 -0
- package/src/lib/filters/execution/exception.filter.d.ts +37 -0
- package/src/lib/filters/execution/exception.filter.js +87 -0
- package/src/lib/filters/execution/exception.filter.js.map +1 -0
- package/src/lib/filters/index.js +5 -0
- package/src/lib/filters/index.js.map +1 -0
- package/src/lib/shared.config.d.ts +16 -0
- package/src/lib/shared.config.js +12 -0
- package/src/lib/shared.config.js.map +1 -0
- package/src/lib/shared.module.d.ts +29 -0
- package/src/lib/shared.module.js +46 -0
- package/src/lib/shared.module.js.map +1 -0
- package/.eslintrc.json +0 -36
- package/jest.config.ts +0 -10
- package/project.json +0 -37
- package/src/lib/auth/jwt.strategy.ts +0 -24
- package/src/lib/auth/permission.service.spec.ts +0 -62
- package/src/lib/auth/permission.service.ts +0 -35
- package/src/lib/filters/execution/exception.filter.ts +0 -90
- package/src/lib/filters/execution/execution.filter.spec.ts +0 -108
- package/src/lib/shared.config.ts +0 -21
- package/src/lib/shared.module.ts +0 -55
- package/tsconfig.json +0 -22
- package/tsconfig.lib.json +0 -10
- package/tsconfig.spec.json +0 -15
- /package/src/{index.ts → index.d.ts} +0 -0
- /package/src/lib/auth/{index.ts → index.d.ts} +0 -0
- /package/src/lib/decorators/{index.ts → index.d.ts} +0 -0
- /package/src/lib/filters/{index.ts → index.d.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartsoft001/nestjs",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.80.0",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"types": "./src/index.d.ts",
|
|
@@ -13,4 +13,4 @@
|
|
|
13
13
|
"@smartsoft001/domain-core": "2.76.0",
|
|
14
14
|
"@smartsoft001/users": "2.76.0"
|
|
15
15
|
}
|
|
16
|
-
}
|
|
16
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./lib/shared.config"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./lib/shared.module"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./lib/filters"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./lib/decorators"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./lib/auth"), exports);
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/shared/nestjs/src/index.ts"],"names":[],"mappings":";;;AAAA,8DAAoC;AACpC,8DAAoC;AACpC,wDAA8B;AAC9B,2DAAiC;AACjC,qDAA2B"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./jwt.strategy"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./permission.service"), exports);
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../packages/shared/nestjs/src/lib/auth/index.ts"],"names":[],"mappings":";;;AAAA,yDAA+B;AAC/B,+DAAqC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Strategy } from 'passport-jwt';
|
|
2
|
+
import { SharedConfig } from '../shared.config';
|
|
3
|
+
declare const JwtStrategy_base: new (...args: [opt: import("passport-jwt").StrategyOptionsWithRequest] | [opt: import("passport-jwt").StrategyOptionsWithoutRequest]) => Strategy & {
|
|
4
|
+
validate(...args: any[]): unknown;
|
|
5
|
+
};
|
|
6
|
+
export declare class JwtStrategy extends JwtStrategy_base {
|
|
7
|
+
private config;
|
|
8
|
+
constructor(config: SharedConfig);
|
|
9
|
+
validate(payload: any): Promise<any>;
|
|
10
|
+
}
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JwtStrategy = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const passport_1 = require("@nestjs/passport");
|
|
7
|
+
const passport_jwt_1 = require("passport-jwt");
|
|
8
|
+
const shared_config_1 = require("../shared.config");
|
|
9
|
+
let JwtStrategy = class JwtStrategy extends (0, passport_1.PassportStrategy)(passport_jwt_1.Strategy) {
|
|
10
|
+
constructor(config) {
|
|
11
|
+
var _a;
|
|
12
|
+
super({
|
|
13
|
+
jwtFromRequest: passport_jwt_1.ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
14
|
+
ignoreExpiration: false,
|
|
15
|
+
secretOrKey: (_a = config.tokenConfig) === null || _a === void 0 ? void 0 : _a.secretOrPrivateKey,
|
|
16
|
+
});
|
|
17
|
+
this.config = config;
|
|
18
|
+
}
|
|
19
|
+
validate(payload) {
|
|
20
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
return Object.assign(Object.assign({}, payload), { permissions: payload.permissions, username: payload.sub });
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
exports.JwtStrategy = JwtStrategy;
|
|
26
|
+
exports.JwtStrategy = JwtStrategy = tslib_1.__decorate([
|
|
27
|
+
(0, common_1.Injectable)(),
|
|
28
|
+
tslib_1.__metadata("design:paramtypes", [shared_config_1.SharedConfig])
|
|
29
|
+
], JwtStrategy);
|
|
30
|
+
//# sourceMappingURL=jwt.strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.strategy.js","sourceRoot":"","sources":["../../../../../../../packages/shared/nestjs/src/lib/auth/jwt.strategy.ts"],"names":[],"mappings":";;;;AAAA,2CAA4C;AAC5C,+CAAoD;AACpD,+CAAoD;AAEpD,oDAAgD;AAGzC,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,IAAA,2BAAgB,EAAC,uBAAQ,CAAC;IACzD,YAAoB,MAAoB;;QACtC,KAAK,CAAC;YACJ,cAAc,EAAE,yBAAU,CAAC,2BAA2B,EAAE;YACxD,gBAAgB,EAAE,KAAK;YACvB,WAAW,EAAE,MAAA,MAAM,CAAC,WAAW,0CAAE,kBAA4B;SAC9D,CAAC,CAAC;QALe,WAAM,GAAN,MAAM,CAAc;IAMxC,CAAC;IAEK,QAAQ,CAAC,OAAY;;YACzB,uCACK,OAAO,KACV,WAAW,EAAE,OAAO,CAAC,WAAW,EAChC,QAAQ,EAAE,OAAO,CAAC,GAAG,IACrB;QACJ,CAAC;KAAA;CACF,CAAA;AAhBY,kCAAW;sBAAX,WAAW;IADvB,IAAA,mBAAU,GAAE;6CAEiB,4BAAY;GAD7B,WAAW,CAgBvB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { IUser } from '@smartsoft001/users';
|
|
2
|
+
import { PermissionType, SharedConfig } from '../shared.config';
|
|
3
|
+
/**
|
|
4
|
+
* Service to handle permission validation for users.
|
|
5
|
+
*
|
|
6
|
+
* @class PermissionService
|
|
7
|
+
*/
|
|
8
|
+
export declare class PermissionService {
|
|
9
|
+
private config;
|
|
10
|
+
constructor(config: SharedConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Validates if the user has the required permissions for a given type.
|
|
13
|
+
* @param {PermissionType} type - The type of permission to validate.
|
|
14
|
+
* @param {IUser} user - The user object containing permissions.
|
|
15
|
+
* @throws {DomainForbiddenError} If the user does not have the required permissions.
|
|
16
|
+
*/
|
|
17
|
+
valid(type: PermissionType, user: IUser): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PermissionService = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const domain_core_1 = require("@smartsoft001/domain-core");
|
|
7
|
+
const shared_config_1 = require("../shared.config");
|
|
8
|
+
/**
|
|
9
|
+
* Service to handle permission validation for users.
|
|
10
|
+
*
|
|
11
|
+
* @class PermissionService
|
|
12
|
+
*/
|
|
13
|
+
let PermissionService = class PermissionService {
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.config = config;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Validates if the user has the required permissions for a given type.
|
|
19
|
+
* @param {PermissionType} type - The type of permission to validate.
|
|
20
|
+
* @param {IUser} user - The user object containing permissions.
|
|
21
|
+
* @throws {DomainForbiddenError} If the user does not have the required permissions.
|
|
22
|
+
*/
|
|
23
|
+
valid(type, user) {
|
|
24
|
+
if (!this.config.permissions)
|
|
25
|
+
return;
|
|
26
|
+
const typeConfig = this.config.permissions[type];
|
|
27
|
+
if (!typeConfig)
|
|
28
|
+
return;
|
|
29
|
+
if (!user.permissions)
|
|
30
|
+
throw new domain_core_1.DomainForbiddenError(`Context forbidden`);
|
|
31
|
+
if (!typeConfig.some((tc) => user.permissions.some((up) => tc === up)))
|
|
32
|
+
throw new domain_core_1.DomainForbiddenError(`Context forbidden`);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
exports.PermissionService = PermissionService;
|
|
36
|
+
exports.PermissionService = PermissionService = tslib_1.__decorate([
|
|
37
|
+
(0, common_1.Injectable)(),
|
|
38
|
+
tslib_1.__metadata("design:paramtypes", [shared_config_1.SharedConfig])
|
|
39
|
+
], PermissionService);
|
|
40
|
+
//# sourceMappingURL=permission.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission.service.js","sourceRoot":"","sources":["../../../../../../../packages/shared/nestjs/src/lib/auth/permission.service.ts"],"names":[],"mappings":";;;;AAAA,2CAA4C;AAE5C,2DAAiE;AAGjE,oDAAgE;AAEhE;;;;GAIG;AAEI,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAC5B,YAAoB,MAAoB;QAApB,WAAM,GAAN,MAAM,CAAc;IAAG,CAAC;IAE5C;;;;;OAKG;IACH,KAAK,CAAC,IAAoB,EAAE,IAAW;QACrC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW;YAAE,OAAO;QAErC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAEjD,IAAI,CAAC,UAAU;YAAE,OAAO;QAExB,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,MAAM,IAAI,kCAAoB,CAAC,mBAAmB,CAAC,CAAC;QAE3E,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YACpE,MAAM,IAAI,kCAAoB,CAAC,mBAAmB,CAAC,CAAC;IACxD,CAAC;CACF,CAAA;AArBY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;6CAEiB,4BAAY;GAD7B,iBAAiB,CAqB7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../packages/shared/nestjs/src/lib/decorators/index.ts"],"names":[],"mappings":";;;AAAA,gEAAsC"}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Custom decorator to extract the user object from the request.
|
|
5
3
|
*
|
|
@@ -20,7 +18,4 @@ import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
|
|
20
18
|
* }
|
|
21
19
|
* ```
|
|
22
20
|
*/
|
|
23
|
-
export const User
|
|
24
|
-
const [req] = context.getArgs();
|
|
25
|
-
return req.user;
|
|
26
|
-
});
|
|
21
|
+
export declare const User: (...dataOrPipes: any[]) => ParameterDecorator;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.User = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
/**
|
|
6
|
+
* Custom decorator to extract the user object from the request.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { Controller, Get } from '@nestjs/common';
|
|
11
|
+
*
|
|
12
|
+
* import { IUser } from '@smartsoft001/users';
|
|
13
|
+
*
|
|
14
|
+
* import { User } from './user.decorator';
|
|
15
|
+
*
|
|
16
|
+
* @Controller('profile')
|
|
17
|
+
* export class ProfileController {
|
|
18
|
+
* @Get()
|
|
19
|
+
* getProfile(@User() user: IUser) {
|
|
20
|
+
* return user;
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
exports.User = (0, common_1.createParamDecorator)((_, context) => {
|
|
26
|
+
const [req] = context.getArgs();
|
|
27
|
+
return req.user;
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=user.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user.decorator.js","sourceRoot":"","sources":["../../../../../../../../packages/shared/nestjs/src/lib/decorators/user/user.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAAwE;AAExE;;;;;;;;;;;;;;;;;;;GAmBG;AACU,QAAA,IAAI,GAAG,IAAA,6BAAoB,EAAC,CAAC,CAAC,EAAE,OAAyB,EAAE,EAAE;IACxE,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAChC,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ArgumentsHost, ExceptionFilter } from '@nestjs/common';
|
|
2
|
+
/**
|
|
3
|
+
* Exception filter to handle and format exceptions thrown by the application.
|
|
4
|
+
*
|
|
5
|
+
* @class
|
|
6
|
+
* @implements {ExceptionFilter}
|
|
7
|
+
* @throws {HttpException} If the exception is an instance of HttpException.
|
|
8
|
+
* @throws {DomainValidationError} If the exception is of type DomainValidationError.
|
|
9
|
+
* @throws {DomainForbiddenError} If the exception is of type DomainForbiddenError.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { Module } from '@nestjs/common';
|
|
14
|
+
* import { APP_FILTER } from '@nestjs/core';
|
|
15
|
+
*
|
|
16
|
+
* import { AppExceptionFilter } from '@smartsoft001/nestjs';
|
|
17
|
+
*
|
|
18
|
+
* @Module({
|
|
19
|
+
* providers: [
|
|
20
|
+
* {
|
|
21
|
+
* provide: APP_FILTER,
|
|
22
|
+
* useClass: AppExceptionFilter,
|
|
23
|
+
* },
|
|
24
|
+
* ],
|
|
25
|
+
* })
|
|
26
|
+
* export class AppModule {}
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class AppExceptionFilter implements ExceptionFilter {
|
|
30
|
+
/**
|
|
31
|
+
* Method to catch and handle exceptions.
|
|
32
|
+
*
|
|
33
|
+
* @param {any} exception - The exception thrown.
|
|
34
|
+
* @param {ArgumentsHost} host - The arguments host.
|
|
35
|
+
*/
|
|
36
|
+
catch(exception: any, host: ArgumentsHost): void;
|
|
37
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var AppExceptionFilter_1;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.AppExceptionFilter = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
const domain_core_1 = require("@smartsoft001/domain-core");
|
|
8
|
+
/**
|
|
9
|
+
* Exception filter to handle and format exceptions thrown by the application.
|
|
10
|
+
*
|
|
11
|
+
* @class
|
|
12
|
+
* @implements {ExceptionFilter}
|
|
13
|
+
* @throws {HttpException} If the exception is an instance of HttpException.
|
|
14
|
+
* @throws {DomainValidationError} If the exception is of type DomainValidationError.
|
|
15
|
+
* @throws {DomainForbiddenError} If the exception is of type DomainForbiddenError.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { Module } from '@nestjs/common';
|
|
20
|
+
* import { APP_FILTER } from '@nestjs/core';
|
|
21
|
+
*
|
|
22
|
+
* import { AppExceptionFilter } from '@smartsoft001/nestjs';
|
|
23
|
+
*
|
|
24
|
+
* @Module({
|
|
25
|
+
* providers: [
|
|
26
|
+
* {
|
|
27
|
+
* provide: APP_FILTER,
|
|
28
|
+
* useClass: AppExceptionFilter,
|
|
29
|
+
* },
|
|
30
|
+
* ],
|
|
31
|
+
* })
|
|
32
|
+
* export class AppModule {}
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
let AppExceptionFilter = AppExceptionFilter_1 = class AppExceptionFilter {
|
|
36
|
+
/**
|
|
37
|
+
* Method to catch and handle exceptions.
|
|
38
|
+
*
|
|
39
|
+
* @param {any} exception - The exception thrown.
|
|
40
|
+
* @param {ArgumentsHost} host - The arguments host.
|
|
41
|
+
*/
|
|
42
|
+
catch(exception, host) {
|
|
43
|
+
const ctx = host.switchToHttp();
|
|
44
|
+
const response = ctx.getResponse();
|
|
45
|
+
let status = common_1.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
46
|
+
let message = null;
|
|
47
|
+
if (exception instanceof common_1.HttpException) {
|
|
48
|
+
status = exception.getStatus();
|
|
49
|
+
message = exception['message'];
|
|
50
|
+
}
|
|
51
|
+
else if (exception['type'] === domain_core_1.DomainValidationError) {
|
|
52
|
+
status = common_1.HttpStatus.BAD_REQUEST;
|
|
53
|
+
message = exception['message'];
|
|
54
|
+
}
|
|
55
|
+
else if (exception['type'] === domain_core_1.DomainForbiddenError) {
|
|
56
|
+
status = common_1.HttpStatus.FORBIDDEN;
|
|
57
|
+
message = exception['message'];
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
status = common_1.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
61
|
+
message = 'Internal server error';
|
|
62
|
+
}
|
|
63
|
+
common_1.Logger.error(exception['stack'] || exception['message'] || exception, AppExceptionFilter_1.name);
|
|
64
|
+
const result = response.status(status);
|
|
65
|
+
if (message && result.json) {
|
|
66
|
+
result.json({
|
|
67
|
+
details: message,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
else if (!message && result.json) {
|
|
71
|
+
result.json();
|
|
72
|
+
}
|
|
73
|
+
else if (message && !result.json) {
|
|
74
|
+
result.send({
|
|
75
|
+
details: message,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
result.send();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
exports.AppExceptionFilter = AppExceptionFilter;
|
|
84
|
+
exports.AppExceptionFilter = AppExceptionFilter = AppExceptionFilter_1 = tslib_1.__decorate([
|
|
85
|
+
(0, common_1.Catch)()
|
|
86
|
+
], AppExceptionFilter);
|
|
87
|
+
//# sourceMappingURL=exception.filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exception.filter.js","sourceRoot":"","sources":["../../../../../../../../packages/shared/nestjs/src/lib/filters/execution/exception.filter.ts"],"names":[],"mappings":";;;;;AAAA,2CAOwB;AAExB,2DAGmC;AAEnC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEI,IAAM,kBAAkB,0BAAxB,MAAM,kBAAkB;IAC7B;;;;;OAKG;IACH,KAAK,CAAC,SAAc,EAAE,IAAmB;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QAEnC,IAAI,MAAM,GAAG,mBAAU,CAAC,qBAAqB,CAAC;QAC9C,IAAI,OAAO,GAAG,IAAI,CAAC;QACnB,IAAI,SAAS,YAAY,sBAAa,EAAE,CAAC;YACvC,MAAM,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC;YAC/B,OAAO,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC;aAAM,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,mCAAqB,EAAE,CAAC;YACvD,MAAM,GAAG,mBAAU,CAAC,WAAW,CAAC;YAChC,OAAO,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC;aAAM,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,kCAAoB,EAAE,CAAC;YACtD,MAAM,GAAG,mBAAU,CAAC,SAAS,CAAC;YAC9B,OAAO,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,mBAAU,CAAC,qBAAqB,CAAC;YAC1C,OAAO,GAAG,uBAAuB,CAAC;QACpC,CAAC;QAED,eAAM,CAAC,KAAK,CACV,SAAS,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,SAAS,CAAC,IAAI,SAAS,EACvD,oBAAkB,CAAC,IAAI,CACxB,CAAC;QAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,OAAO,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC;gBACV,OAAO,EAAE,OAAO;aACjB,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,CAAC;aAAM,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC;gBACV,OAAO,EAAE,OAAO;aACjB,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;CACF,CAAA;AA/CY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,cAAK,GAAE;GACK,kBAAkB,CA+C9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../packages/shared/nestjs/src/lib/filters/index.ts"],"names":[],"mappings":";;;AAAA,uEAA6C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ISharedPermissions {
|
|
2
|
+
create: Array<string>;
|
|
3
|
+
read: Array<string>;
|
|
4
|
+
update: Array<string>;
|
|
5
|
+
delete: Array<string>;
|
|
6
|
+
[key: string]: Array<string>;
|
|
7
|
+
}
|
|
8
|
+
export declare class SharedConfig {
|
|
9
|
+
tokenConfig?: {
|
|
10
|
+
secretOrPrivateKey: string;
|
|
11
|
+
expiredIn: number;
|
|
12
|
+
};
|
|
13
|
+
permissions?: ISharedPermissions;
|
|
14
|
+
type?: any;
|
|
15
|
+
}
|
|
16
|
+
export type PermissionType = 'create' | 'read' | 'update' | 'delete' | string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SharedConfig = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
let SharedConfig = class SharedConfig {
|
|
7
|
+
};
|
|
8
|
+
exports.SharedConfig = SharedConfig;
|
|
9
|
+
exports.SharedConfig = SharedConfig = tslib_1.__decorate([
|
|
10
|
+
(0, common_1.Injectable)()
|
|
11
|
+
], SharedConfig);
|
|
12
|
+
//# sourceMappingURL=shared.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.config.js","sourceRoot":"","sources":["../../../../../../packages/shared/nestjs/src/lib/shared.config.ts"],"names":[],"mappings":";;;;AAAA,2CAA4C;AAWrC,IAAM,YAAY,GAAlB,MAAM,YAAY;CAOxB,CAAA;AAPY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;GACA,YAAY,CAOxB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { DynamicModule } from '@nestjs/common';
|
|
2
|
+
import { SharedConfig } from './shared.config';
|
|
3
|
+
/**
|
|
4
|
+
* SharedModule class provides methods to configure the module's core functionalities and database settings.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SharedModule {
|
|
7
|
+
/**
|
|
8
|
+
* Configures the module's core functionalities.
|
|
9
|
+
*
|
|
10
|
+
* @param {SharedConfig} config - An object containing the module's configuration.
|
|
11
|
+
* @returns {DynamicModule} A DynamicModule object with providers and exports.
|
|
12
|
+
*/
|
|
13
|
+
static forFeature(config: SharedConfig): DynamicModule;
|
|
14
|
+
/**
|
|
15
|
+
* Extends the forFeature() configuration by adding database settings. Use in AppModule.
|
|
16
|
+
*
|
|
17
|
+
* @param {SharedConfig & { db: { host: string; port: number; database: string; username?: string; password?: string; }}} config - An extended SharedConfig object that includes additional database settings.
|
|
18
|
+
* @returns {DynamicModule} A DynamicModule object that imports and exports the forFeature() configuration.
|
|
19
|
+
*/
|
|
20
|
+
static forRoot(config: SharedConfig & {
|
|
21
|
+
db: {
|
|
22
|
+
host: string;
|
|
23
|
+
port: number;
|
|
24
|
+
database: string;
|
|
25
|
+
username?: string;
|
|
26
|
+
password?: string;
|
|
27
|
+
};
|
|
28
|
+
}): DynamicModule;
|
|
29
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SharedModule = void 0;
|
|
4
|
+
const auth_1 = require("./auth");
|
|
5
|
+
const shared_config_1 = require("./shared.config");
|
|
6
|
+
/**
|
|
7
|
+
* SharedModule class provides methods to configure the module's core functionalities and database settings.
|
|
8
|
+
*/
|
|
9
|
+
class SharedModule {
|
|
10
|
+
/**
|
|
11
|
+
* Configures the module's core functionalities.
|
|
12
|
+
*
|
|
13
|
+
* @param {SharedConfig} config - An object containing the module's configuration.
|
|
14
|
+
* @returns {DynamicModule} A DynamicModule object with providers and exports.
|
|
15
|
+
*/
|
|
16
|
+
static forFeature(config) {
|
|
17
|
+
return {
|
|
18
|
+
module: SharedModule,
|
|
19
|
+
providers: [
|
|
20
|
+
{ provide: shared_config_1.SharedConfig, useValue: config },
|
|
21
|
+
auth_1.JwtStrategy,
|
|
22
|
+
auth_1.PermissionService,
|
|
23
|
+
],
|
|
24
|
+
exports: [
|
|
25
|
+
{ provide: shared_config_1.SharedConfig, useValue: config },
|
|
26
|
+
auth_1.PermissionService,
|
|
27
|
+
auth_1.JwtStrategy,
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Extends the forFeature() configuration by adding database settings. Use in AppModule.
|
|
33
|
+
*
|
|
34
|
+
* @param {SharedConfig & { db: { host: string; port: number; database: string; username?: string; password?: string; }}} config - An extended SharedConfig object that includes additional database settings.
|
|
35
|
+
* @returns {DynamicModule} A DynamicModule object that imports and exports the forFeature() configuration.
|
|
36
|
+
*/
|
|
37
|
+
static forRoot(config) {
|
|
38
|
+
return {
|
|
39
|
+
module: SharedModule,
|
|
40
|
+
imports: [SharedModule.forFeature(config)],
|
|
41
|
+
exports: [SharedModule.forFeature(config)],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.SharedModule = SharedModule;
|
|
46
|
+
//# sourceMappingURL=shared.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.module.js","sourceRoot":"","sources":["../../../../../../packages/shared/nestjs/src/lib/shared.module.ts"],"names":[],"mappings":";;;AAEA,iCAAwD;AACxD,mDAA+C;AAE/C;;GAEG;AACH,MAAa,YAAY;IACvB;;;;;OAKG;IACH,MAAM,CAAC,UAAU,CAAC,MAAoB;QACpC,OAAO;YACL,MAAM,EAAE,YAAY;YACpB,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,4BAAY,EAAE,QAAQ,EAAE,MAAM,EAAE;gBAC3C,kBAAW;gBACX,wBAAiB;aAClB;YACD,OAAO,EAAE;gBACP,EAAE,OAAO,EAAE,4BAAY,EAAE,QAAQ,EAAE,MAAM,EAAE;gBAC3C,wBAAiB;gBACjB,kBAAW;aACZ;SACF,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CACZ,MAQC;QAED,OAAO;YACL,MAAM,EAAE,YAAY;YACpB,OAAO,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YAC1C,OAAO,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;SAC3C,CAAC;IACJ,CAAC;CACF;AA9CD,oCA8CC"}
|
package/.eslintrc.json
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": ["../../../.eslintrc.json"],
|
|
3
|
-
"ignorePatterns": ["!**/*"],
|
|
4
|
-
"rules": {},
|
|
5
|
-
"overrides": [
|
|
6
|
-
{
|
|
7
|
-
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
|
8
|
-
"rules": {}
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"files": ["*.ts", "*.tsx"],
|
|
12
|
-
"rules": {}
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"files": ["*.js", "*.jsx"],
|
|
16
|
-
"rules": {}
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"files": ["*.json"],
|
|
20
|
-
"parser": "jsonc-eslint-parser",
|
|
21
|
-
"rules": {
|
|
22
|
-
"@nx/dependency-checks": [
|
|
23
|
-
"error",
|
|
24
|
-
{
|
|
25
|
-
"ignoredDependencies": [
|
|
26
|
-
"passport-jwt",
|
|
27
|
-
"@nestjs/passport",
|
|
28
|
-
"@nestjs/common",
|
|
29
|
-
"@nestjs/testing"
|
|
30
|
-
]
|
|
31
|
-
}
|
|
32
|
-
]
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
]
|
|
36
|
-
}
|
package/jest.config.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
displayName: 'nestjs',
|
|
3
|
-
preset: '../../../jest.preset.js',
|
|
4
|
-
testEnvironment: 'node',
|
|
5
|
-
transform: {
|
|
6
|
-
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
|
|
7
|
-
},
|
|
8
|
-
moduleFileExtensions: ['ts', 'js', 'html'],
|
|
9
|
-
coverageDirectory: '../../../coverage/packages/shared/nestjs',
|
|
10
|
-
};
|
package/project.json
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "nestjs",
|
|
3
|
-
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
-
"sourceRoot": "packages/shared/nestjs/src",
|
|
5
|
-
"projectType": "library",
|
|
6
|
-
"tags": [],
|
|
7
|
-
"targets": {
|
|
8
|
-
"build": {
|
|
9
|
-
"executor": "@nx/js:tsc",
|
|
10
|
-
"outputs": ["{options.outputPath}"],
|
|
11
|
-
"options": {
|
|
12
|
-
"outputPath": "dist/packages/shared/nestjs",
|
|
13
|
-
"main": "packages/shared/nestjs/src/index.ts",
|
|
14
|
-
"tsConfig": "packages/shared/nestjs/tsconfig.lib.json",
|
|
15
|
-
"assets": ["packages/shared/nestjs/*.md"]
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
"lint": {
|
|
19
|
-
"executor": "@nx/eslint:lint"
|
|
20
|
-
},
|
|
21
|
-
"test": {
|
|
22
|
-
"executor": "@nx/jest:jest",
|
|
23
|
-
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
|
24
|
-
"options": {
|
|
25
|
-
"jestConfig": "packages/shared/nestjs/jest.config.ts"
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
"deploy": {
|
|
29
|
-
"executor": "ngx-deploy-npm:deploy",
|
|
30
|
-
"options": {
|
|
31
|
-
"access": "public",
|
|
32
|
-
"distFolderPath": "dist/packages/shared/nestjs"
|
|
33
|
-
},
|
|
34
|
-
"dependsOn": ["build"]
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Injectable } from '@nestjs/common';
|
|
2
|
-
import { PassportStrategy } from '@nestjs/passport';
|
|
3
|
-
import { ExtractJwt, Strategy } from 'passport-jwt';
|
|
4
|
-
|
|
5
|
-
import { SharedConfig } from '../shared.config';
|
|
6
|
-
|
|
7
|
-
@Injectable()
|
|
8
|
-
export class JwtStrategy extends PassportStrategy(Strategy) {
|
|
9
|
-
constructor(private config: SharedConfig) {
|
|
10
|
-
super({
|
|
11
|
-
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
12
|
-
ignoreExpiration: false,
|
|
13
|
-
secretOrKey: config.tokenConfig?.secretOrPrivateKey as string,
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async validate(payload: any) {
|
|
18
|
-
return {
|
|
19
|
-
...payload,
|
|
20
|
-
permissions: payload.permissions,
|
|
21
|
-
username: payload.sub,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { Test, TestingModule } from '@nestjs/testing';
|
|
2
|
-
|
|
3
|
-
import { DomainForbiddenError } from '@smartsoft001/domain-core';
|
|
4
|
-
import { IUser } from '@smartsoft001/users';
|
|
5
|
-
|
|
6
|
-
import { PermissionService } from './permission.service';
|
|
7
|
-
import { SharedConfig } from '../shared.config';
|
|
8
|
-
|
|
9
|
-
describe('shared-nestjs: PermissionService', () => {
|
|
10
|
-
let service: PermissionService;
|
|
11
|
-
let config: SharedConfig;
|
|
12
|
-
|
|
13
|
-
beforeEach(async () => {
|
|
14
|
-
config = {
|
|
15
|
-
permissions: {
|
|
16
|
-
create: ['admin', 'editor'],
|
|
17
|
-
read: ['admin', 'editor', 'viewer'],
|
|
18
|
-
update: ['admin', 'editor'],
|
|
19
|
-
delete: ['admin'],
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const module: TestingModule = await Test.createTestingModule({
|
|
24
|
-
providers: [
|
|
25
|
-
PermissionService,
|
|
26
|
-
{ provide: SharedConfig, useValue: config },
|
|
27
|
-
],
|
|
28
|
-
}).compile();
|
|
29
|
-
|
|
30
|
-
service = module.get<PermissionService>(PermissionService);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should be defined', () => {
|
|
34
|
-
expect(service).toBeDefined();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should allow access if user has the required permission', () => {
|
|
38
|
-
const user: IUser = { username: 'testuser', permissions: ['admin'] };
|
|
39
|
-
expect(() => service.valid('create', user)).not.toThrow();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should throw DomainForbiddenError if user does not have the required permission', () => {
|
|
43
|
-
const user: IUser = { username: 'testuser', permissions: ['viewer'] };
|
|
44
|
-
expect(() => service.valid('create', user)).toThrow(DomainForbiddenError);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should not throw if permissions config is not defined', () => {
|
|
48
|
-
config.permissions = undefined;
|
|
49
|
-
const user: IUser = { username: 'testuser', permissions: ['admin'] };
|
|
50
|
-
expect(() => service.valid('create', user)).not.toThrow();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('should not throw if permission type config is not defined', () => {
|
|
54
|
-
const user: IUser = { username: 'testuser', permissions: ['admin'] };
|
|
55
|
-
expect(() => service.valid('nonexistent', user)).not.toThrow();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should throw DomainForbiddenError if user permissions are not defined', () => {
|
|
59
|
-
const user: IUser = { username: 'testuser', permissions: [] };
|
|
60
|
-
expect(() => service.valid('create', user)).toThrow(DomainForbiddenError);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { Injectable } from '@nestjs/common';
|
|
2
|
-
|
|
3
|
-
import { DomainForbiddenError } from '@smartsoft001/domain-core';
|
|
4
|
-
import { IUser } from '@smartsoft001/users';
|
|
5
|
-
|
|
6
|
-
import { PermissionType, SharedConfig } from '../shared.config';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Service to handle permission validation for users.
|
|
10
|
-
*
|
|
11
|
-
* @class PermissionService
|
|
12
|
-
*/
|
|
13
|
-
@Injectable()
|
|
14
|
-
export class PermissionService {
|
|
15
|
-
constructor(private config: SharedConfig) {}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Validates if the user has the required permissions for a given type.
|
|
19
|
-
* @param {PermissionType} type - The type of permission to validate.
|
|
20
|
-
* @param {IUser} user - The user object containing permissions.
|
|
21
|
-
* @throws {DomainForbiddenError} If the user does not have the required permissions.
|
|
22
|
-
*/
|
|
23
|
-
valid(type: PermissionType, user: IUser): void {
|
|
24
|
-
if (!this.config.permissions) return;
|
|
25
|
-
|
|
26
|
-
const typeConfig = this.config.permissions[type];
|
|
27
|
-
|
|
28
|
-
if (!typeConfig) return;
|
|
29
|
-
|
|
30
|
-
if (!user.permissions) throw new DomainForbiddenError(`Context forbidden`);
|
|
31
|
-
|
|
32
|
-
if (!typeConfig.some((tc) => user.permissions.some((up) => tc === up)))
|
|
33
|
-
throw new DomainForbiddenError(`Context forbidden`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ArgumentsHost,
|
|
3
|
-
Catch,
|
|
4
|
-
ExceptionFilter,
|
|
5
|
-
HttpException,
|
|
6
|
-
HttpStatus,
|
|
7
|
-
Logger,
|
|
8
|
-
} from '@nestjs/common';
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
DomainForbiddenError,
|
|
12
|
-
DomainValidationError,
|
|
13
|
-
} from '@smartsoft001/domain-core';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Exception filter to handle and format exceptions thrown by the application.
|
|
17
|
-
*
|
|
18
|
-
* @class
|
|
19
|
-
* @implements {ExceptionFilter}
|
|
20
|
-
* @throws {HttpException} If the exception is an instance of HttpException.
|
|
21
|
-
* @throws {DomainValidationError} If the exception is of type DomainValidationError.
|
|
22
|
-
* @throws {DomainForbiddenError} If the exception is of type DomainForbiddenError.
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```ts
|
|
26
|
-
* import { Module } from '@nestjs/common';
|
|
27
|
-
* import { APP_FILTER } from '@nestjs/core';
|
|
28
|
-
*
|
|
29
|
-
* import { AppExceptionFilter } from '@smartsoft001/nestjs';
|
|
30
|
-
*
|
|
31
|
-
* @Module({
|
|
32
|
-
* providers: [
|
|
33
|
-
* {
|
|
34
|
-
* provide: APP_FILTER,
|
|
35
|
-
* useClass: AppExceptionFilter,
|
|
36
|
-
* },
|
|
37
|
-
* ],
|
|
38
|
-
* })
|
|
39
|
-
* export class AppModule {}
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
@Catch()
|
|
43
|
-
export class AppExceptionFilter implements ExceptionFilter {
|
|
44
|
-
/**
|
|
45
|
-
* Method to catch and handle exceptions.
|
|
46
|
-
*
|
|
47
|
-
* @param {any} exception - The exception thrown.
|
|
48
|
-
* @param {ArgumentsHost} host - The arguments host.
|
|
49
|
-
*/
|
|
50
|
-
catch(exception: any, host: ArgumentsHost) {
|
|
51
|
-
const ctx = host.switchToHttp();
|
|
52
|
-
const response = ctx.getResponse();
|
|
53
|
-
|
|
54
|
-
let status = HttpStatus.INTERNAL_SERVER_ERROR;
|
|
55
|
-
let message = null;
|
|
56
|
-
if (exception instanceof HttpException) {
|
|
57
|
-
status = exception.getStatus();
|
|
58
|
-
message = exception['message'];
|
|
59
|
-
} else if (exception['type'] === DomainValidationError) {
|
|
60
|
-
status = HttpStatus.BAD_REQUEST;
|
|
61
|
-
message = exception['message'];
|
|
62
|
-
} else if (exception['type'] === DomainForbiddenError) {
|
|
63
|
-
status = HttpStatus.FORBIDDEN;
|
|
64
|
-
message = exception['message'];
|
|
65
|
-
} else {
|
|
66
|
-
status = HttpStatus.INTERNAL_SERVER_ERROR;
|
|
67
|
-
message = 'Internal server error';
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
Logger.error(
|
|
71
|
-
exception['stack'] || exception['message'] || exception,
|
|
72
|
-
AppExceptionFilter.name,
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
const result = response.status(status);
|
|
76
|
-
if (message && result.json) {
|
|
77
|
-
result.json({
|
|
78
|
-
details: message,
|
|
79
|
-
});
|
|
80
|
-
} else if (!message && result.json) {
|
|
81
|
-
result.json();
|
|
82
|
-
} else if (message && !result.json) {
|
|
83
|
-
result.send({
|
|
84
|
-
details: message,
|
|
85
|
-
});
|
|
86
|
-
} else {
|
|
87
|
-
result.send();
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
|
|
2
|
-
import { Test, TestingModule } from '@nestjs/testing';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
DomainForbiddenError,
|
|
6
|
-
DomainValidationError,
|
|
7
|
-
} from '@smartsoft001/domain-core';
|
|
8
|
-
|
|
9
|
-
import { AppExceptionFilter } from './exception.filter';
|
|
10
|
-
|
|
11
|
-
describe('shared-nestjs: ExceptionFilter', () => {
|
|
12
|
-
let appExceptionFilter: AppExceptionFilter;
|
|
13
|
-
|
|
14
|
-
beforeEach(async () => {
|
|
15
|
-
const module: TestingModule = await Test.createTestingModule({
|
|
16
|
-
providers: [AppExceptionFilter],
|
|
17
|
-
}).compile();
|
|
18
|
-
|
|
19
|
-
appExceptionFilter = module.get<AppExceptionFilter>(AppExceptionFilter);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('should handle HttpException', () => {
|
|
23
|
-
const mockResponse = {
|
|
24
|
-
status: jest.fn().mockReturnThis(),
|
|
25
|
-
json: jest.fn(),
|
|
26
|
-
send: jest.fn(),
|
|
27
|
-
};
|
|
28
|
-
const mockHost = {
|
|
29
|
-
switchToHttp: jest.fn().mockReturnValue({
|
|
30
|
-
getResponse: () => mockResponse,
|
|
31
|
-
}),
|
|
32
|
-
} as unknown as ArgumentsHost;
|
|
33
|
-
const exception = new HttpException('Forbidden', HttpStatus.FORBIDDEN);
|
|
34
|
-
|
|
35
|
-
appExceptionFilter.catch(exception, mockHost);
|
|
36
|
-
|
|
37
|
-
expect(mockResponse.status).toHaveBeenCalledWith(HttpStatus.FORBIDDEN);
|
|
38
|
-
expect(mockResponse.json).toHaveBeenCalledWith({ details: 'Forbidden' });
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should handle DomainValidationError', () => {
|
|
42
|
-
const mockResponse = {
|
|
43
|
-
status: jest.fn().mockReturnThis(),
|
|
44
|
-
json: jest.fn(),
|
|
45
|
-
send: jest.fn(),
|
|
46
|
-
};
|
|
47
|
-
const mockHost = {
|
|
48
|
-
switchToHttp: jest.fn().mockReturnValue({
|
|
49
|
-
getResponse: () => mockResponse,
|
|
50
|
-
}),
|
|
51
|
-
} as unknown as ArgumentsHost;
|
|
52
|
-
const exception = {
|
|
53
|
-
type: DomainValidationError,
|
|
54
|
-
message: 'Validation failed',
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
appExceptionFilter.catch(exception, mockHost);
|
|
58
|
-
|
|
59
|
-
expect(mockResponse.status).toHaveBeenCalledWith(HttpStatus.BAD_REQUEST);
|
|
60
|
-
expect(mockResponse.json).toHaveBeenCalledWith({
|
|
61
|
-
details: 'Validation failed',
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should handle DomainForbiddenError', () => {
|
|
66
|
-
const mockResponse = {
|
|
67
|
-
status: jest.fn().mockReturnThis(),
|
|
68
|
-
json: jest.fn(),
|
|
69
|
-
send: jest.fn(),
|
|
70
|
-
};
|
|
71
|
-
const mockHost = {
|
|
72
|
-
switchToHttp: jest.fn().mockReturnValue({
|
|
73
|
-
getResponse: () => mockResponse,
|
|
74
|
-
}),
|
|
75
|
-
} as unknown as ArgumentsHost;
|
|
76
|
-
const exception = { type: DomainForbiddenError, message: 'Access denied' };
|
|
77
|
-
|
|
78
|
-
appExceptionFilter.catch(exception, mockHost);
|
|
79
|
-
|
|
80
|
-
expect(mockResponse.status).toHaveBeenCalledWith(HttpStatus.FORBIDDEN);
|
|
81
|
-
expect(mockResponse.json).toHaveBeenCalledWith({
|
|
82
|
-
details: 'Access denied',
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('should handle internal server error', () => {
|
|
87
|
-
const mockResponse = {
|
|
88
|
-
status: jest.fn().mockReturnThis(),
|
|
89
|
-
json: jest.fn(),
|
|
90
|
-
send: jest.fn(),
|
|
91
|
-
};
|
|
92
|
-
const mockHost = {
|
|
93
|
-
switchToHttp: jest.fn().mockReturnValue({
|
|
94
|
-
getResponse: () => mockResponse,
|
|
95
|
-
}),
|
|
96
|
-
} as unknown as ArgumentsHost;
|
|
97
|
-
const exception = { message: 'Internal server error' };
|
|
98
|
-
|
|
99
|
-
appExceptionFilter.catch(exception, mockHost);
|
|
100
|
-
|
|
101
|
-
expect(mockResponse.status).toHaveBeenCalledWith(
|
|
102
|
-
HttpStatus.INTERNAL_SERVER_ERROR,
|
|
103
|
-
);
|
|
104
|
-
expect(mockResponse.json).toHaveBeenCalledWith({
|
|
105
|
-
details: 'Internal server error',
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
});
|
package/src/lib/shared.config.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Injectable } from '@nestjs/common';
|
|
2
|
-
|
|
3
|
-
export interface ISharedPermissions {
|
|
4
|
-
create: Array<string>;
|
|
5
|
-
read: Array<string>;
|
|
6
|
-
update: Array<string>;
|
|
7
|
-
delete: Array<string>;
|
|
8
|
-
[key: string]: Array<string>;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
@Injectable()
|
|
12
|
-
export class SharedConfig {
|
|
13
|
-
tokenConfig?: {
|
|
14
|
-
secretOrPrivateKey: string;
|
|
15
|
-
expiredIn: number;
|
|
16
|
-
};
|
|
17
|
-
permissions?: ISharedPermissions;
|
|
18
|
-
type?: any;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type PermissionType = 'create' | 'read' | 'update' | 'delete' | string;
|
package/src/lib/shared.module.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { DynamicModule } from '@nestjs/common';
|
|
2
|
-
|
|
3
|
-
import { JwtStrategy, PermissionService } from './auth';
|
|
4
|
-
import { SharedConfig } from './shared.config';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* SharedModule class provides methods to configure the module's core functionalities and database settings.
|
|
8
|
-
*/
|
|
9
|
-
export class SharedModule {
|
|
10
|
-
/**
|
|
11
|
-
* Configures the module's core functionalities.
|
|
12
|
-
*
|
|
13
|
-
* @param {SharedConfig} config - An object containing the module's configuration.
|
|
14
|
-
* @returns {DynamicModule} A DynamicModule object with providers and exports.
|
|
15
|
-
*/
|
|
16
|
-
static forFeature(config: SharedConfig): DynamicModule {
|
|
17
|
-
return {
|
|
18
|
-
module: SharedModule,
|
|
19
|
-
providers: [
|
|
20
|
-
{ provide: SharedConfig, useValue: config },
|
|
21
|
-
JwtStrategy,
|
|
22
|
-
PermissionService,
|
|
23
|
-
],
|
|
24
|
-
exports: [
|
|
25
|
-
{ provide: SharedConfig, useValue: config },
|
|
26
|
-
PermissionService,
|
|
27
|
-
JwtStrategy,
|
|
28
|
-
],
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Extends the forFeature() configuration by adding database settings. Use in AppModule.
|
|
34
|
-
*
|
|
35
|
-
* @param {SharedConfig & { db: { host: string; port: number; database: string; username?: string; password?: string; }}} config - An extended SharedConfig object that includes additional database settings.
|
|
36
|
-
* @returns {DynamicModule} A DynamicModule object that imports and exports the forFeature() configuration.
|
|
37
|
-
*/
|
|
38
|
-
static forRoot(
|
|
39
|
-
config: SharedConfig & {
|
|
40
|
-
db: {
|
|
41
|
-
host: string;
|
|
42
|
-
port: number;
|
|
43
|
-
database: string;
|
|
44
|
-
username?: string;
|
|
45
|
-
password?: string;
|
|
46
|
-
};
|
|
47
|
-
},
|
|
48
|
-
): DynamicModule {
|
|
49
|
-
return {
|
|
50
|
-
module: SharedModule,
|
|
51
|
-
imports: [SharedModule.forFeature(config)],
|
|
52
|
-
exports: [SharedModule.forFeature(config)],
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../../tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"forceConsistentCasingInFileNames": true,
|
|
6
|
-
"strict": true,
|
|
7
|
-
"noImplicitOverride": true,
|
|
8
|
-
"noImplicitReturns": true,
|
|
9
|
-
"noFallthroughCasesInSwitch": true,
|
|
10
|
-
"noPropertyAccessFromIndexSignature": true
|
|
11
|
-
},
|
|
12
|
-
"files": [],
|
|
13
|
-
"include": [],
|
|
14
|
-
"references": [
|
|
15
|
-
{
|
|
16
|
-
"path": "./tsconfig.lib.json"
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"path": "./tsconfig.spec.json"
|
|
20
|
-
}
|
|
21
|
-
]
|
|
22
|
-
}
|
package/tsconfig.lib.json
DELETED
package/tsconfig.spec.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "../../../dist/out-tsc",
|
|
5
|
-
"module": "commonjs",
|
|
6
|
-
"moduleResolution": "node10",
|
|
7
|
-
"types": ["jest", "node"]
|
|
8
|
-
},
|
|
9
|
-
"include": [
|
|
10
|
-
"jest.config.ts",
|
|
11
|
-
"src/**/*.test.ts",
|
|
12
|
-
"src/**/*.spec.ts",
|
|
13
|
-
"src/**/*.d.ts"
|
|
14
|
-
]
|
|
15
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|