@flusys/nestjs-shared 3.0.1 → 4.0.0-lts
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 +159 -79
- package/cjs/classes/api-controller.class.js +26 -8
- package/cjs/classes/api-service.class.js +100 -17
- package/cjs/classes/winston-logger-adapter.class.js +15 -20
- package/cjs/classes/winston.logger.class.js +103 -70
- package/cjs/constants/index.js +1 -0
- package/cjs/constants/message-keys.js +80 -0
- package/cjs/constants/permissions.js +32 -1
- package/cjs/decorators/index.js +1 -0
- package/cjs/decorators/log-action.decorator.js +149 -0
- package/cjs/dtos/response-payload.dto.js +72 -0
- package/cjs/exceptions/base-app.exception.js +145 -0
- package/cjs/exceptions/index.js +1 -0
- package/cjs/exceptions/permission.exception.js +12 -8
- package/cjs/filters/global-exception.filter.js +167 -0
- package/cjs/filters/index.js +18 -0
- package/cjs/guards/jwt-auth.guard.js +4 -1
- package/cjs/guards/permission.guard.js +6 -13
- package/cjs/index.js +1 -0
- package/cjs/interceptors/idempotency.interceptor.js +1 -1
- package/cjs/interceptors/index.js +0 -1
- package/cjs/interfaces/logger.interface.js +1 -4
- package/cjs/middlewares/logger.middleware.js +83 -26
- package/cjs/modules/datasource/multi-tenant-datasource.service.js +33 -11
- package/cjs/modules/utils/utils.service.js +4 -20
- package/cjs/utils/index.js +0 -1
- package/cjs/utils/query-helpers.util.js +8 -1
- package/classes/api-controller.class.d.ts +1 -0
- package/classes/api-service.class.d.ts +5 -10
- package/classes/winston-logger-adapter.class.d.ts +12 -11
- package/classes/winston.logger.class.d.ts +1 -0
- package/constants/index.d.ts +1 -0
- package/constants/message-keys.d.ts +81 -0
- package/constants/permissions.d.ts +36 -0
- package/decorators/index.d.ts +1 -0
- package/decorators/log-action.decorator.d.ts +8 -0
- package/dtos/response-payload.dto.d.ts +8 -0
- package/exceptions/base-app.exception.d.ts +41 -0
- package/exceptions/index.d.ts +1 -0
- package/exceptions/permission.exception.d.ts +1 -1
- package/fesm/classes/api-controller.class.js +26 -8
- package/fesm/classes/api-service.class.js +101 -18
- package/fesm/classes/winston-logger-adapter.class.js +18 -44
- package/fesm/classes/winston.logger.class.js +100 -68
- package/fesm/constants/index.js +2 -0
- package/fesm/constants/message-keys.js +59 -0
- package/fesm/constants/permissions.js +24 -1
- package/fesm/decorators/index.js +1 -0
- package/fesm/decorators/log-action.decorator.js +139 -0
- package/fesm/dtos/response-payload.dto.js +72 -0
- package/fesm/exceptions/base-app.exception.js +109 -0
- package/fesm/exceptions/index.js +1 -0
- package/fesm/exceptions/permission.exception.js +15 -17
- package/fesm/filters/global-exception.filter.js +157 -0
- package/fesm/filters/index.js +1 -0
- package/fesm/guards/jwt-auth.guard.js +5 -2
- package/fesm/guards/permission.guard.js +8 -15
- package/fesm/index.js +1 -0
- package/fesm/interceptors/idempotency.interceptor.js +2 -2
- package/fesm/interceptors/index.js +0 -1
- package/fesm/interfaces/logger.interface.js +1 -4
- package/fesm/middlewares/logger.middleware.js +83 -26
- package/fesm/modules/datasource/multi-tenant-datasource.service.js +34 -12
- package/fesm/modules/utils/utils.service.js +5 -21
- package/fesm/utils/index.js +0 -1
- package/fesm/utils/query-helpers.util.js +8 -1
- package/filters/global-exception.filter.d.ts +10 -0
- package/filters/index.d.ts +1 -0
- package/guards/permission.guard.d.ts +1 -3
- package/index.d.ts +1 -0
- package/interceptors/index.d.ts +0 -1
- package/interfaces/logger.interface.d.ts +5 -5
- package/modules/datasource/multi-tenant-datasource.service.d.ts +1 -2
- package/modules/utils/utils.service.d.ts +0 -1
- package/package.json +5 -3
- package/utils/index.d.ts +0 -1
- package/cjs/interceptors/query-performance.interceptor.js +0 -66
- package/cjs/utils/error-handler.util.js +0 -90
- package/fesm/interceptors/query-performance.interceptor.js +0 -56
- package/fesm/utils/error-handler.util.js +0 -82
- package/interceptors/query-performance.interceptor.d.ts +0 -8
- package/utils/error-handler.util.d.ts +0 -19
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BadRequestException } from '@nestjs/common';
|
|
2
|
+
import { AUTH_MESSAGES } from '../constants';
|
|
2
3
|
/**
|
|
3
4
|
* Apply company filter to a query builder if company feature is enabled.
|
|
4
5
|
* Centralizes the common pattern of filtering by user's company.
|
|
@@ -72,7 +73,13 @@ import { BadRequestException } from '@nestjs/common';
|
|
|
72
73
|
*/ export function validateCompanyOwnership(entity, user, isCompanyFeatureEnabled, entityName) {
|
|
73
74
|
if (isCompanyFeatureEnabled && user?.companyId && hasCompanyId(entity)) {
|
|
74
75
|
if (entity.companyId && entity.companyId !== user.companyId) {
|
|
75
|
-
throw new BadRequestException(
|
|
76
|
+
throw new BadRequestException({
|
|
77
|
+
message: `${entityName} belongs to another company`,
|
|
78
|
+
messageKey: AUTH_MESSAGES.COMPANY_NO_ACCESS,
|
|
79
|
+
messageParams: {
|
|
80
|
+
entity: entityName
|
|
81
|
+
}
|
|
82
|
+
});
|
|
76
83
|
}
|
|
77
84
|
}
|
|
78
85
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ArgumentsHost, ExceptionFilter } from '@nestjs/common';
|
|
2
|
+
export declare class GlobalExceptionFilter implements ExceptionFilter {
|
|
3
|
+
private readonly logger;
|
|
4
|
+
catch(exception: unknown, host: ArgumentsHost): void;
|
|
5
|
+
private buildErrorResponse;
|
|
6
|
+
private extractHttpExceptionDetails;
|
|
7
|
+
private getStatusCode;
|
|
8
|
+
private getStack;
|
|
9
|
+
private buildLogMessage;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './global-exception.filter';
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { CanActivate, ExecutionContext } from '@nestjs/common';
|
|
2
2
|
import { Reflector } from '@nestjs/core';
|
|
3
3
|
import { HybridCache } from '../classes/hybrid-cache.class';
|
|
4
|
-
import { ILogger } from '../interfaces/logger.interface';
|
|
5
4
|
import { PermissionGuardConfig } from '../interfaces/permission.interface';
|
|
6
5
|
export declare class PermissionGuard implements CanActivate {
|
|
7
6
|
private readonly reflector;
|
|
8
7
|
private readonly cache?;
|
|
9
8
|
private readonly config;
|
|
10
|
-
|
|
11
|
-
constructor(reflector: Reflector, cache?: HybridCache, config?: PermissionGuardConfig, logger?: ILogger);
|
|
9
|
+
constructor(reflector: Reflector, cache?: HybridCache, config?: PermissionGuardConfig);
|
|
12
10
|
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
13
11
|
private normalizeToLogicNode;
|
|
14
12
|
private evaluateLogicNode;
|
package/index.d.ts
CHANGED
package/interceptors/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * from './delete-empty-id-from-body.interceptor';
|
|
2
2
|
export * from './idempotency.interceptor';
|
|
3
|
-
export * from './query-performance.interceptor';
|
|
4
3
|
export * from './response-meta.interceptor';
|
|
5
4
|
export * from './set-user-field-on-body.interceptor';
|
|
6
5
|
export * from './slug.interceptor';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export interface ILogger {
|
|
2
|
-
log(message: string, context?: string, ...args:
|
|
3
|
-
error(message: string, trace?: string, context?: string, ...args:
|
|
4
|
-
warn(message: string, context?: string, ...args:
|
|
5
|
-
debug(message: string, context?: string, ...args:
|
|
6
|
-
verbose(message: string, context?: string, ...args:
|
|
2
|
+
log(message: string, context?: string, ...args: unknown[]): void;
|
|
3
|
+
error(message: string, trace?: string, context?: string, ...args: unknown[]): void;
|
|
4
|
+
warn(message: string, context?: string, ...args: unknown[]): void;
|
|
5
|
+
debug(message: string, context?: string, ...args: unknown[]): void;
|
|
6
|
+
verbose(message: string, context?: string, ...args: unknown[]): void;
|
|
7
7
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { DatabaseMode, IDatabaseConfig, IDataSourceServiceOptions, ITenantDatabaseConfig } from '@flusys/nestjs-core';
|
|
2
|
-
import {
|
|
2
|
+
import { OnModuleDestroy } from '@nestjs/common';
|
|
3
3
|
import { Request } from 'express';
|
|
4
4
|
import { DataSource, EntityTarget, ObjectLiteral, Repository } from 'typeorm';
|
|
5
5
|
export declare class MultiTenantDataSourceService implements OnModuleDestroy {
|
|
6
6
|
protected readonly options?: IDataSourceServiceOptions;
|
|
7
7
|
protected readonly request?: Request;
|
|
8
|
-
protected readonly logger: Logger;
|
|
9
8
|
protected static readonly tenantConnections: Map<string, DataSource>;
|
|
10
9
|
protected static singleDataSource: DataSource | null;
|
|
11
10
|
protected static readonly tenantsRegistry: Map<string, ITenantDatabaseConfig>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { HybridCache } from '../../classes/hybrid-cache.class';
|
|
2
2
|
export declare class UtilsService {
|
|
3
|
-
private readonly logger;
|
|
4
3
|
getCacheKey(entityName: string, params: any, entityId?: string, tenantId?: string): string;
|
|
5
4
|
trackCacheKey(cacheKey: string, entityName: string, cacheManager: HybridCache, entityId?: string, tenantId?: string): Promise<void>;
|
|
6
5
|
clearCache(entityName: string, cacheManager: HybridCache, entityId?: string, tenantId?: string): Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-shared",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-lts",
|
|
4
4
|
"description": "Common shared utilities for Flusys NestJS applications",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "fesm/index.js",
|
|
@@ -107,9 +107,11 @@
|
|
|
107
107
|
"keyv": "^5.0.0",
|
|
108
108
|
"typeorm": "^0.3.0",
|
|
109
109
|
"winston": "^3.0.0",
|
|
110
|
-
"winston-daily-rotate-file": "^5.0.0"
|
|
110
|
+
"winston-daily-rotate-file": "^5.0.0",
|
|
111
|
+
"express": "^4.18.0",
|
|
112
|
+
"rxjs": "^7.8.0"
|
|
111
113
|
},
|
|
112
114
|
"dependencies": {
|
|
113
|
-
"@flusys/nestjs-core": "
|
|
115
|
+
"@flusys/nestjs-core": "4.0.0-lts"
|
|
114
116
|
}
|
|
115
117
|
}
|
package/utils/index.d.ts
CHANGED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "QueryPerformanceInterceptor", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return QueryPerformanceInterceptor;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _common = require("@nestjs/common");
|
|
12
|
-
const _operators = require("rxjs/operators");
|
|
13
|
-
function _define_property(obj, key, value) {
|
|
14
|
-
if (key in obj) {
|
|
15
|
-
Object.defineProperty(obj, key, {
|
|
16
|
-
value: value,
|
|
17
|
-
enumerable: true,
|
|
18
|
-
configurable: true,
|
|
19
|
-
writable: true
|
|
20
|
-
});
|
|
21
|
-
} else {
|
|
22
|
-
obj[key] = value;
|
|
23
|
-
}
|
|
24
|
-
return obj;
|
|
25
|
-
}
|
|
26
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
27
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
28
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
29
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
30
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
31
|
-
}
|
|
32
|
-
function _ts_metadata(k, v) {
|
|
33
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
34
|
-
}
|
|
35
|
-
let QueryPerformanceInterceptor = class QueryPerformanceInterceptor {
|
|
36
|
-
intercept(context, next) {
|
|
37
|
-
const request = context.switchToHttp().getRequest();
|
|
38
|
-
const { method, url } = request;
|
|
39
|
-
const handler = context.getHandler().name;
|
|
40
|
-
const controller = context.getClass().name;
|
|
41
|
-
const startTime = Date.now();
|
|
42
|
-
return next.handle().pipe((0, _operators.tap)(()=>{
|
|
43
|
-
const executionTime = Date.now() - startTime;
|
|
44
|
-
if (executionTime > this.threshold) {
|
|
45
|
-
this.logger.warn(`Slow request detected: ${method} ${url} | ` + `Controller: ${controller}.${handler} | ` + `Execution time: ${executionTime}ms`);
|
|
46
|
-
} else {
|
|
47
|
-
// Optional: Log all requests in debug mode
|
|
48
|
-
this.logger.debug(`${method} ${url} | ${controller}.${handler} | ${executionTime}ms`);
|
|
49
|
-
}
|
|
50
|
-
}));
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* @param threshold - Time threshold in milliseconds (default: 1000ms)
|
|
54
|
-
*/ constructor(threshold = 1000){
|
|
55
|
-
_define_property(this, "logger", new _common.Logger(QueryPerformanceInterceptor.name));
|
|
56
|
-
_define_property(this, "threshold", void 0);
|
|
57
|
-
this.threshold = threshold;
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
QueryPerformanceInterceptor = _ts_decorate([
|
|
61
|
-
(0, _common.Injectable)(),
|
|
62
|
-
_ts_metadata("design:type", Function),
|
|
63
|
-
_ts_metadata("design:paramtypes", [
|
|
64
|
-
Number
|
|
65
|
-
])
|
|
66
|
-
], QueryPerformanceInterceptor);
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "ErrorHandler", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return ErrorHandler;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
/** Sensitive keys that should be redacted from logs */ const SENSITIVE_KEYS = [
|
|
12
|
-
'password',
|
|
13
|
-
'secret',
|
|
14
|
-
'token',
|
|
15
|
-
'apiKey',
|
|
16
|
-
'credential',
|
|
17
|
-
'authorization'
|
|
18
|
-
];
|
|
19
|
-
let ErrorHandler = class ErrorHandler {
|
|
20
|
-
/**
|
|
21
|
-
* Safely extract error message from unknown error.
|
|
22
|
-
*/ static getErrorMessage(error) {
|
|
23
|
-
if (error instanceof Error) {
|
|
24
|
-
return error.message;
|
|
25
|
-
}
|
|
26
|
-
if (typeof error === 'string') {
|
|
27
|
-
return error;
|
|
28
|
-
}
|
|
29
|
-
return 'Unknown error occurred';
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Sanitize context data to redact sensitive fields from logs.
|
|
33
|
-
*/ static sanitizeContextForLogging(context) {
|
|
34
|
-
const sanitized = {};
|
|
35
|
-
for (const [key, value] of Object.entries(context)){
|
|
36
|
-
const isSensitive = SENSITIVE_KEYS.some((sk)=>key.toLowerCase().includes(sk.toLowerCase()));
|
|
37
|
-
if (isSensitive) {
|
|
38
|
-
sanitized[key] = '[REDACTED]';
|
|
39
|
-
} else if (Array.isArray(value)) {
|
|
40
|
-
sanitized[key] = value.map((item)=>typeof item === 'object' && item !== null ? this.sanitizeContextForLogging(item) : item);
|
|
41
|
-
} else if (typeof value === 'object' && value !== null) {
|
|
42
|
-
sanitized[key] = this.sanitizeContextForLogging(value);
|
|
43
|
-
} else {
|
|
44
|
-
sanitized[key] = value;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return sanitized;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Create error context object for internal logging.
|
|
51
|
-
*/ static createErrorContext(error, context) {
|
|
52
|
-
const errorContext = {
|
|
53
|
-
error: {
|
|
54
|
-
message: this.getErrorMessage(error)
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
if (error instanceof Error) {
|
|
58
|
-
errorContext.error.stack = error.stack;
|
|
59
|
-
errorContext.error.name = error.name;
|
|
60
|
-
}
|
|
61
|
-
if (context && Object.keys(context).length > 0) {
|
|
62
|
-
errorContext.context = this.sanitizeContextForLogging(context);
|
|
63
|
-
}
|
|
64
|
-
return errorContext;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Log error with consistent format.
|
|
68
|
-
*/ static logError(logger, error, operation, context) {
|
|
69
|
-
const errorContext = this.createErrorContext(error, {
|
|
70
|
-
operation,
|
|
71
|
-
...context
|
|
72
|
-
});
|
|
73
|
-
const errorMessage = `Failed to ${operation}: ${errorContext.error.message}`;
|
|
74
|
-
logger.error(errorMessage, errorContext.error.stack, errorContext);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Re-throw error with proper type checking.
|
|
78
|
-
*/ static rethrowError(error) {
|
|
79
|
-
if (error instanceof Error) {
|
|
80
|
-
throw error;
|
|
81
|
-
}
|
|
82
|
-
throw new Error(`Unexpected error: ${String(error)}`);
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Log error and re-throw (common pattern).
|
|
86
|
-
*/ static logAndRethrow(logger, error, operation, context) {
|
|
87
|
-
this.logError(logger, error, operation, context);
|
|
88
|
-
this.rethrowError(error);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
function _define_property(obj, key, value) {
|
|
2
|
-
if (key in obj) {
|
|
3
|
-
Object.defineProperty(obj, key, {
|
|
4
|
-
value: value,
|
|
5
|
-
enumerable: true,
|
|
6
|
-
configurable: true,
|
|
7
|
-
writable: true
|
|
8
|
-
});
|
|
9
|
-
} else {
|
|
10
|
-
obj[key] = value;
|
|
11
|
-
}
|
|
12
|
-
return obj;
|
|
13
|
-
}
|
|
14
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
15
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
17
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
18
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
|
-
}
|
|
20
|
-
function _ts_metadata(k, v) {
|
|
21
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
|
-
}
|
|
23
|
-
import { Injectable, Logger } from '@nestjs/common';
|
|
24
|
-
import { tap } from 'rxjs/operators';
|
|
25
|
-
export class QueryPerformanceInterceptor {
|
|
26
|
-
intercept(context, next) {
|
|
27
|
-
const request = context.switchToHttp().getRequest();
|
|
28
|
-
const { method, url } = request;
|
|
29
|
-
const handler = context.getHandler().name;
|
|
30
|
-
const controller = context.getClass().name;
|
|
31
|
-
const startTime = Date.now();
|
|
32
|
-
return next.handle().pipe(tap(()=>{
|
|
33
|
-
const executionTime = Date.now() - startTime;
|
|
34
|
-
if (executionTime > this.threshold) {
|
|
35
|
-
this.logger.warn(`Slow request detected: ${method} ${url} | ` + `Controller: ${controller}.${handler} | ` + `Execution time: ${executionTime}ms`);
|
|
36
|
-
} else {
|
|
37
|
-
// Optional: Log all requests in debug mode
|
|
38
|
-
this.logger.debug(`${method} ${url} | ${controller}.${handler} | ${executionTime}ms`);
|
|
39
|
-
}
|
|
40
|
-
}));
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* @param threshold - Time threshold in milliseconds (default: 1000ms)
|
|
44
|
-
*/ constructor(threshold = 1000){
|
|
45
|
-
_define_property(this, "logger", new Logger(QueryPerformanceInterceptor.name));
|
|
46
|
-
_define_property(this, "threshold", void 0);
|
|
47
|
-
this.threshold = threshold;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
QueryPerformanceInterceptor = _ts_decorate([
|
|
51
|
-
Injectable(),
|
|
52
|
-
_ts_metadata("design:type", Function),
|
|
53
|
-
_ts_metadata("design:paramtypes", [
|
|
54
|
-
Number
|
|
55
|
-
])
|
|
56
|
-
], QueryPerformanceInterceptor);
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/** Sensitive keys that should be redacted from logs */ const SENSITIVE_KEYS = [
|
|
2
|
-
'password',
|
|
3
|
-
'secret',
|
|
4
|
-
'token',
|
|
5
|
-
'apiKey',
|
|
6
|
-
'credential',
|
|
7
|
-
'authorization'
|
|
8
|
-
];
|
|
9
|
-
/**
|
|
10
|
-
* Error handling utility for consistent error logging and handling.
|
|
11
|
-
*/ export class ErrorHandler {
|
|
12
|
-
/**
|
|
13
|
-
* Safely extract error message from unknown error.
|
|
14
|
-
*/ static getErrorMessage(error) {
|
|
15
|
-
if (error instanceof Error) {
|
|
16
|
-
return error.message;
|
|
17
|
-
}
|
|
18
|
-
if (typeof error === 'string') {
|
|
19
|
-
return error;
|
|
20
|
-
}
|
|
21
|
-
return 'Unknown error occurred';
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Sanitize context data to redact sensitive fields from logs.
|
|
25
|
-
*/ static sanitizeContextForLogging(context) {
|
|
26
|
-
const sanitized = {};
|
|
27
|
-
for (const [key, value] of Object.entries(context)){
|
|
28
|
-
const isSensitive = SENSITIVE_KEYS.some((sk)=>key.toLowerCase().includes(sk.toLowerCase()));
|
|
29
|
-
if (isSensitive) {
|
|
30
|
-
sanitized[key] = '[REDACTED]';
|
|
31
|
-
} else if (Array.isArray(value)) {
|
|
32
|
-
sanitized[key] = value.map((item)=>typeof item === 'object' && item !== null ? this.sanitizeContextForLogging(item) : item);
|
|
33
|
-
} else if (typeof value === 'object' && value !== null) {
|
|
34
|
-
sanitized[key] = this.sanitizeContextForLogging(value);
|
|
35
|
-
} else {
|
|
36
|
-
sanitized[key] = value;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return sanitized;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Create error context object for internal logging.
|
|
43
|
-
*/ static createErrorContext(error, context) {
|
|
44
|
-
const errorContext = {
|
|
45
|
-
error: {
|
|
46
|
-
message: this.getErrorMessage(error)
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
if (error instanceof Error) {
|
|
50
|
-
errorContext.error.stack = error.stack;
|
|
51
|
-
errorContext.error.name = error.name;
|
|
52
|
-
}
|
|
53
|
-
if (context && Object.keys(context).length > 0) {
|
|
54
|
-
errorContext.context = this.sanitizeContextForLogging(context);
|
|
55
|
-
}
|
|
56
|
-
return errorContext;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Log error with consistent format.
|
|
60
|
-
*/ static logError(logger, error, operation, context) {
|
|
61
|
-
const errorContext = this.createErrorContext(error, {
|
|
62
|
-
operation,
|
|
63
|
-
...context
|
|
64
|
-
});
|
|
65
|
-
const errorMessage = `Failed to ${operation}: ${errorContext.error.message}`;
|
|
66
|
-
logger.error(errorMessage, errorContext.error.stack, errorContext);
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Re-throw error with proper type checking.
|
|
70
|
-
*/ static rethrowError(error) {
|
|
71
|
-
if (error instanceof Error) {
|
|
72
|
-
throw error;
|
|
73
|
-
}
|
|
74
|
-
throw new Error(`Unexpected error: ${String(error)}`);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Log error and re-throw (common pattern).
|
|
78
|
-
*/ static logAndRethrow(logger, error, operation, context) {
|
|
79
|
-
this.logError(logger, error, operation, context);
|
|
80
|
-
this.rethrowError(error);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
|
|
2
|
-
import { Observable } from 'rxjs';
|
|
3
|
-
export declare class QueryPerformanceInterceptor implements NestInterceptor {
|
|
4
|
-
private readonly logger;
|
|
5
|
-
private readonly threshold;
|
|
6
|
-
constructor(threshold?: number);
|
|
7
|
-
intercept(context: ExecutionContext, next: CallHandler): Observable<any>;
|
|
8
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Logger } from '@nestjs/common';
|
|
2
|
-
export interface IErrorContext {
|
|
3
|
-
operation?: string;
|
|
4
|
-
entity?: string;
|
|
5
|
-
userId?: string;
|
|
6
|
-
id?: string;
|
|
7
|
-
companyId?: string;
|
|
8
|
-
branchId?: string;
|
|
9
|
-
sectionId?: string;
|
|
10
|
-
data?: Record<string, unknown>;
|
|
11
|
-
}
|
|
12
|
-
export declare class ErrorHandler {
|
|
13
|
-
static getErrorMessage(error: unknown): string;
|
|
14
|
-
private static sanitizeContextForLogging;
|
|
15
|
-
private static createErrorContext;
|
|
16
|
-
static logError(logger: Logger, error: unknown, operation: string, context?: Omit<IErrorContext, 'operation'>): void;
|
|
17
|
-
static rethrowError(error: unknown): never;
|
|
18
|
-
static logAndRethrow(logger: Logger, error: unknown, operation: string, context?: Omit<IErrorContext, 'operation'>): never;
|
|
19
|
-
}
|