@nest-yalc-2/errors 2.2.13 → 2.2.16
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/README.md +116 -15
- package/package.json +39 -39
- package/dist/src/__tests__/database-exception.filter.spec.ts +0 -71
- package/dist/src/__tests__/http-exception.filter.spec.ts +0 -182
- package/dist/src/__tests__/system-exception.filter.spec.ts +0 -39
- package/dist/src/__tests__/tsconfig.json +0 -3
- package/dist/src/__tests__/validation-exception.filter.spec.ts +0 -31
- package/dist/src/filters/database-exception.filter.d.ts +0 -8
- package/dist/src/filters/database-exception.filter.js +0 -30
- package/dist/src/filters/database-exception.filter.js.map +0 -1
- package/dist/src/filters/database-exception.filter.ts +0 -45
- package/dist/src/filters/http-exception.filter.d.ts +0 -18
- package/dist/src/filters/http-exception.filter.js +0 -102
- package/dist/src/filters/http-exception.filter.js.map +0 -1
- package/dist/src/filters/http-exception.filter.ts +0 -145
- package/dist/src/filters/index.d.ts +0 -1
- package/dist/src/filters/index.js +0 -2
- package/dist/src/filters/index.js.map +0 -1
- package/dist/src/filters/index.ts +0 -6
- package/dist/src/filters/system-exception.filter.d.ts +0 -7
- package/dist/src/filters/system-exception.filter.js +0 -18
- package/dist/src/filters/system-exception.filter.js.map +0 -1
- package/dist/src/filters/system-exception.filter.ts +0 -13
- package/dist/src/filters/validation-exception.filter.d.ts +0 -8
- package/dist/src/filters/validation-exception.filter.js +0 -22
- package/dist/src/filters/validation-exception.filter.js.map +0 -1
- package/dist/src/filters/validation-exception.filter.ts +0 -26
- package/dist/src/index.d.ts +0 -2
- package/dist/src/index.js +0 -3
- package/dist/src/index.js.map +0 -1
- package/dist/src/index.ts +0 -4
package/README.md
CHANGED
|
@@ -6,13 +6,6 @@
|
|
|
6
6
|
[](https://github.com/AI-Autistic-Intelligence)
|
|
7
7
|
</div>
|
|
8
8
|
|
|
9
|
-
## 📖 Overview
|
|
10
|
-
|
|
11
|
-
**@nest-yalc-2/errors** is a core enterprise module of the [Ferrox Ecosystem](https://ferrox-rust.dev).
|
|
12
|
-
Core enterprise module for the @nest-yalc-2/errors integration within the Ferrox/YALC ecosystem.
|
|
13
|
-
|
|
14
|
-
> ⚠️ **Note:** This package is a foundational component of the enterprise Ferrox/YALC microservice architecture. For comprehensive documentation, architecture patterns (including the 7-Layer Architecture), and ecosystem comparisons across Node, Rust, Python, and PHP, please visit the [Official Documentation Portal](https://ferrox-rust.dev/docs/nestjs-yalc/fundamentals/errors).
|
|
15
|
-
|
|
16
9
|
## 🚀 Installation
|
|
17
10
|
|
|
18
11
|
```bash
|
|
@@ -23,18 +16,126 @@ yarn add @nest-yalc-2/errors
|
|
|
23
16
|
pnpm add @nest-yalc-2/errors
|
|
24
17
|
```
|
|
25
18
|
|
|
26
|
-
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# ⚠️ Exception Filters & Error Mapping (`@nest-yalc-2/errors`)
|
|
22
|
+
|
|
23
|
+
`@nest-yalc-2/errors` provides standardized NestJS 11+ Exception Filters mapping `@node-yalc/errors` to RFC 7807 Problem Details HTTP and GraphQL error responses.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🌟 Key Features
|
|
28
|
+
|
|
29
|
+
- **Global Exception Filter (`YalcExceptionFilter`)**: Intercepts `@node-yalc/errors` and standard NestJS exceptions globally.
|
|
30
|
+
- **RFC 7807 Problem Details Compliance**: Formats HTTP error responses into standard `application/problem+json` structure.
|
|
31
|
+
- **Production Stack Trace Masking**: Masks internal stack trace details in production while preserving correlation IDs.
|
|
32
|
+
- **GraphQL Error Extension Mapping**: Formats Apollo and Mercurius GraphQL error extensions.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 🔬 Internal Architecture & Execution Mechanics
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
flowchart TD
|
|
40
|
+
Exception["AppError / DomainError Thrown"]
|
|
41
|
+
GlobalFilter["YalcExceptionFilter Execution"]
|
|
42
|
+
EnvCheck{"Environment Check (Production?)"}
|
|
43
|
+
MaskedError["Sanitize Stack Trace & Internal DB Details"]
|
|
44
|
+
FullError["Include Full Stack Trace (Development Only)"]
|
|
45
|
+
RFCResponse["Emit RFC 7807 Problem Details JSON"]
|
|
46
|
+
|
|
47
|
+
Exception --> GlobalFilter
|
|
48
|
+
GlobalFilter --> EnvCheck
|
|
49
|
+
EnvCheck -->|Production| MaskedError
|
|
50
|
+
EnvCheck -->|Development| FullError
|
|
51
|
+
MaskedError --> RFCResponse
|
|
52
|
+
FullError --> RFCResponse
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 📊 Architectural Comparison: `@nest-yalc-2/errors` vs Standard NestJS Filters
|
|
58
|
+
|
|
59
|
+
| Feature / Dimension | ⚠️ `@nest-yalc-2/errors` | 🐢 Default NestJS Exception Filter |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| **Response Format** | **RFC 7807 Problem Details Compliant** | Basic `{ statusCode, message, error }` |
|
|
62
|
+
| **Stack Trace Protection** | **Automated Production Masking** | Exposes Stack Traces if unhandled |
|
|
63
|
+
| **Trace ID Injection** | **Automatically attaches `X-Request-Id`** | Manual Formatting Required |
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 🚀 Practical Usage & Production Code Examples
|
|
68
|
+
|
|
69
|
+
### 1. Registering Global Exception Filter in `AppModule`
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { Module } from '@nestjs/common';
|
|
73
|
+
import { APP_FILTER } from '@nestjs/core';
|
|
74
|
+
import { YalcExceptionFilter } from '@nest-yalc-2/errors';
|
|
75
|
+
|
|
76
|
+
@Module({
|
|
77
|
+
providers: [
|
|
78
|
+
{
|
|
79
|
+
provide: APP_FILTER,
|
|
80
|
+
useClass: YalcExceptionFilter,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
})
|
|
84
|
+
export class AppModule {}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2. Throwing Typed Errors in Business Services
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { Injectable } from '@nestjs/common';
|
|
91
|
+
import { NotFoundError, ValidationError } from '@node-yalc/errors';
|
|
92
|
+
|
|
93
|
+
@Injectable()
|
|
94
|
+
export class AccountService {
|
|
95
|
+
|
|
96
|
+
async findAccount(accountId: string) {
|
|
97
|
+
if (!accountId) {
|
|
98
|
+
throw new ValidationError('Account ID is required');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const account = null;
|
|
102
|
+
if (!account) {
|
|
103
|
+
throw new NotFoundError(`Account ${accountId} not found`, { accountId });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return account;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## ⚠️ Common Pitfalls & Anti-Patterns
|
|
114
|
+
|
|
115
|
+
> [!CAUTION]
|
|
116
|
+
> **Catching Errors and Returning HTTP 200 OK**: Returning `200 OK` with `{ success: false, error: '...' }` inside response bodies breaks REST semantics, caches error responses in CDNs, and confuses API clients. Always throw typed exceptions mapped by `YalcExceptionFilter`.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 💡 Best Practices
|
|
121
|
+
|
|
122
|
+
> [!TIP]
|
|
123
|
+
> **Client Request Correlation**: Include the returned `instance` trace ID when logging client-side errors to allow support engineers to locate the exact backend log line instantly.
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
---
|
|
27
127
|
|
|
28
|
-
|
|
128
|
+
## 🔗 Cross-References
|
|
29
129
|
|
|
30
|
-
|
|
130
|
+
To see how this module integrates with the rest of the Ferrox architecture, refer to the following documentation:
|
|
31
131
|
|
|
32
|
-
|
|
132
|
+
- [GraphQL Transport Module](https://ferrox-rust.dev/docs/nestjs-yalc/transports/graphql)
|
|
133
|
+
- [Node-YALC Errors](https://ferrox-rust.dev/docs/nestjs-yalc/node-yalc/docs/fundamentals/errors)
|
|
33
134
|
|
|
34
|
-
## 🛡️ Security & Enterprise Support
|
|
35
135
|
|
|
36
|
-
|
|
136
|
+
---
|
|
137
|
+
## 📚 Ecosystem Documentation
|
|
37
138
|
|
|
38
|
-
|
|
139
|
+
This module is a core component of the Ferrox enterprise microservice architecture.
|
|
39
140
|
|
|
40
|
-
|
|
141
|
+
👉 **[Read the Full Documentation on Ferrox-Rust.dev](https://ferrox-rust.dev/docs/nestjs-yalc/fundamentals/errors)**
|
package/package.json
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
2
|
+
"name": "@nest-yalc-2/errors",
|
|
3
|
+
"version": "2.2.16",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "",
|
|
6
|
+
"main": "./dist/src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/src/index.js",
|
|
9
|
+
"./*": "./dist/src/*"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
13
|
+
},
|
|
14
|
+
"author": "Autistic_Intelligence",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"types": "./dist/src/index.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@nest-yalc-2/crud-gen": "*",
|
|
22
|
+
"@nest-yalc-2/event-manager": "*",
|
|
23
|
+
"@nest-yalc-2/logger": "*",
|
|
24
|
+
"@nest-yalc-2/utils": "*",
|
|
25
|
+
"axios": "^1.20.0",
|
|
26
|
+
"neverthrow": "^8.2.0",
|
|
27
|
+
"tslib": "^2.8.1"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@nestjs/common": "^12.0.0"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"nestjs",
|
|
34
|
+
"nestjs-yalc",
|
|
35
|
+
"yalc",
|
|
36
|
+
"errors",
|
|
37
|
+
"framework",
|
|
38
|
+
"utility"
|
|
39
|
+
]
|
|
40
|
+
}
|
|
@@ -1,71 +0,0 @@
|
|
|
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 {
|
|
13
|
-
ArgumentsHost,
|
|
14
|
-
InternalServerErrorException,
|
|
15
|
-
LoggerService,
|
|
16
|
-
} from '@nestjs/common';
|
|
17
|
-
import { EntityTarget } from 'typeorm';
|
|
18
|
-
import { ConnectionNotFoundError, EntityNotFoundError } from 'typeorm';
|
|
19
|
-
import { ExceptionContextEnum } from '@node-yalc/errors/error.enum.js';
|
|
20
|
-
import { DatabaseExceptionFilter } from '../filters/database-exception.filter.js';
|
|
21
|
-
|
|
22
|
-
import { GqlArgumentsHost } from '@nestjs/graphql';
|
|
23
|
-
|
|
24
|
-
jest.mock('@nestjs/graphql');
|
|
25
|
-
|
|
26
|
-
describe('Database exceptions filter', () => {
|
|
27
|
-
let filter: DatabaseExceptionFilter;
|
|
28
|
-
const loggerServiceMock = createMock<LoggerService>();
|
|
29
|
-
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
filter = new DatabaseExceptionFilter(loggerServiceMock);
|
|
32
|
-
GqlArgumentsHost.create = jest.fn().mockReturnValue({
|
|
33
|
-
getType: jest.fn(),
|
|
34
|
-
} as any) as any;
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
afterEach(() => {
|
|
38
|
-
jest.restoreAllMocks();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should be defined', () => {
|
|
42
|
-
expect(filter).toBeDefined();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should catch and log EntityNotFound errors', () => {
|
|
46
|
-
const mockArgumentsHost = createMock<ArgumentsHost>();
|
|
47
|
-
|
|
48
|
-
const mockedEntityTarget: EntityTarget<null> = 'emptyString';
|
|
49
|
-
const error = new EntityNotFoundError(mockedEntityTarget, []);
|
|
50
|
-
|
|
51
|
-
const returnedError = filter.catch(error, mockArgumentsHost);
|
|
52
|
-
expect(loggerServiceMock.error).toHaveBeenCalledWith(
|
|
53
|
-
error,
|
|
54
|
-
ExceptionContextEnum.DATABASE,
|
|
55
|
-
);
|
|
56
|
-
expect(returnedError).toBeInstanceOf(InternalServerErrorException);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('should catch and log ConnectionNotFoundError errors', () => {
|
|
60
|
-
const mockArgumentsHost = createMock<ArgumentsHost>();
|
|
61
|
-
|
|
62
|
-
const error = new ConnectionNotFoundError('test connection');
|
|
63
|
-
|
|
64
|
-
filter.catch(error, mockArgumentsHost);
|
|
65
|
-
expect(loggerServiceMock.error).toHaveBeenCalledWith(
|
|
66
|
-
error,
|
|
67
|
-
error.stack,
|
|
68
|
-
ExceptionContextEnum.DATABASE,
|
|
69
|
-
);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
@@ -1,182 +0,0 @@
|
|
|
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 '@node-yalc/errors';
|
|
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 and send response', () => {
|
|
101
|
-
const exception = new InternalServerErrorException();
|
|
102
|
-
mockArgumentsHost.getType.mockReturnValue('http');
|
|
103
|
-
const mockResponse = {
|
|
104
|
-
status: jest.fn().mockReturnThis(),
|
|
105
|
-
send: jest.fn(),
|
|
106
|
-
};
|
|
107
|
-
mockArgumentsHost.switchToHttp.mockReturnValue({
|
|
108
|
-
getResponse: () => mockResponse,
|
|
109
|
-
getRequest: jest.fn(),
|
|
110
|
-
getNext: jest.fn(),
|
|
111
|
-
} as any);
|
|
112
|
-
filter.catch(exception, mockArgumentsHost as ArgumentsHost);
|
|
113
|
-
expect(loggerServiceMock.error).toHaveBeenCalledWith(
|
|
114
|
-
exception.message,
|
|
115
|
-
exception.stack,
|
|
116
|
-
expect.anything(),
|
|
117
|
-
);
|
|
118
|
-
expect(mockResponse.status).toHaveBeenCalledWith(500);
|
|
119
|
-
expect(mockResponse.send).toHaveBeenCalledWith(exception.message);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('should catch and log Non-Http error with host type http and send response', () => {
|
|
123
|
-
const exception = new Error('test');
|
|
124
|
-
mockArgumentsHost.getType.mockReturnValue('http');
|
|
125
|
-
const mockResponse = {
|
|
126
|
-
status: jest.fn().mockReturnThis(),
|
|
127
|
-
send: jest.fn(),
|
|
128
|
-
};
|
|
129
|
-
mockArgumentsHost.switchToHttp.mockReturnValue({
|
|
130
|
-
getResponse: () => mockResponse,
|
|
131
|
-
getRequest: jest.fn(),
|
|
132
|
-
getNext: jest.fn(),
|
|
133
|
-
} as any);
|
|
134
|
-
filter.catch(exception, mockArgumentsHost as ArgumentsHost);
|
|
135
|
-
expect(mockResponse.status).toHaveBeenCalledWith(500);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('should not send response if sendResponse is false', () => {
|
|
139
|
-
const exception = new InternalServerErrorException();
|
|
140
|
-
mockArgumentsHost.getType.mockReturnValue('http');
|
|
141
|
-
const mockResponse = {
|
|
142
|
-
status: jest.fn().mockReturnThis(),
|
|
143
|
-
send: jest.fn(),
|
|
144
|
-
};
|
|
145
|
-
mockArgumentsHost.switchToHttp.mockReturnValue({
|
|
146
|
-
getResponse: () => mockResponse,
|
|
147
|
-
getRequest: jest.fn(),
|
|
148
|
-
getNext: jest.fn(),
|
|
149
|
-
} as any);
|
|
150
|
-
filter.catch(exception, mockArgumentsHost as ArgumentsHost, { sendResponse: false });
|
|
151
|
-
expect(mockResponse.status).not.toHaveBeenCalled();
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('should catch and log Http log with host type http', () => {
|
|
155
|
-
const exception = new BadRequestException();
|
|
156
|
-
mockArgumentsHost.getType.mockReturnValue('http');
|
|
157
|
-
const mockResponse = {
|
|
158
|
-
status: jest.fn().mockReturnThis(),
|
|
159
|
-
send: jest.fn(),
|
|
160
|
-
};
|
|
161
|
-
mockArgumentsHost.switchToHttp.mockReturnValue({
|
|
162
|
-
getResponse: () => mockResponse,
|
|
163
|
-
getRequest: jest.fn(),
|
|
164
|
-
getNext: jest.fn(),
|
|
165
|
-
} as any);
|
|
166
|
-
filter.catch(exception, mockArgumentsHost as ArgumentsHost);
|
|
167
|
-
expect(loggerServiceMock.log).toHaveBeenCalledWith(
|
|
168
|
-
exception.message,
|
|
169
|
-
expect.anything(),
|
|
170
|
-
);
|
|
171
|
-
expect(mockResponse.status).toHaveBeenCalledWith(400);
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('should catch an error with the logger itself', () => {
|
|
175
|
-
const exception = new InternalServerErrorException();
|
|
176
|
-
loggerServiceMock.error = null;
|
|
177
|
-
mockArgumentsHost.getType.mockReturnValue('http');
|
|
178
|
-
console.error = jest.fn();
|
|
179
|
-
filter.catch(exception, mockArgumentsHost as ArgumentsHost);
|
|
180
|
-
expect(console.error).toHaveBeenCalled();
|
|
181
|
-
});
|
|
182
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
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 '@node-yalc/errors/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
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
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 '@node-yalc/errors';
|
|
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
|
-
});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { GqlExceptionFilter } from '@nestjs/graphql';
|
|
2
|
-
import * as common from '@nestjs/common';
|
|
3
|
-
import type { LoggerService } from '@nestjs/common';
|
|
4
|
-
export declare class DatabaseExceptionFilter implements GqlExceptionFilter {
|
|
5
|
-
private logger;
|
|
6
|
-
constructor(logger: LoggerService);
|
|
7
|
-
catch(error: Error, host: common.ArgumentsHost): Error;
|
|
8
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import { GqlArgumentsHost } from '@nestjs/graphql';
|
|
3
|
-
import * as common from '@nestjs/common';
|
|
4
|
-
import { EntityNotFoundError, ConnectionNotFoundError } from 'typeorm';
|
|
5
|
-
import { ExceptionContextEnum } from '@node-yalc/errors/error.enum.js';
|
|
6
|
-
let DatabaseExceptionFilter = class DatabaseExceptionFilter {
|
|
7
|
-
constructor(logger) {
|
|
8
|
-
this.logger = logger;
|
|
9
|
-
}
|
|
10
|
-
catch(error, host) {
|
|
11
|
-
const gqlHost = GqlArgumentsHost.create(host);
|
|
12
|
-
gqlHost.getType();
|
|
13
|
-
switch (true) {
|
|
14
|
-
case error instanceof EntityNotFoundError:
|
|
15
|
-
this.logger.error(error, ExceptionContextEnum.DATABASE);
|
|
16
|
-
error = new common.InternalServerErrorException(error);
|
|
17
|
-
break;
|
|
18
|
-
default:
|
|
19
|
-
this.logger.error(error, error.stack, ExceptionContextEnum.DATABASE);
|
|
20
|
-
break;
|
|
21
|
-
}
|
|
22
|
-
return error;
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
DatabaseExceptionFilter = __decorate([
|
|
26
|
-
common.Catch(EntityNotFoundError, ConnectionNotFoundError),
|
|
27
|
-
__metadata("design:paramtypes", [Object])
|
|
28
|
-
], DatabaseExceptionFilter);
|
|
29
|
-
export { DatabaseExceptionFilter };
|
|
30
|
-
//# sourceMappingURL=database-exception.filter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"database-exception.filter.js","sourceRoot":"","sources":["database-exception.filter.ts"],"names":[],"mappings":";AAAA,OAAO,EAAsB,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,MAAM,MAAM,gBAAgB,CAAC;AAEzC,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAKhE,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;IAClC,YAAoB,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAE7C,KAAK,CAAC,KAAY,EAAE,IAA0B;QAC5C,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9C,OAAO,CAAC,OAAO,EAAE,CAAC;QAWlB,QAAQ,IAAI,EAAE,CAAC;YAIb,KAAK,KAAK,YAAY,mBAAmB;gBACvC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAC;gBACxD,KAAK,GAAG,IAAI,MAAM,CAAC,4BAA4B,CAAC,KAAK,CAAC,CAAC;gBAEvD,MAAM;YAER;gBACE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAC;gBAErE,MAAM;QACV,CAAC;QAGD,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAA;AAnCY,uBAAuB;IADnC,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,uBAAuB,CAAC;;GAC9C,uBAAuB,CAmCnC"}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { GqlExceptionFilter, GqlArgumentsHost } from '@nestjs/graphql';
|
|
2
|
-
import * as common from '@nestjs/common';
|
|
3
|
-
// We can import more errors from the typeorm/error folder if necessary, nothing is exported though, so use explicit paths.
|
|
4
|
-
import { EntityNotFoundError, ConnectionNotFoundError } from 'typeorm';
|
|
5
|
-
import { ExceptionContextEnum } from '@node-yalc/errors/error.enum.js';
|
|
6
|
-
|
|
7
|
-
import type { LoggerService } from '@nestjs/common';
|
|
8
|
-
|
|
9
|
-
@common.Catch(EntityNotFoundError, ConnectionNotFoundError)
|
|
10
|
-
export class DatabaseExceptionFilter implements GqlExceptionFilter {
|
|
11
|
-
constructor(private logger: LoggerService) {}
|
|
12
|
-
|
|
13
|
-
catch(error: Error, host: common.ArgumentsHost) {
|
|
14
|
-
const gqlHost = GqlArgumentsHost.create(host);
|
|
15
|
-
gqlHost.getType();
|
|
16
|
-
|
|
17
|
-
// Normally transactions are for performance monitoring,
|
|
18
|
-
// Op and Name reflect which operation and function we are running
|
|
19
|
-
// Could not get issue tracking working without, using exception filter as op.
|
|
20
|
-
// const transaction = Sentry.startTransaction({
|
|
21
|
-
// op: 'DatabaseExceptionFilter', // operation (encode)
|
|
22
|
-
// name: 'Caught Error', // name (parseAvatarImage)
|
|
23
|
-
// });
|
|
24
|
-
|
|
25
|
-
// TODO: Validate when monitoring is in place if we need an eventEmitter here instead of log
|
|
26
|
-
switch (true) {
|
|
27
|
-
// Re-throw a new 500 HTTP-friendly error
|
|
28
|
-
// Add more TypeORM errors here, because there's no base Error class
|
|
29
|
-
// @url: https://github.com/typeorm/typeorm/issues/3479
|
|
30
|
-
case error instanceof EntityNotFoundError:
|
|
31
|
-
this.logger.error(error, ExceptionContextEnum.DATABASE);
|
|
32
|
-
error = new common.InternalServerErrorException(error);
|
|
33
|
-
// Sentry.captureException(error);
|
|
34
|
-
break;
|
|
35
|
-
// Log critically any other error, because those are not expected normally
|
|
36
|
-
default:
|
|
37
|
-
this.logger.error(error, error.stack, ExceptionContextEnum.DATABASE);
|
|
38
|
-
// Sentry.captureException(error);
|
|
39
|
-
break;
|
|
40
|
-
}
|
|
41
|
-
// transaction.finish();
|
|
42
|
-
|
|
43
|
-
return error;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { GqlExceptionFilter } from '@nestjs/graphql';
|
|
2
|
-
import * as common from '@nestjs/common';
|
|
3
|
-
import type { HttpServer } from '@nestjs/common';
|
|
4
|
-
import { IAbstractDefaultError } from '@node-yalc/errors';
|
|
5
|
-
import { MissingArgumentsError } from '@nest-yalc-2/crud-gen/missing-arguments.error.js';
|
|
6
|
-
import { FastifyReply as FResponse } from 'fastify';
|
|
7
|
-
import { GqlError } from '@nest-yalc-2/graphql/plugins/gql.error.js';
|
|
8
|
-
import { BaseExceptionFilter } from '@nestjs/core';
|
|
9
|
-
import { type ImprovedLoggerService } from '@node-yalc/logger/logger-abstract.service.js';
|
|
10
|
-
type HttpErrorType = common.HttpException | MissingArgumentsError | GqlError | IAbstractDefaultError;
|
|
11
|
-
export declare class HttpExceptionFilter extends BaseExceptionFilter implements GqlExceptionFilter, common.ExceptionFilter {
|
|
12
|
-
protected logger: ImprovedLoggerService;
|
|
13
|
-
constructor(logger: ImprovedLoggerService, applicationRef?: HttpServer);
|
|
14
|
-
catch(error: Error | HttpErrorType, host: common.ArgumentsHost, { sendResponse }?: {
|
|
15
|
-
sendResponse: boolean;
|
|
16
|
-
}): Error | FResponse<import("fastify").RouteGenericInterface, import("fastify").RawServerDefault, import("node:http").IncomingMessage, import("node:http").ServerResponse<import("node:http").IncomingMessage>, unknown, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown> | IAbstractDefaultError;
|
|
17
|
-
}
|
|
18
|
-
export {};
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import * as common from '@nestjs/common';
|
|
3
|
-
import { DefaultErrorMixin, isDefaultErrorMixin, formatCause, } from '@node-yalc/errors';
|
|
4
|
-
import { MissingArgumentsError } from '@nest-yalc-2/crud-gen/missing-arguments.error.js';
|
|
5
|
-
import { isEntityError, } from '@nest-yalc-2/crud-gen/entity.error.js';
|
|
6
|
-
import { GqlError } from '@nest-yalc-2/graphql/plugins/gql.error.js';
|
|
7
|
-
import { BaseExceptionFilter } from '@nestjs/core';
|
|
8
|
-
import { getLogLevelByStatus } from '@node-yalc/event-manager/event.helper.js';
|
|
9
|
-
import { LogLevelEnum } from '@node-yalc/logger/logger.enum.js';
|
|
10
|
-
let HttpExceptionFilter = class HttpExceptionFilter extends BaseExceptionFilter {
|
|
11
|
-
constructor(logger, applicationRef) {
|
|
12
|
-
super(applicationRef);
|
|
13
|
-
this.logger = logger;
|
|
14
|
-
}
|
|
15
|
-
catch(error, host, { sendResponse } = { sendResponse: true }) {
|
|
16
|
-
try {
|
|
17
|
-
const isHttpError = this.isHttpError(error) || error instanceof common.HttpException;
|
|
18
|
-
switch (true) {
|
|
19
|
-
case error instanceof MissingArgumentsError:
|
|
20
|
-
this.logger.log(error.message, {
|
|
21
|
-
stack: error.stack,
|
|
22
|
-
});
|
|
23
|
-
break;
|
|
24
|
-
case isDefaultErrorMixin(error):
|
|
25
|
-
break;
|
|
26
|
-
case isEntityError(error):
|
|
27
|
-
{
|
|
28
|
-
const entityError = error;
|
|
29
|
-
this.logger.error(entityError.originalError?.message
|
|
30
|
-
? entityError.originalError.message
|
|
31
|
-
: error, entityError.originalError?.stack, {
|
|
32
|
-
stack: entityError.originalError?.stack,
|
|
33
|
-
data: {
|
|
34
|
-
response: entityError.getResponse(),
|
|
35
|
-
name: entityError.name,
|
|
36
|
-
cause: formatCause(entityError.cause),
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
break;
|
|
41
|
-
case isHttpError:
|
|
42
|
-
{
|
|
43
|
-
const httpError = error;
|
|
44
|
-
const logLevel = getLogLevelByStatus(httpError.getStatus());
|
|
45
|
-
if (logLevel === LogLevelEnum.ERROR) {
|
|
46
|
-
this.logger[logLevel](error.message, error.stack, {
|
|
47
|
-
stack: httpError.stack,
|
|
48
|
-
data: {
|
|
49
|
-
response: httpError.getResponse(),
|
|
50
|
-
name: error.name,
|
|
51
|
-
cause: formatCause(error.cause),
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
this.logger[logLevel](error.message, {
|
|
57
|
-
stack: error.stack,
|
|
58
|
-
data: {
|
|
59
|
-
response: httpError.getResponse(),
|
|
60
|
-
name: error.name,
|
|
61
|
-
cause: formatCause(error.cause),
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
break;
|
|
67
|
-
case error instanceof GqlError:
|
|
68
|
-
this.logger.error(error.systemMessage ?? error.message);
|
|
69
|
-
break;
|
|
70
|
-
default:
|
|
71
|
-
this.logger.error(error.message, error.stack, {
|
|
72
|
-
stack: error.stack,
|
|
73
|
-
data: {
|
|
74
|
-
cause: formatCause(error.cause),
|
|
75
|
-
name: error.name,
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
if (host.getType() === 'http') {
|
|
81
|
-
if (sendResponse) {
|
|
82
|
-
const ctx = host.switchToHttp();
|
|
83
|
-
const response = ctx.getResponse();
|
|
84
|
-
let status = common.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
85
|
-
if (isHttpError)
|
|
86
|
-
status = error.getStatus();
|
|
87
|
-
return response.status(status).send(error.message);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
catch (e) {
|
|
92
|
-
console.error(e);
|
|
93
|
-
}
|
|
94
|
-
return error;
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
HttpExceptionFilter = __decorate([
|
|
98
|
-
common.Catch(common.HttpException, MissingArgumentsError, GqlError, DefaultErrorMixin),
|
|
99
|
-
__metadata("design:paramtypes", [Object, Object])
|
|
100
|
-
], HttpExceptionFilter);
|
|
101
|
-
export { HttpExceptionFilter };
|
|
102
|
-
//# sourceMappingURL=http-exception.filter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http-exception.filter.js","sourceRoot":"","sources":["http-exception.filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { GqlExceptionFilter } from '@nestjs/graphql';
|
|
2
|
-
import * as common from '@nestjs/common';
|
|
3
|
-
import type { HttpServer } from '@nestjs/common';
|
|
4
|
-
import {
|
|
5
|
-
DefaultErrorMixin,
|
|
6
|
-
isDefaultErrorMixin,
|
|
7
|
-
formatCause,
|
|
8
|
-
IAbstractDefaultError,
|
|
9
|
-
} from '@node-yalc/errors';
|
|
10
|
-
import { MissingArgumentsError } from '@nest-yalc-2/crud-gen/missing-arguments.error.js';
|
|
11
|
-
import {
|
|
12
|
-
EntityError,
|
|
13
|
-
isEntityError,
|
|
14
|
-
} from '@nest-yalc-2/crud-gen/entity.error.js';
|
|
15
|
-
import { FastifyReply as FResponse } from 'fastify';
|
|
16
|
-
import { GqlError } from '@nest-yalc-2/graphql/plugins/gql.error.js';
|
|
17
|
-
import { BaseExceptionFilter } from '@nestjs/core';
|
|
18
|
-
import { getLogLevelByStatus } from '@node-yalc/event-manager/event.helper.js';
|
|
19
|
-
import { LogLevelEnum } from '@node-yalc/logger/logger.enum.js';
|
|
20
|
-
import { type ImprovedLoggerService } from '@node-yalc/logger/logger-abstract.service.js';
|
|
21
|
-
|
|
22
|
-
type HttpErrorType =
|
|
23
|
-
common.HttpException | MissingArgumentsError | GqlError | IAbstractDefaultError;
|
|
24
|
-
@common.Catch(
|
|
25
|
-
common.HttpException,
|
|
26
|
-
MissingArgumentsError,
|
|
27
|
-
GqlError,
|
|
28
|
-
DefaultErrorMixin,
|
|
29
|
-
)
|
|
30
|
-
export class HttpExceptionFilter
|
|
31
|
-
extends BaseExceptionFilter
|
|
32
|
-
implements GqlExceptionFilter, common.ExceptionFilter
|
|
33
|
-
{
|
|
34
|
-
constructor(
|
|
35
|
-
protected logger: ImprovedLoggerService,
|
|
36
|
-
applicationRef?: HttpServer,
|
|
37
|
-
) {
|
|
38
|
-
super(applicationRef);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
catch(
|
|
42
|
-
error: Error | HttpErrorType,
|
|
43
|
-
host: common.ArgumentsHost,
|
|
44
|
-
{ sendResponse }: { sendResponse: boolean } = { sendResponse: true },
|
|
45
|
-
) {
|
|
46
|
-
try {
|
|
47
|
-
const isHttpError =
|
|
48
|
-
this.isHttpError(error) || error instanceof common.HttpException;
|
|
49
|
-
// TODO: Validate when monitoring is in place if we need an eventEmitter here instead of log
|
|
50
|
-
switch (true) {
|
|
51
|
-
// Base logging for normal operation execution errors
|
|
52
|
-
case error instanceof MissingArgumentsError:
|
|
53
|
-
this.logger.log(error.message, {
|
|
54
|
-
stack: error.stack,
|
|
55
|
-
});
|
|
56
|
-
break;
|
|
57
|
-
|
|
58
|
-
case isDefaultErrorMixin(error):
|
|
59
|
-
// no need to log, DefaultErrorMixin already logs
|
|
60
|
-
break;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Log original error message (for now only if is an EntityError)
|
|
64
|
-
* @todo refactor with the default error mixin
|
|
65
|
-
*/
|
|
66
|
-
case isEntityError(error):
|
|
67
|
-
{
|
|
68
|
-
const entityError = error as EntityError;
|
|
69
|
-
this.logger.error(
|
|
70
|
-
entityError.originalError?.message
|
|
71
|
-
? entityError.originalError.message
|
|
72
|
-
: error,
|
|
73
|
-
entityError.originalError?.stack,
|
|
74
|
-
{
|
|
75
|
-
stack: entityError.originalError?.stack,
|
|
76
|
-
data: {
|
|
77
|
-
response: entityError.getResponse(),
|
|
78
|
-
name: entityError.name,
|
|
79
|
-
cause: formatCause(entityError.cause),
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
break;
|
|
85
|
-
|
|
86
|
-
case isHttpError:
|
|
87
|
-
{
|
|
88
|
-
const httpError = error as common.HttpException;
|
|
89
|
-
const logLevel = getLogLevelByStatus(httpError.getStatus());
|
|
90
|
-
|
|
91
|
-
if (logLevel === LogLevelEnum.ERROR) {
|
|
92
|
-
(this.logger as any)[logLevel](error.message, error.stack, {
|
|
93
|
-
stack: httpError.stack,
|
|
94
|
-
data: {
|
|
95
|
-
response: httpError.getResponse(),
|
|
96
|
-
name: error.name,
|
|
97
|
-
cause: formatCause(error.cause),
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
} else {
|
|
101
|
-
(this.logger as any)[logLevel](error.message, {
|
|
102
|
-
stack: error.stack,
|
|
103
|
-
data: {
|
|
104
|
-
response: httpError.getResponse(),
|
|
105
|
-
name: error.name,
|
|
106
|
-
cause: formatCause(error.cause),
|
|
107
|
-
},
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
break;
|
|
112
|
-
|
|
113
|
-
case error instanceof GqlError:
|
|
114
|
-
this.logger.error((<GqlError>error).systemMessage ?? error.message);
|
|
115
|
-
break;
|
|
116
|
-
|
|
117
|
-
// Log critically any other error, as those are not expected
|
|
118
|
-
default:
|
|
119
|
-
this.logger.error(error.message, error.stack, {
|
|
120
|
-
stack: error.stack,
|
|
121
|
-
data: {
|
|
122
|
-
cause: formatCause(error.cause),
|
|
123
|
-
name: error.name,
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (host.getType() === 'http') {
|
|
130
|
-
if (sendResponse) {
|
|
131
|
-
const ctx = host.switchToHttp();
|
|
132
|
-
const response = ctx.getResponse<FResponse>();
|
|
133
|
-
let status = common.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
134
|
-
if (isHttpError) status = (error as common.HttpException).getStatus();
|
|
135
|
-
return response.status(status).send(error.message);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
} catch (e) {
|
|
139
|
-
// eslint-disable-next-line no-console
|
|
140
|
-
console.error(e); // if there's an error with the logger itself
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return error;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { SystemExceptionFilter } from './system-exception.filter.js';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/* istanbul ignore file */
|
|
2
|
-
|
|
3
|
-
// export { HttpExceptionFilter } from './http-exception.filter.js';
|
|
4
|
-
// export { DatabaseExceptionFilter } from './database-exception.filter.js';
|
|
5
|
-
// export { ValidationExceptionFilter } from './validation-exception.filter.js';
|
|
6
|
-
export { SystemExceptionFilter } from './system-exception.filter.js';
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { ExceptionFilter } from '@nestjs/common';
|
|
2
|
-
import type { LoggerService } from '@nestjs/common';
|
|
3
|
-
export declare class SystemExceptionFilter implements ExceptionFilter {
|
|
4
|
-
private logger;
|
|
5
|
-
constructor(logger: LoggerService);
|
|
6
|
-
catch(error: Error): Error;
|
|
7
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import { Catch } from '@nestjs/common';
|
|
3
|
-
import { ExceptionContextEnum } from '@node-yalc/errors/error.enum.js';
|
|
4
|
-
let SystemExceptionFilter = class SystemExceptionFilter {
|
|
5
|
-
constructor(logger) {
|
|
6
|
-
this.logger = logger;
|
|
7
|
-
}
|
|
8
|
-
catch(error) {
|
|
9
|
-
this.logger.error(error, error.stack, ExceptionContextEnum.SYSTEM);
|
|
10
|
-
return error;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
SystemExceptionFilter = __decorate([
|
|
14
|
-
Catch(TypeError, SyntaxError, RangeError, EvalError, ReferenceError),
|
|
15
|
-
__metadata("design:paramtypes", [Object])
|
|
16
|
-
], SystemExceptionFilter);
|
|
17
|
-
export { SystemExceptionFilter };
|
|
18
|
-
//# sourceMappingURL=system-exception.filter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"system-exception.filter.js","sourceRoot":"","sources":["system-exception.filter.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAmB,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAGhE,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAChC,YAAoB,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAE7C,KAAK,CAAC,KAAY;QAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;QACnE,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAA;AAPY,qBAAqB;IADjC,KAAK,CAAC,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,CAAC;;GACxD,qBAAqB,CAOjC"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Catch, ExceptionFilter } from '@nestjs/common';
|
|
2
|
-
import type { LoggerService } from '@nestjs/common';
|
|
3
|
-
import { ExceptionContextEnum } from '@node-yalc/errors/error.enum.js';
|
|
4
|
-
|
|
5
|
-
@Catch(TypeError, SyntaxError, RangeError, EvalError, ReferenceError)
|
|
6
|
-
export class SystemExceptionFilter implements ExceptionFilter {
|
|
7
|
-
constructor(private logger: LoggerService) {}
|
|
8
|
-
|
|
9
|
-
catch(error: Error) {
|
|
10
|
-
this.logger.error(error, error.stack, ExceptionContextEnum.SYSTEM);
|
|
11
|
-
return error;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { GqlExceptionFilter } from '@nestjs/graphql';
|
|
2
|
-
import { InputValidationError } from '@node-yalc/errors';
|
|
3
|
-
import type { LoggerService } from '@nestjs/common';
|
|
4
|
-
export declare class ValidationExceptionFilter implements GqlExceptionFilter {
|
|
5
|
-
private logger;
|
|
6
|
-
constructor(logger: LoggerService);
|
|
7
|
-
catch(error: Error): InputValidationError;
|
|
8
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import { CrudGenError } from '@nest-yalc-2/crud-gen/crud-gen.error.js';
|
|
3
|
-
import { UUIDValidationError } from '@nest-yalc-2/graphql/scalars/uuid-validation.error.js';
|
|
4
|
-
import * as common from '@nestjs/common';
|
|
5
|
-
import { InputValidationError } from '@node-yalc/errors';
|
|
6
|
-
let ValidationExceptionFilter = class ValidationExceptionFilter {
|
|
7
|
-
constructor(logger) {
|
|
8
|
-
this.logger = logger;
|
|
9
|
-
}
|
|
10
|
-
catch(error) {
|
|
11
|
-
const newError = new InputValidationError(error.systemMessage, { response: { message: error.message } });
|
|
12
|
-
newError.stack = error.stack;
|
|
13
|
-
this.logger.error(error.systemMessage ?? newError.message, newError.stack);
|
|
14
|
-
return newError;
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
ValidationExceptionFilter = __decorate([
|
|
18
|
-
common.Catch(UUIDValidationError, CrudGenError),
|
|
19
|
-
__metadata("design:paramtypes", [Object])
|
|
20
|
-
], ValidationExceptionFilter);
|
|
21
|
-
export { ValidationExceptionFilter };
|
|
22
|
-
//# sourceMappingURL=validation-exception.filter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validation-exception.filter.js","sourceRoot":"","sources":["validation-exception.filter.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uDAAuD,CAAC;AAC5F,OAAO,KAAK,MAAM,MAAM,gBAAgB,CAAC;AAEzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAKlD,IAAM,yBAAyB,GAA/B,MAAM,yBAAyB;IACpC,YAAoB,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAE7C,KAAK,CAAC,KAAY;QAChB,MAAM,QAAQ,GAAG,IAAI,oBAAoB,CACxB,KAAM,CAAC,aAAa,EACnC,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,CACzC,CAAC;QACF,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,KAAK,CACA,KAAM,CAAC,aAAa,IAAI,QAAQ,CAAC,OAAO,EACvD,QAAQ,CAAC,KAAK,CACf,CAAC;QAEF,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAA;AAhBY,yBAAyB;IADrC,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,YAAY,CAAC;;GACnC,yBAAyB,CAgBrC"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { CrudGenError } from '@nest-yalc-2/crud-gen/crud-gen.error.js';
|
|
2
|
-
import { UUIDValidationError } from '@nest-yalc-2/graphql/scalars/uuid-validation.error.js';
|
|
3
|
-
import * as common from '@nestjs/common';
|
|
4
|
-
import { GqlExceptionFilter } from '@nestjs/graphql';
|
|
5
|
-
import { InputValidationError } from '@node-yalc/errors';
|
|
6
|
-
|
|
7
|
-
import type { LoggerService } from '@nestjs/common';
|
|
8
|
-
|
|
9
|
-
@common.Catch(UUIDValidationError, CrudGenError)
|
|
10
|
-
export class ValidationExceptionFilter implements GqlExceptionFilter {
|
|
11
|
-
constructor(private logger: LoggerService) {}
|
|
12
|
-
|
|
13
|
-
catch(error: Error) {
|
|
14
|
-
const newError = new InputValidationError(
|
|
15
|
-
(<CrudGenError>error).systemMessage,
|
|
16
|
-
{ response: { message: error.message } },
|
|
17
|
-
);
|
|
18
|
-
newError.stack = error.stack; // we need the stack trace for dev
|
|
19
|
-
this.logger.error(
|
|
20
|
-
(<CrudGenError>error).systemMessage ?? newError.message,
|
|
21
|
-
newError.stack,
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
return newError;
|
|
25
|
-
}
|
|
26
|
-
}
|
package/dist/src/index.d.ts
DELETED
package/dist/src/index.js
DELETED
package/dist/src/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,cAAc,oBAAoB,CAAC"}
|
package/dist/src/index.ts
DELETED