@cryptexlabs/codex-nodejs-common 0.16.7 → 0.16.9

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/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cryptexlabs/codex-nodejs-common",
3
- "version": "0.16.6",
3
+ "version": "0.16.8",
4
4
  "description": "Common code for Codex framework",
5
5
  "main": "lib/src/index.js",
6
6
  "type": "commonjs",
@@ -3,6 +3,5 @@ import { Context } from "../context";
3
3
  export declare class FriendlyHttpException extends HttpException {
4
4
  readonly context: Context;
5
5
  readonly userMessage: string;
6
- readonly stack: string;
7
- constructor(response: string | Record<string, any>, context: Context, userMessage: string, status: HttpStatus, stack: string);
6
+ constructor(response: string | Record<string, any>, context: Context, userMessage: string, status: HttpStatus, customStack?: string);
8
7
  }
@@ -3,11 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FriendlyHttpException = void 0;
4
4
  const common_1 = require("@nestjs/common");
5
5
  class FriendlyHttpException extends common_1.HttpException {
6
- constructor(response, context, userMessage, status, stack) {
6
+ constructor(response, context, userMessage, status, customStack) {
7
7
  super(response, status);
8
8
  this.context = context;
9
9
  this.userMessage = userMessage;
10
- this.stack = stack;
10
+ if (customStack) {
11
+ this.stack = customStack;
12
+ }
13
+ else {
14
+ Error.captureStackTrace(this, this.constructor);
15
+ }
11
16
  }
12
17
  }
13
18
  exports.FriendlyHttpException = FriendlyHttpException;
@@ -1 +1 @@
1
- {"version":3,"file":"friendly-http-exception.js","sourceRoot":"","sources":["../../../src/exception/friendly-http-exception.ts"],"names":[],"mappings":";;;AAAA,2CAA2D;AAG3D,MAAa,qBAAsB,SAAQ,sBAAa;IACtD,YACE,QAAsC,EACtB,OAAgB,EAChB,WAAmB,EACnC,MAAkB,EAEF,KAAa;QAE7B,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QANR,YAAO,GAAP,OAAO,CAAS;QAChB,gBAAW,GAAX,WAAW,CAAQ;QAGnB,UAAK,GAAL,KAAK,CAAQ;IAG/B,CAAC;CACF;AAXD,sDAWC"}
1
+ {"version":3,"file":"friendly-http-exception.js","sourceRoot":"","sources":["../../../src/exception/friendly-http-exception.ts"],"names":[],"mappings":";;;AAAA,2CAA2D;AAG3D,MAAa,qBAAsB,SAAQ,sBAAa;IACtD,YACE,QAAsC,EACtB,OAAgB,EAChB,WAAmB,EACnC,MAAkB,EAElB,WAAoB;QAEpB,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QANR,YAAO,GAAP,OAAO,CAAS;QAChB,gBAAW,GAAX,WAAW,CAAQ;QAMnC,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;CACF;AAhBD,sDAgBC"}
@@ -8,6 +8,7 @@ export declare class AppHttpExceptionFilter extends BaseExceptionFilter {
8
8
  private readonly config;
9
9
  private _lastErrorLogTime;
10
10
  private _suppressedErrorCount;
11
+ private _lastSuppressedError;
11
12
  constructor(fallbackLocale: Locale, fallbackLogger: LoggerService, config: DefaultConfig, applicationRef?: HttpServer);
12
13
  private _isDebugLevel;
13
14
  private _shouldLogError;
@@ -32,11 +32,12 @@ let AppHttpExceptionFilter = class AppHttpExceptionFilter extends core_1.BaseExc
32
32
  this.config = config;
33
33
  this._lastErrorLogTime = 0;
34
34
  this._suppressedErrorCount = 0;
35
+ this._lastSuppressedError = null;
35
36
  }
36
37
  _isDebugLevel() {
37
38
  return this.config.logLevels.some((level) => level.toLowerCase() === "debug");
38
39
  }
39
- _shouldLogError() {
40
+ _shouldLogError(exception) {
40
41
  if (this._isDebugLevel()) {
41
42
  return true;
42
43
  }
@@ -47,6 +48,9 @@ let AppHttpExceptionFilter = class AppHttpExceptionFilter extends core_1.BaseExc
47
48
  return true;
48
49
  }
49
50
  this._suppressedErrorCount++;
51
+ if (exception) {
52
+ this._lastSuppressedError = exception;
53
+ }
50
54
  return false;
51
55
  }
52
56
  catch(exception, host) {
@@ -96,7 +100,7 @@ let AppHttpExceptionFilter = class AppHttpExceptionFilter extends core_1.BaseExc
96
100
  else {
97
101
  logger.error(`No stack available for error of type ${typeof exception}`);
98
102
  }
99
- const shouldLogError = this._shouldLogError();
103
+ const shouldLogError = this._shouldLogError(exception);
100
104
  if (shouldLogError) {
101
105
  if (developerText) {
102
106
  if (this.config.loggerType === "pino") {
@@ -130,8 +134,12 @@ let AppHttpExceptionFilter = class AppHttpExceptionFilter extends core_1.BaseExc
130
134
  logger.error(exception.stack);
131
135
  }
132
136
  if (this._suppressedErrorCount > 0) {
133
- logger.error(`Suppressed ${this._suppressedErrorCount} error(s) in the last minute due to rate limiting`);
137
+ const sampleError = this._lastSuppressedError
138
+ ? this.getDeveloperText(this._lastSuppressedError, fallbackLocale)
139
+ : "No sample available";
140
+ logger.error(`Suppressed ${this._suppressedErrorCount} error(s) in the last minute due to rate limiting. Sample: ${sampleError}`);
134
141
  this._suppressedErrorCount = 0;
142
+ this._lastSuppressedError = null;
135
143
  }
136
144
  }
137
145
  let status;
@@ -1 +1 @@
1
- {"version":3,"file":"app-http-exception-filter.js","sourceRoot":"","sources":["../../../src/filter/app-http-exception-filter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app-http-exception-filter.js","sourceRoot":"","sources":["../../../src/filter/app-http-exception-filter.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cryptexlabs/codex-nodejs-common",
3
- "version": "0.16.7",
3
+ "version": "0.16.9",
4
4
  "description": "Common code for Codex framework",
5
5
  "main": "lib/src/index.js",
6
6
  "type": "commonjs",
@@ -0,0 +1,99 @@
1
+ import { FriendlyHttpException } from "./friendly-http-exception";
2
+ import { HttpStatus, LoggerService } from "@nestjs/common";
3
+ import { Context } from "../context";
4
+ import { Locale, MessageContextInterface } from "@cryptexlabs/codex-data-model";
5
+ import { DefaultConfig } from "../config";
6
+ import { instance, mock, when } from "ts-mockito";
7
+
8
+ describe("FriendlyHttpException", () => {
9
+ let mockContext: Context;
10
+
11
+ beforeEach(() => {
12
+ const mockConfig = mock(DefaultConfig);
13
+ const config = instance(mockConfig);
14
+ when(mockConfig.logLevels).thenReturn(["info"]);
15
+ when(mockConfig.appName).thenReturn("test-app");
16
+ when(mockConfig.appVersion).thenReturn("1.0.0");
17
+ when(mockConfig.environmentName).thenReturn("test");
18
+ when(mockConfig.clientId).thenReturn("test-client");
19
+
20
+ const mockLogger = mock<LoggerService>();
21
+ const logger = instance(mockLogger);
22
+
23
+ const mockMessageContext = mock<MessageContextInterface>();
24
+ const messageContext = instance(mockMessageContext);
25
+
26
+ mockContext = new Context(
27
+ "test-correlation-id",
28
+ logger,
29
+ config,
30
+ {
31
+ id: "client-id",
32
+ name: "client-name",
33
+ version: "1.0.0",
34
+ variant: "test",
35
+ },
36
+ new Locale("en", "US"),
37
+ messageContext
38
+ );
39
+ });
40
+
41
+ describe("stack trace handling", () => {
42
+ it("should capture stack trace automatically when no custom stack is provided", () => {
43
+ const exception = new FriendlyHttpException(
44
+ "Test error message",
45
+ mockContext,
46
+ "User friendly message",
47
+ HttpStatus.BAD_REQUEST
48
+ );
49
+
50
+ expect(exception.stack).toBeDefined();
51
+ expect(typeof exception.stack).toBe("string");
52
+ expect(exception.stack).toContain("FriendlyHttpException");
53
+ });
54
+
55
+ it("should use custom stack when provided", () => {
56
+ const customStack = "CustomStack\nLine1\nLine2";
57
+
58
+ const exception = new FriendlyHttpException(
59
+ "Test error message",
60
+ mockContext,
61
+ "User friendly message",
62
+ HttpStatus.BAD_REQUEST,
63
+ customStack
64
+ );
65
+
66
+ expect(exception.stack).toBe(customStack);
67
+ });
68
+
69
+ it("should have stack property accessible for logging", () => {
70
+ const exception = new FriendlyHttpException(
71
+ "Test error message",
72
+ mockContext,
73
+ "User friendly message",
74
+ HttpStatus.INTERNAL_SERVER_ERROR
75
+ );
76
+
77
+ expect(exception.stack).toBeDefined();
78
+ expect(exception.name).toBe("FriendlyHttpException");
79
+ });
80
+
81
+ it("should preserve other exception properties", () => {
82
+ const userMessage = "Something went wrong";
83
+ const response = "Developer error message";
84
+ const status = HttpStatus.NOT_FOUND;
85
+
86
+ const exception = new FriendlyHttpException(
87
+ response,
88
+ mockContext,
89
+ userMessage,
90
+ status
91
+ );
92
+
93
+ expect(exception.userMessage).toBe(userMessage);
94
+ expect(exception.context).toBe(mockContext);
95
+ expect(exception.getStatus()).toBe(status);
96
+ expect(exception.message).toBe(response);
97
+ });
98
+ });
99
+ });
@@ -8,8 +8,13 @@ export class FriendlyHttpException extends HttpException {
8
8
  public readonly userMessage: string,
9
9
  status: HttpStatus,
10
10
 
11
- public readonly stack: string
11
+ customStack?: string
12
12
  ) {
13
13
  super(response, status);
14
+ if (customStack) {
15
+ this.stack = customStack;
16
+ } else {
17
+ Error.captureStackTrace(this, this.constructor);
18
+ }
14
19
  }
15
20
  }
@@ -0,0 +1,186 @@
1
+ import { AppHttpExceptionFilter } from "./app-http-exception-filter";
2
+ import { DefaultConfig } from "../config";
3
+ import { Locale } from "@cryptexlabs/codex-data-model";
4
+ import { instance, mock, when } from "ts-mockito";
5
+ import { LoggerService, HttpException, HttpStatus } from "@nestjs/common";
6
+
7
+ describe("AppHttpExceptionFilter", () => {
8
+ let filter: AppHttpExceptionFilter;
9
+ let configMock: DefaultConfig;
10
+ let loggerMock: LoggerService;
11
+ let fallbackLocale: Locale;
12
+
13
+ const setupFilter = () => {
14
+ configMock = mock(DefaultConfig);
15
+ loggerMock = {
16
+ error: jest.fn(),
17
+ log: jest.fn(),
18
+ warn: jest.fn(),
19
+ debug: jest.fn(),
20
+ verbose: jest.fn(),
21
+ } as any;
22
+
23
+ fallbackLocale = {
24
+ language: "en",
25
+ country: "US",
26
+ i18n: "en-US",
27
+ } as Locale;
28
+
29
+ when(configMock.logLevels).thenReturn(["error", "warn"]);
30
+ when(configMock.errorLogIntervalMs).thenReturn(60000);
31
+ when(configMock.loggerType).thenReturn("pino");
32
+ when(configMock.appName).thenReturn("test-app");
33
+ when(configMock.appVersion).thenReturn("1.0.0");
34
+ when(configMock.environmentName).thenReturn("test");
35
+ when(configMock.clientId).thenReturn("test-client");
36
+
37
+ filter = new AppHttpExceptionFilter(
38
+ fallbackLocale,
39
+ loggerMock,
40
+ instance(configMock)
41
+ );
42
+ };
43
+
44
+ describe("rate limiting", () => {
45
+ let originalDateNow: () => number;
46
+ let currentTime: number;
47
+
48
+ beforeEach(() => {
49
+ setupFilter();
50
+ originalDateNow = Date.now;
51
+ currentTime = 1000000;
52
+ Date.now = jest.fn(() => currentTime);
53
+ });
54
+
55
+ afterEach(() => {
56
+ Date.now = originalDateNow;
57
+ });
58
+
59
+ it("should capture and log sample error when errors are suppressed", () => {
60
+ const mockHost = {
61
+ switchToHttp: () => ({
62
+ getRequest: () => ({
63
+ headers: {},
64
+ body: {},
65
+ url: "/test",
66
+ method: "GET",
67
+ }),
68
+ getResponse: () => ({
69
+ status: () => ({
70
+ json: () => {},
71
+ }),
72
+ }),
73
+ }),
74
+ } as any;
75
+
76
+ const firstException = new HttpException(
77
+ "First error message",
78
+ HttpStatus.BAD_REQUEST
79
+ );
80
+ const secondException = new HttpException(
81
+ "Second error message",
82
+ HttpStatus.BAD_REQUEST
83
+ );
84
+ const thirdException = new HttpException(
85
+ "Third error message",
86
+ HttpStatus.BAD_REQUEST
87
+ );
88
+
89
+ filter.catch(firstException, mockHost);
90
+
91
+ filter.catch(secondException, mockHost);
92
+ filter.catch(thirdException, mockHost);
93
+
94
+ currentTime += 60000;
95
+
96
+ filter.catch(
97
+ new HttpException(
98
+ "Fourth error to trigger log",
99
+ HttpStatus.BAD_REQUEST
100
+ ),
101
+ mockHost
102
+ );
103
+
104
+ const errorCalls = (loggerMock.error as jest.Mock).mock.calls;
105
+ const rateLimitMessage = errorCalls.find(
106
+ (call) => typeof call[0] === "string" && call[0].includes("Suppressed")
107
+ );
108
+
109
+ expect(rateLimitMessage).toBeDefined();
110
+ expect(rateLimitMessage[0]).toContain(
111
+ "Suppressed 2 error(s) in the last minute due to rate limiting"
112
+ );
113
+ expect(rateLimitMessage[0]).toContain("Sample: Third error message");
114
+ });
115
+
116
+ it("should not show rate limit message when only one error occurs", () => {
117
+ const mockHost = {
118
+ switchToHttp: () => ({
119
+ getRequest: () => ({
120
+ headers: {},
121
+ body: {},
122
+ url: "/test",
123
+ method: "GET",
124
+ }),
125
+ getResponse: () => ({
126
+ status: () => ({
127
+ json: () => {},
128
+ }),
129
+ }),
130
+ }),
131
+ } as any;
132
+
133
+ const exception = new HttpException("Test error", HttpStatus.BAD_REQUEST);
134
+
135
+ filter.catch(exception, mockHost);
136
+
137
+ const errorCalls = (loggerMock.error as jest.Mock).mock.calls;
138
+ const rateLimitMessage = errorCalls.find(
139
+ (call) => typeof call[0] === "string" && call[0].includes("Suppressed")
140
+ );
141
+
142
+ expect(rateLimitMessage).toBeUndefined();
143
+ });
144
+ });
145
+
146
+ describe("getDeveloperText", () => {
147
+ beforeEach(() => {
148
+ setupFilter();
149
+ });
150
+
151
+ it("should extract developer text from exception", () => {
152
+ const exception = new HttpException(
153
+ "Test error message",
154
+ HttpStatus.BAD_REQUEST
155
+ );
156
+
157
+ const result = filter.getDeveloperText(exception, fallbackLocale);
158
+
159
+ expect(result).toBe("Test error message");
160
+ });
161
+
162
+ it("should handle exceptions with response.message", () => {
163
+ const exception = {
164
+ getStatus: () => HttpStatus.BAD_REQUEST,
165
+ response: { message: "Response error message" },
166
+ message: "Fallback message",
167
+ };
168
+
169
+ const result = filter.getDeveloperText(exception, fallbackLocale);
170
+
171
+ expect(result).toBe("Response error message");
172
+ });
173
+
174
+ it("should handle exceptions with array response.message", () => {
175
+ const exception = {
176
+ getStatus: () => HttpStatus.BAD_REQUEST,
177
+ response: { message: ["Error 1", "Error 2", "Error 3"] },
178
+ message: "Fallback message",
179
+ };
180
+
181
+ const result = filter.getDeveloperText(exception, fallbackLocale);
182
+
183
+ expect(result).toBe("Error 1 + Error 2 + Error 3");
184
+ });
185
+ });
186
+ });
@@ -25,6 +25,7 @@ import { LocaleUtil } from "../util";
25
25
  export class AppHttpExceptionFilter extends BaseExceptionFilter {
26
26
  private _lastErrorLogTime: number = 0;
27
27
  private _suppressedErrorCount: number = 0;
28
+ private _lastSuppressedError: any = null;
28
29
 
29
30
  constructor(
30
31
  private readonly fallbackLocale: Locale,
@@ -41,7 +42,7 @@ export class AppHttpExceptionFilter extends BaseExceptionFilter {
41
42
  );
42
43
  }
43
44
 
44
- private _shouldLogError(): boolean {
45
+ private _shouldLogError(exception?: any): boolean {
45
46
  if (this._isDebugLevel()) {
46
47
  return true;
47
48
  }
@@ -55,6 +56,9 @@ export class AppHttpExceptionFilter extends BaseExceptionFilter {
55
56
  }
56
57
 
57
58
  this._suppressedErrorCount++;
59
+ if (exception) {
60
+ this._lastSuppressedError = exception;
61
+ }
58
62
  return false;
59
63
  }
60
64
 
@@ -117,7 +121,7 @@ export class AppHttpExceptionFilter extends BaseExceptionFilter {
117
121
  logger.error(`No stack available for error of type ${typeof exception}`);
118
122
  }
119
123
 
120
- const shouldLogError = this._shouldLogError();
124
+ const shouldLogError = this._shouldLogError(exception);
121
125
 
122
126
  if (shouldLogError) {
123
127
  if (developerText) {
@@ -160,10 +164,14 @@ export class AppHttpExceptionFilter extends BaseExceptionFilter {
160
164
  }
161
165
 
162
166
  if (this._suppressedErrorCount > 0) {
167
+ const sampleError = this._lastSuppressedError
168
+ ? this.getDeveloperText(this._lastSuppressedError, fallbackLocale)
169
+ : "No sample available";
163
170
  logger.error(
164
- `Suppressed ${this._suppressedErrorCount} error(s) in the last minute due to rate limiting`
171
+ `Suppressed ${this._suppressedErrorCount} error(s) in the last minute due to rate limiting. Sample: ${sampleError}`
165
172
  );
166
173
  this._suppressedErrorCount = 0;
174
+ this._lastSuppressedError = null;
167
175
  }
168
176
  }
169
177