@nest-yalc-2/errors 1.3.4

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 (64) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +37 -0
  3. package/package.json +42 -0
  4. package/src/__tests__/database-exception.filter.spec.ts +71 -0
  5. package/src/__tests__/default.error.spec.ts +529 -0
  6. package/src/__tests__/error.helper.spec.ts +23 -0
  7. package/src/__tests__/errors.enum.spec.ts +32 -0
  8. package/src/__tests__/http-exception.filter.spec.ts +129 -0
  9. package/src/__tests__/http-status-code-to-errors.spec.ts +26 -0
  10. package/src/__tests__/input-validation.error.spec.ts +27 -0
  11. package/src/__tests__/login.error.spec.ts +23 -0
  12. package/src/__tests__/result.error.spec.ts +47 -0
  13. package/src/__tests__/system-exception.filter.spec.ts +39 -0
  14. package/src/__tests__/tsconfig.json +3 -0
  15. package/src/__tests__/validation-exception.filter.spec.ts +31 -0
  16. package/src/__tests__/verification.error.spec.ts +28 -0
  17. package/src/default.error.d.ts +93 -0
  18. package/src/default.error.js +266 -0
  19. package/src/default.error.js.map +1 -0
  20. package/src/default.error.ts +640 -0
  21. package/src/error.class.d.ts +103 -0
  22. package/src/error.class.js +170 -0
  23. package/src/error.class.js.map +1 -0
  24. package/src/error.class.ts +319 -0
  25. package/src/error.enum.d.ts +29 -0
  26. package/src/error.enum.js +41 -0
  27. package/src/error.enum.js.map +1 -0
  28. package/src/error.enum.ts +45 -0
  29. package/src/error.helper.d.ts +2 -0
  30. package/src/error.helper.js +20 -0
  31. package/src/error.helper.js.map +1 -0
  32. package/src/error.helper.ts +34 -0
  33. package/src/filters/database-exception.filter.d.ts +7 -0
  34. package/src/filters/database-exception.filter.js +74 -0
  35. package/src/filters/database-exception.filter.js.map +1 -0
  36. package/src/filters/database-exception.filter.ts +43 -0
  37. package/src/filters/http-exception.filter.d.ts +16 -0
  38. package/src/filters/http-exception.filter.js +145 -0
  39. package/src/filters/http-exception.filter.js.map +1 -0
  40. package/src/filters/http-exception.filter.ts +143 -0
  41. package/src/filters/index.d.ts +1 -0
  42. package/src/filters/index.js +6 -0
  43. package/src/filters/index.js.map +1 -0
  44. package/src/filters/index.ts +6 -0
  45. package/src/filters/system-exception.filter.d.ts +7 -0
  46. package/src/filters/system-exception.filter.js +29 -0
  47. package/src/filters/system-exception.filter.js.map +1 -0
  48. package/src/filters/system-exception.filter.ts +13 -0
  49. package/src/filters/validation-exception.filter.d.ts +8 -0
  50. package/src/filters/validation-exception.filter.js +66 -0
  51. package/src/filters/validation-exception.filter.js.map +1 -0
  52. package/src/filters/validation-exception.filter.ts +24 -0
  53. package/src/http-status-code-to-errors.d.ts +4 -0
  54. package/src/http-status-code-to-errors.js +24 -0
  55. package/src/http-status-code-to-errors.js.map +1 -0
  56. package/src/http-status-code-to-errors.ts +41 -0
  57. package/src/index.d.ts +5 -0
  58. package/src/index.js +24 -0
  59. package/src/index.js.map +1 -0
  60. package/src/index.ts +7 -0
  61. package/src/result.error.d.ts +4 -0
  62. package/src/result.error.js +24 -0
  63. package/src/result.error.js.map +1 -0
  64. package/src/result.error.ts +25 -0
@@ -0,0 +1,32 @@
1
+ import {
2
+ expect,
3
+ jest,
4
+ describe,
5
+ it,
6
+ beforeEach,
7
+ beforeAll,
8
+ afterAll,
9
+ afterEach,
10
+ } from '@jest/globals';
11
+ import { ErrorsEnum, ExceptionContextEnum } from '../error.enum.js';
12
+
13
+ describe('errors enum test', () => {
14
+ it('ErrorsEnum should have all the values', () => {
15
+ expect(Object.keys(ErrorsEnum)).toEqual(
16
+ expect.arrayContaining([
17
+ 'BAD_LOGIN',
18
+ 'UNAUTHORIZED',
19
+ 'FORBIDDEN_RESOURCE',
20
+ 'INVALID_VALUE',
21
+ ]),
22
+ );
23
+ });
24
+
25
+ it('ExceptionContextEnum have all the values', () => {
26
+ expect(Object.keys(ExceptionContextEnum)).toEqual([
27
+ 'DATABASE',
28
+ 'HTTP',
29
+ 'SYSTEM',
30
+ ]);
31
+ });
32
+ });
@@ -0,0 +1,129 @@
1
+ import { expect, jest, describe, it, beforeEach } from '@jest/globals';
2
+
3
+ import { DeepMocked, createMock } from '@golevelup/ts-jest';
4
+ import { CreateEntityError } from '@nest-yalc-2/crud-gen/entity.error.js';
5
+ import { MissingArgumentsError } from '@nest-yalc-2/crud-gen/missing-arguments.error.js';
6
+ import {
7
+ ArgumentsHost,
8
+ BadRequestException,
9
+ InternalServerErrorException,
10
+ LoggerService,
11
+ } from '@nestjs/common';
12
+ import { HttpExceptionFilter } from '../filters/http-exception.filter.js';
13
+ import { GqlError } from '@nest-yalc-2/graphql/plugins/gql.error.js';
14
+ import { DefaultError } from '../index.js';
15
+ import { GqlArgumentsHost } from '@nestjs/graphql';
16
+ describe('Http exceptions filter', () => {
17
+ let filter: HttpExceptionFilter;
18
+ let loggerServiceMock: DeepMocked<LoggerService>;
19
+ let mockArgumentsHost: DeepMocked<ArgumentsHost>;
20
+
21
+ beforeEach(() => {
22
+ jest.resetAllMocks();
23
+ loggerServiceMock = createMock<LoggerService>();
24
+ mockArgumentsHost = createMock<ArgumentsHost>();
25
+ filter = new HttpExceptionFilter(loggerServiceMock);
26
+ });
27
+
28
+ afterEach(() => {
29
+ jest.restoreAllMocks();
30
+ });
31
+
32
+ it('should be defined', () => {
33
+ expect(filter).toBeDefined();
34
+ });
35
+
36
+ it('should catch and log Application errors', () => {
37
+ const error = new MissingArgumentsError();
38
+
39
+ filter.catch(error, mockArgumentsHost);
40
+ expect(loggerServiceMock.log).toHaveBeenCalledWith(
41
+ error.message,
42
+ expect.anything(),
43
+ );
44
+ });
45
+
46
+ it('should catch Default error', () => {
47
+ const exception = new DefaultError('test');
48
+
49
+ filter.catch(exception, mockArgumentsHost);
50
+ });
51
+
52
+ it('should catch and log System Error error', () => {
53
+ const exception = new Error('test');
54
+
55
+ filter.catch(exception, mockArgumentsHost);
56
+ expect(loggerServiceMock.error).toHaveBeenCalledWith(
57
+ exception.message,
58
+ exception.stack,
59
+ expect.anything(),
60
+ );
61
+ });
62
+
63
+ it('should catch and log Entity error', () => {
64
+ const exception = new CreateEntityError();
65
+
66
+ filter.catch(exception, mockArgumentsHost);
67
+ expect(loggerServiceMock.error).toHaveBeenCalledWith(
68
+ exception,
69
+ undefined,
70
+ expect.anything(),
71
+ );
72
+ });
73
+
74
+ it('should catch EntityError and log the original message', () => {
75
+ const fixedError = new Error('message');
76
+ const exception = new CreateEntityError(fixedError);
77
+
78
+ filter.catch(exception, mockArgumentsHost);
79
+ expect(loggerServiceMock.error).toHaveBeenCalledWith(
80
+ fixedError.message,
81
+ expect.anything(),
82
+ expect.objectContaining({
83
+ data: expect.objectContaining({
84
+ name: 'CreateEntityError',
85
+ }),
86
+ }),
87
+ );
88
+ });
89
+
90
+ it('should catch and log GqlError error', () => {
91
+ const exception: GqlError = new GqlError('message', 'systemMessage');
92
+ filter.catch(exception, mockArgumentsHost);
93
+ expect(loggerServiceMock.error).toHaveBeenCalledWith(exception.systemMessage);
94
+
95
+ exception.systemMessage = undefined;
96
+ filter.catch(exception, mockArgumentsHost);
97
+ expect(loggerServiceMock.error).toHaveBeenCalledWith(exception.message);
98
+ });
99
+
100
+ it('should catch and log Http error with host type http', () => {
101
+ const exception = new InternalServerErrorException();
102
+ mockArgumentsHost.getType.mockReturnValue('http');
103
+ filter.catch(exception, mockArgumentsHost as ArgumentsHost);
104
+ expect(loggerServiceMock.error).toHaveBeenCalledWith(
105
+ exception.message,
106
+ exception.stack,
107
+ expect.anything(),
108
+ );
109
+ });
110
+
111
+ it('should catch and log Http log with host type http', () => {
112
+ const exception = new BadRequestException();
113
+ mockArgumentsHost.getType.mockReturnValue('http');
114
+ filter.catch(exception, mockArgumentsHost as ArgumentsHost);
115
+ expect(loggerServiceMock.log).toHaveBeenCalledWith(
116
+ exception.message,
117
+ expect.anything(),
118
+ );
119
+ });
120
+
121
+ it('should catch an error with the logger itself', () => {
122
+ const exception = new InternalServerErrorException();
123
+ loggerServiceMock.error = null;
124
+ mockArgumentsHost.getType.mockReturnValue('http');
125
+ console.error = jest.fn();
126
+ filter.catch(exception, mockArgumentsHost as ArgumentsHost);
127
+ expect(console.error).toHaveBeenCalled();
128
+ });
129
+ });
@@ -0,0 +1,26 @@
1
+ import { HttpStatusCodes } from '@nest-yalc-2/utils/http.helper.js';
2
+ import { httpStatusCodeToErrors } from '../http-status-code-to-errors.js';
3
+ import {
4
+ BadRequestError,
5
+ GatewayTimeoutError,
6
+ NotFoundError,
7
+ } from '../error.class.js';
8
+ import { describe, expect, it } from '@jest/globals';
9
+
10
+ describe('should test ', () => {
11
+ it('should return not found error when given code 404', () => {
12
+ const httpCode: HttpStatusCodes = 404;
13
+ const result = httpStatusCodeToErrors[httpCode];
14
+ expect(result).toBe(NotFoundError);
15
+ });
16
+ it('should return bad request error when given code 400', () => {
17
+ const httpCode: HttpStatusCodes = 400;
18
+ const result = httpStatusCodeToErrors[httpCode];
19
+ expect(result).toBe(BadRequestError);
20
+ });
21
+ it('should return gateway timeout error when given code 504', () => {
22
+ const httpCode: HttpStatusCodes = 504;
23
+ const result = httpStatusCodeToErrors[httpCode];
24
+ expect(result).toBe(GatewayTimeoutError);
25
+ });
26
+ });
@@ -0,0 +1,27 @@
1
+ import {
2
+ expect,
3
+ jest,
4
+ describe,
5
+ it,
6
+ beforeEach,
7
+ beforeAll,
8
+ afterAll,
9
+ afterEach,
10
+ } from '@jest/globals';
11
+ import { BadRequestError, InputValidationError } from '../error.class.js';
12
+ import { ErrorsEnum } from '../error.enum.js';
13
+
14
+ describe('InputValidationError', () => {
15
+ it('should have internal message without the custom message', () => {
16
+ const customError = new InputValidationError();
17
+ expect(customError.internalMessage).toEqual('Invalid value');
18
+ });
19
+
20
+ it('should set the custom message', () => {
21
+ const customMessage = 'INVALID_INPUT_MESSAGE';
22
+ const customError = new BadRequestError(customMessage);
23
+ expect(customError.internalMessage).toEqual(
24
+ `${ErrorsEnum.BAD_REQUEST}: ${customMessage}`,
25
+ );
26
+ });
27
+ });
@@ -0,0 +1,23 @@
1
+ import { expect, describe, it } from '@jest/globals';
2
+ import { ErrorsEnum } from '../error.enum.js';
3
+ import { LoginError } from '../index.js';
4
+
5
+ describe('Login error', () => {
6
+ const error = new LoginError();
7
+
8
+ it('should be defined', () => {
9
+ expect(error).toBeDefined();
10
+ });
11
+
12
+ it('should have the correct message', () => {
13
+ expect(error.getInternalMessage()).toEqual(ErrorsEnum.BAD_LOGIN);
14
+ });
15
+
16
+ it('should set the custom message', () => {
17
+ const customMessage = 'Something catastrophic happened!';
18
+ const customError = new LoginError(customMessage);
19
+ expect(customError.getInternalMessage()).toEqual(
20
+ `${ErrorsEnum.BAD_LOGIN}: ${customMessage}`,
21
+ );
22
+ });
23
+ });
@@ -0,0 +1,47 @@
1
+ import { describe, expect, it } from '@jest/globals';
2
+ import { tryCatch, tryCatchAsync } from '../result.error.js';
3
+ import { DefaultError } from '../default.error.js';
4
+
5
+ describe('ResultError', () => {
6
+ it('should handle sync success', () => {
7
+ const result = tryCatch(() => 'success');
8
+ if (result.isErr()) {
9
+ expect(true).toBe(false);
10
+ return;
11
+ }
12
+ expect(result.isOk()).toBe(true);
13
+ expect(result.value).toBe('success');
14
+ });
15
+
16
+ it('should handle sync error', () => {
17
+ const result = tryCatch(() => {
18
+ throw new Error('error');
19
+ });
20
+ if (result.isOk()) {
21
+ expect(true).toBe(false);
22
+ return;
23
+ }
24
+ expect(result.error).toBeInstanceOf(DefaultError);
25
+ });
26
+
27
+ it('should handle async success', async () => {
28
+ const result = await tryCatchAsync(async () => 'success');
29
+ if (result.isErr()) {
30
+ expect(true).toBe(false);
31
+ return;
32
+ }
33
+ expect(result.isOk()).toBe(true);
34
+ expect(result.value).toBe('success');
35
+ });
36
+
37
+ it('should handle async error', async () => {
38
+ const result = await tryCatchAsync(async () => {
39
+ throw new Error('error');
40
+ });
41
+ if (result.isOk()) {
42
+ expect(true).toBe(false);
43
+ return;
44
+ }
45
+ expect(result.error).toBeInstanceOf(DefaultError);
46
+ });
47
+ });
@@ -0,0 +1,39 @@
1
+ import {
2
+ expect,
3
+ jest,
4
+ describe,
5
+ it,
6
+ beforeEach,
7
+ beforeAll,
8
+ afterAll,
9
+ afterEach,
10
+ } from '@jest/globals';
11
+ import { createMock } from '@golevelup/ts-jest';
12
+ import { LoggerService, UnprocessableEntityException } from '@nestjs/common';
13
+
14
+ import { ExceptionContextEnum } from '../error.enum.js';
15
+ import { SystemExceptionFilter } from '../filters/system-exception.filter.js';
16
+
17
+ describe('System exceptions filter', () => {
18
+ let filter: SystemExceptionFilter;
19
+ const loggerServiceMock = createMock<LoggerService>();
20
+
21
+ beforeAll(() => {
22
+ filter = new SystemExceptionFilter(loggerServiceMock);
23
+ });
24
+
25
+ it('should be defined', () => {
26
+ expect(filter).toBeDefined();
27
+ });
28
+
29
+ it('should catch and log UnprocessableEntity error', () => {
30
+ const exception = new UnprocessableEntityException();
31
+
32
+ filter.catch(exception);
33
+ expect(loggerServiceMock.error).toHaveBeenCalledWith(
34
+ exception,
35
+ exception.stack,
36
+ ExceptionContextEnum.SYSTEM,
37
+ );
38
+ });
39
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../../tsconfig.test.json"
3
+ }
@@ -0,0 +1,31 @@
1
+ import {
2
+ expect,
3
+ jest,
4
+ describe,
5
+ it,
6
+ beforeEach,
7
+ beforeAll,
8
+ afterAll,
9
+ afterEach,
10
+ } from '@jest/globals';
11
+ import { createMock } from '@golevelup/ts-jest';
12
+ import { LoggerService } from '@nestjs/common';
13
+ import { ValidationExceptionFilter } from '../filters/validation-exception.filter.js';
14
+ import { InputValidationError } from '../index.js';
15
+ import { CrudGenError } from '@nest-yalc-2/crud-gen/crud-gen.error.js';
16
+
17
+ describe('ValidationExceptionFilter', () => {
18
+ const logger = createMock<LoggerService>();
19
+ it('should received error to InputValidationError', () => {
20
+ const filter = new ValidationExceptionFilter(logger);
21
+ const result = filter.catch(new Error());
22
+ expect(result).toBeInstanceOf(InputValidationError);
23
+ });
24
+
25
+ it('should received error to CrudGenError', () => {
26
+ const error: CrudGenError = new CrudGenError('message', 'systemMessage');
27
+ const filter = new ValidationExceptionFilter(logger);
28
+ filter.catch(error);
29
+ expect(logger.error).toHaveBeenCalledWith(error.systemMessage, error.stack);
30
+ });
31
+ });
@@ -0,0 +1,28 @@
1
+ import { expect, describe, it } from '@jest/globals';
2
+ import {
3
+ getHttpStatusDescription,
4
+ HttpStatusCodes,
5
+ } from '@nest-yalc-2/utils/http.helper.js';
6
+ import { HttpException } from '@nestjs/common';
7
+ import { AdditionalVerificationNeededError } from '../index.js';
8
+
9
+ describe('Verification error', () => {
10
+ const error = new AdditionalVerificationNeededError();
11
+
12
+ it('should be defined', () => {
13
+ expect(error).toBeDefined();
14
+ });
15
+
16
+ it('should have the correct message and code', () => {
17
+ expect(error.description).toEqual(
18
+ getHttpStatusDescription(HttpStatusCodes.UnavailableForLegalReasons),
19
+ );
20
+ expect(error.getStatus()).toEqual(
21
+ HttpStatusCodes.UnavailableForLegalReasons,
22
+ );
23
+ });
24
+
25
+ it('should be an instance of HttpException', () => {
26
+ expect(error).toBeInstanceOf(HttpException);
27
+ });
28
+ });
@@ -0,0 +1,93 @@
1
+ import type { ImprovedLoggerService } from '@nest-yalc-2/logger/logger-abstract.service.js';
2
+ import { ClassType, Mixin } from '@nest-yalc-2/types/globals.d.js';
3
+ import { HttpException, HttpExceptionOptions, HttpStatus, LogLevel } from '@nestjs/common';
4
+ import { EventEmitter2 } from '@nestjs/event-emitter';
5
+ export declare const ON_DEFAULT_ERROR_EVENT = "onDefaultError";
6
+ export interface ISharedErrorProperties {
7
+ data?: any;
8
+ config?: any;
9
+ internalMessage?: string;
10
+ description?: string;
11
+ eventName?: string;
12
+ }
13
+ export interface IHttpExceptionArguments {
14
+ response?: Partial<IBetterResponseInterface>;
15
+ errorCode?: HttpStatus | number;
16
+ }
17
+ export interface IHttpExceptionParentArguments extends Omit<IHttpExceptionArguments, 'errorCode'> {
18
+ }
19
+ export interface IErrorPayload extends ISharedErrorProperties {
20
+ response?: Partial<IBetterResponseInterface>;
21
+ cause?: IFormattedCause;
22
+ errorName?: string;
23
+ }
24
+ export interface IErrorEventPayload extends IErrorPayload {
25
+ message?: string;
26
+ stack?: string;
27
+ }
28
+ export interface ILogErrorPayload extends Omit<IErrorEventPayload, keyof IHttpExceptionArguments> {
29
+ [key: string]: any;
30
+ }
31
+ type loggerOptionType = {
32
+ instance?: ImprovedLoggerService;
33
+ level?: LogLevel;
34
+ } | false;
35
+ export interface IAbstractDefaultError extends Omit<HttpException, 'cause' | 'message'>, Omit<IErrorEventPayload, 'response'> {
36
+ logger?: loggerOptionType;
37
+ eventEmitter?: EventEmitter2;
38
+ getResponse(): IBetterResponseInterface;
39
+ getInternalMessage(): string | undefined;
40
+ getDescription(): string | undefined;
41
+ getEventPayload(): IErrorEventPayload;
42
+ setErrorInfo(options: IAbstractDefaultErrorOptions & {
43
+ response?: Partial<IBetterResponseInterface>;
44
+ }): void;
45
+ mergeErrorInfo(info: IAbstractDefaultErrorOptions & {
46
+ response?: Partial<IBetterResponseInterface>;
47
+ cause?: Error;
48
+ }): void;
49
+ }
50
+ export interface IAbstractDefaultErrorConstructor<TErrorClass extends ClassType<HttpException> = ClassType<HttpException>> {
51
+ new (options: IAbstractDefaultErrorOptions, ...args: ConstructorParameters<TErrorClass>): IAbstractDefaultError;
52
+ }
53
+ export interface IAbstractDefaultErrorOptions extends ISharedErrorProperties {
54
+ masks?: string[];
55
+ logger?: loggerOptionType | boolean;
56
+ eventEmitter?: EventEmitter2 | boolean;
57
+ eventName?: string;
58
+ stack?: string;
59
+ }
60
+ export interface IDefaultErrorBaseOptions extends Omit<IAbstractDefaultErrorOptions, 'internalMessage'>, HttpExceptionOptions, IHttpExceptionParentArguments {
61
+ }
62
+ export interface IDefaultErrorOptions extends Omit<IAbstractDefaultErrorOptions, 'internalMessage'>, HttpExceptionOptions, IHttpExceptionArguments {
63
+ }
64
+ export interface IBetterResponseInterface {
65
+ error?: string;
66
+ statusCode: number;
67
+ statusCodeDescription: string;
68
+ message: string;
69
+ [key: string]: any;
70
+ }
71
+ export declare const newDefaultError: <T extends ClassType<HttpException> = typeof HttpException>(base: T, options: IAbstractDefaultErrorOptions, ...args: ConstructorParameters<T>) => IAbstractDefaultError;
72
+ interface IFormattedCause {
73
+ message?: string;
74
+ stack?: string;
75
+ parentCause?: IFormattedCause;
76
+ [key: string]: any;
77
+ }
78
+ export declare function formatCause(error?: any): IFormattedCause | undefined;
79
+ export declare const DefaultErrorMixin: <T extends ClassType<HttpException> = ClassType<HttpException>>(base?: T) => IAbstractDefaultErrorConstructor<T>;
80
+ export type DefaultErrorMixin = Mixin<typeof DefaultErrorMixin>;
81
+ export interface IDefaultErrorBaseConstructor<T extends ClassType<HttpException> = ClassType<HttpException>> {
82
+ new (internalMessage?: string, options?: Omit<IAbstractDefaultErrorOptions, 'internalMessage'>, ...args: ConstructorParameters<T>): IAbstractDefaultError;
83
+ }
84
+ export declare function DefaultErrorBase<T extends ClassType<HttpException> = ClassType<HttpException>>(base?: T): IDefaultErrorBaseConstructor<T>;
85
+ declare const DefaultError_base: IDefaultErrorBaseConstructor<typeof HttpException>;
86
+ export declare class DefaultError extends DefaultError_base {
87
+ static defaultStatusCode: HttpStatus;
88
+ constructor(internalMessage?: string, options?: IDefaultErrorOptions);
89
+ }
90
+ export declare const errorToDefaultError: (error: Error | HttpException | DefaultError, options?: IDefaultErrorOptions) => DefaultError;
91
+ export declare function isDefaultErrorMixin(error: any): error is IAbstractDefaultError;
92
+ export declare function isDefaultErrorMixinClass(error: any): error is typeof DefaultError;
93
+ export {};