@flusys/nestjs-shared 1.1.0 → 1.2.0-rc.1

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 (158) hide show
  1. package/README.md +139 -1103
  2. package/cjs/classes/api-controller.class.js +320 -29
  3. package/cjs/classes/api-service.class.js +219 -64
  4. package/cjs/classes/handle-custome-db.js +37 -0
  5. package/cjs/classes/index.js +1 -2
  6. package/cjs/classes/winston.logger.class.js +103 -70
  7. package/cjs/constants/index.js +1 -4
  8. package/cjs/constants/message-keys.js +68 -0
  9. package/cjs/constants/permissions.js +114 -11
  10. package/cjs/decorators/api-response.decorator.js +1 -2
  11. package/cjs/decorators/index.js +1 -1
  12. package/cjs/decorators/log-action.decorator.js +149 -0
  13. package/cjs/decorators/require-permission.decorator.js +5 -5
  14. package/cjs/dtos/get-by-ids.dto.js +65 -0
  15. package/cjs/dtos/identity-response.dto.js +4 -8
  16. package/cjs/dtos/index.js +1 -0
  17. package/cjs/dtos/response-payload.dto.js +72 -0
  18. package/cjs/entities/identity.js +8 -2
  19. package/cjs/entities/index.js +1 -0
  20. package/cjs/entities/raw-type.js +4 -0
  21. package/cjs/entities/user-root.js +2 -1
  22. package/cjs/enums/index.js +20 -0
  23. package/cjs/enums/notification-type.enum.js +17 -0
  24. package/cjs/enums/participant-status.enum.js +17 -0
  25. package/cjs/enums/recurrence-type.enum.js +18 -0
  26. package/cjs/exceptions/base-app.exception.js +151 -0
  27. package/cjs/exceptions/index.js +1 -0
  28. package/cjs/exceptions/permission.exception.js +13 -9
  29. package/cjs/filters/global-exception.filter.js +279 -0
  30. package/cjs/filters/index.js +18 -0
  31. package/cjs/guards/jwt-auth.guard.js +4 -1
  32. package/cjs/guards/permission.guard.js +71 -77
  33. package/cjs/index.js +2 -0
  34. package/cjs/interceptors/idempotency.interceptor.js +1 -1
  35. package/cjs/interceptors/index.js +0 -1
  36. package/cjs/interfaces/event-manager-adapter.interface.js +11 -0
  37. package/cjs/interfaces/index.js +2 -1
  38. package/cjs/interfaces/notification-adapter.interface.js +11 -0
  39. package/cjs/interfaces/permission.interface.js +1 -1
  40. package/cjs/middlewares/logger.middleware.js +83 -26
  41. package/cjs/modules/datasource/index.js +0 -1
  42. package/cjs/modules/datasource/multi-tenant-datasource.service.js +46 -85
  43. package/cjs/modules/utils/utils.service.js +4 -20
  44. package/cjs/utils/date-time.util.js +94 -0
  45. package/cjs/utils/index.js +1 -1
  46. package/cjs/utils/query-helpers.util.js +8 -1
  47. package/cjs/utils/request.util.js +25 -0
  48. package/classes/api-controller.class.d.ts +14 -6
  49. package/classes/api-service.class.d.ts +25 -22
  50. package/classes/handle-custome-db.d.ts +3 -0
  51. package/classes/index.d.ts +1 -2
  52. package/classes/winston.logger.class.d.ts +1 -0
  53. package/constants/index.d.ts +1 -1
  54. package/constants/message-keys.d.ts +45 -0
  55. package/constants/permissions.d.ts +127 -0
  56. package/decorators/api-response.decorator.d.ts +1 -1
  57. package/decorators/current-user.decorator.d.ts +1 -1
  58. package/decorators/index.d.ts +1 -1
  59. package/decorators/log-action.decorator.d.ts +8 -0
  60. package/decorators/require-permission.decorator.d.ts +2 -2
  61. package/dtos/get-by-ids.dto.d.ts +4 -0
  62. package/dtos/index.d.ts +1 -0
  63. package/dtos/response-payload.dto.d.ts +8 -0
  64. package/entities/index.d.ts +1 -0
  65. package/entities/raw-type.d.ts +1 -0
  66. package/enums/index.d.ts +3 -0
  67. package/enums/notification-type.enum.d.ts +6 -0
  68. package/enums/participant-status.enum.d.ts +6 -0
  69. package/enums/recurrence-type.enum.d.ts +7 -0
  70. package/exceptions/base-app.exception.d.ts +41 -0
  71. package/exceptions/index.d.ts +1 -0
  72. package/exceptions/permission.exception.d.ts +2 -2
  73. package/fesm/classes/api-controller.class.js +321 -30
  74. package/fesm/classes/api-service.class.js +222 -67
  75. package/fesm/classes/handle-custome-db.js +19 -0
  76. package/fesm/classes/index.js +1 -2
  77. package/fesm/classes/winston.logger.class.js +100 -68
  78. package/fesm/constants/index.js +2 -1
  79. package/fesm/constants/message-keys.js +49 -0
  80. package/fesm/constants/permissions.js +86 -14
  81. package/fesm/decorators/api-response.decorator.js +2 -20
  82. package/fesm/decorators/index.js +1 -1
  83. package/fesm/decorators/log-action.decorator.js +139 -0
  84. package/fesm/decorators/require-permission.decorator.js +17 -65
  85. package/fesm/dtos/get-by-ids.dto.js +55 -0
  86. package/fesm/dtos/identity-response.dto.js +4 -8
  87. package/fesm/dtos/index.js +1 -0
  88. package/fesm/dtos/response-payload.dto.js +72 -0
  89. package/fesm/entities/identity.js +8 -2
  90. package/fesm/entities/index.js +1 -0
  91. package/fesm/entities/raw-type.js +1 -0
  92. package/fesm/entities/user-root.js +2 -1
  93. package/fesm/enums/index.js +3 -0
  94. package/fesm/enums/notification-type.enum.js +7 -0
  95. package/fesm/enums/participant-status.enum.js +7 -0
  96. package/fesm/enums/recurrence-type.enum.js +8 -0
  97. package/fesm/exceptions/base-app.exception.js +115 -0
  98. package/fesm/exceptions/index.js +1 -0
  99. package/fesm/exceptions/permission.exception.js +16 -18
  100. package/fesm/filters/global-exception.filter.js +269 -0
  101. package/fesm/filters/index.js +1 -0
  102. package/fesm/guards/jwt-auth.guard.js +5 -2
  103. package/fesm/guards/permission.guard.js +73 -79
  104. package/fesm/index.js +2 -0
  105. package/fesm/interceptors/idempotency.interceptor.js +2 -2
  106. package/fesm/interceptors/index.js +0 -1
  107. package/fesm/interfaces/datasource.interface.js +1 -20
  108. package/fesm/interfaces/event-manager-adapter.interface.js +1 -0
  109. package/fesm/interfaces/index.js +2 -1
  110. package/fesm/interfaces/notification-adapter.interface.js +1 -0
  111. package/fesm/interfaces/permission.interface.js +1 -3
  112. package/fesm/middlewares/logger.middleware.js +83 -26
  113. package/fesm/modules/datasource/index.js +0 -1
  114. package/fesm/modules/datasource/multi-tenant-datasource.service.js +47 -86
  115. package/fesm/modules/utils/utils.service.js +5 -21
  116. package/fesm/utils/date-time.util.js +70 -0
  117. package/fesm/utils/index.js +1 -1
  118. package/fesm/utils/query-helpers.util.js +8 -1
  119. package/fesm/utils/request.util.js +22 -0
  120. package/filters/global-exception.filter.d.ts +9 -0
  121. package/filters/index.d.ts +1 -0
  122. package/guards/permission.guard.d.ts +3 -7
  123. package/index.d.ts +2 -0
  124. package/interceptors/idempotency.interceptor.d.ts +1 -1
  125. package/interceptors/index.d.ts +0 -1
  126. package/interfaces/api.interface.d.ts +2 -0
  127. package/interfaces/event-manager-adapter.interface.d.ts +43 -0
  128. package/interfaces/index.d.ts +2 -1
  129. package/interfaces/notification-adapter.interface.d.ts +21 -0
  130. package/interfaces/permission.interface.d.ts +13 -8
  131. package/modules/datasource/index.d.ts +0 -1
  132. package/modules/datasource/multi-tenant-datasource.service.d.ts +5 -15
  133. package/modules/utils/utils.service.d.ts +0 -1
  134. package/package.json +21 -14
  135. package/utils/date-time.util.d.ts +8 -0
  136. package/utils/index.d.ts +1 -1
  137. package/utils/request.util.d.ts +2 -0
  138. package/cjs/classes/request-scoped-api.service.js +0 -61
  139. package/cjs/classes/winston-logger-adapter.class.js +0 -104
  140. package/cjs/decorators/sanitize-html.decorator.js +0 -36
  141. package/cjs/interceptors/query-performance.interceptor.js +0 -66
  142. package/cjs/interfaces/logger.interface.js +0 -7
  143. package/cjs/modules/datasource/datasource.module.js +0 -117
  144. package/cjs/utils/error-handler.util.js +0 -90
  145. package/classes/request-scoped-api.service.d.ts +0 -14
  146. package/classes/winston-logger-adapter.class.d.ts +0 -22
  147. package/decorators/sanitize-html.decorator.d.ts +0 -2
  148. package/fesm/classes/request-scoped-api.service.js +0 -51
  149. package/fesm/classes/winston-logger-adapter.class.js +0 -107
  150. package/fesm/decorators/sanitize-html.decorator.js +0 -45
  151. package/fesm/interceptors/query-performance.interceptor.js +0 -56
  152. package/fesm/interfaces/logger.interface.js +0 -4
  153. package/fesm/modules/datasource/datasource.module.js +0 -107
  154. package/fesm/utils/error-handler.util.js +0 -82
  155. package/interceptors/query-performance.interceptor.d.ts +0 -8
  156. package/interfaces/logger.interface.d.ts +0 -7
  157. package/modules/datasource/datasource.module.d.ts +0 -19
  158. package/utils/error-handler.util.d.ts +0 -19
@@ -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,14 +0,0 @@
1
- import { DataSource, EntityTarget, Repository } from 'typeorm';
2
- import { Identity } from '../entities';
3
- import { IDataSourceProvider } from '../interfaces';
4
- import { ApiService } from './api-service.class';
5
- export declare abstract class RequestScopedApiService<CreateDtoT extends object, UpdateDtoT extends {
6
- id: string;
7
- }, InterfaceT extends Identity, EntityT extends Identity, RepositoryT extends Repository<EntityT>> extends ApiService<CreateDtoT, UpdateDtoT, InterfaceT, EntityT, RepositoryT> {
8
- private repositoryInitialized;
9
- protected abstract resolveEntity(): EntityTarget<EntityT>;
10
- protected abstract getDataSourceProvider(): IDataSourceProvider;
11
- protected ensureRepositoryInitialized(): Promise<void>;
12
- protected initializeAdditionalRepositories(entities: EntityTarget<any>[]): Promise<Repository<any>[]>;
13
- protected getDataSourceForService(): Promise<DataSource>;
14
- }
@@ -1,22 +0,0 @@
1
- import { Logger } from '@nestjs/common';
2
- import { ILogger } from '../interfaces/logger.interface';
3
- export declare class WinstonLoggerAdapter implements ILogger {
4
- private readonly context?;
5
- constructor(context?: string);
6
- private buildLogMeta;
7
- log(message: string, context?: string, ...args: any[]): void;
8
- error(message: string, trace?: string, context?: string, ...args: any[]): void;
9
- warn(message: string, context?: string, ...args: any[]): void;
10
- debug(message: string, context?: string, ...args: any[]): void;
11
- verbose(message: string, context?: string, ...args: any[]): void;
12
- }
13
- export declare class NestLoggerAdapter implements ILogger {
14
- private readonly logger;
15
- constructor(logger: Logger);
16
- private formatMessage;
17
- log(message: string, context?: string, ...args: any[]): void;
18
- error(message: string, trace?: string, context?: string, ...args: any[]): void;
19
- warn(message: string, context?: string, ...args: any[]): void;
20
- debug(message: string, context?: string, ...args: any[]): void;
21
- verbose(message: string, context?: string, ...args: any[]): void;
22
- }
@@ -1,2 +0,0 @@
1
- export declare function SanitizeHtml(): PropertyDecorator;
2
- export declare function SanitizeAndTrim(): PropertyDecorator;
@@ -1,51 +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
- import { Injectable, Scope } from '@nestjs/common';
21
- import { ApiService } from './api-service.class';
22
- export class RequestScopedApiService extends ApiService {
23
- async ensureRepositoryInitialized() {
24
- if (!this.repositoryInitialized) {
25
- const entity = this.resolveEntity();
26
- const provider = this.getDataSourceProvider();
27
- this.repository = await provider.getRepository(entity);
28
- this.repositoryInitialized = true;
29
- }
30
- }
31
- /** Initialize additional repositories beyond the primary entity */ async initializeAdditionalRepositories(entities) {
32
- const provider = this.getDataSourceProvider();
33
- const repositories = [];
34
- for (const entity of entities){
35
- repositories.push(await provider.getRepository(entity));
36
- }
37
- return repositories;
38
- }
39
- /** Get DataSource for direct access (transactions, custom queries) */ async getDataSourceForService() {
40
- const provider = this.getDataSourceProvider();
41
- return await provider.getDataSource();
42
- }
43
- constructor(...args){
44
- super(...args), _define_property(this, "repositoryInitialized", false);
45
- }
46
- }
47
- RequestScopedApiService = _ts_decorate([
48
- Injectable({
49
- scope: Scope.REQUEST
50
- })
51
- ], RequestScopedApiService);
@@ -1,107 +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
- import { instance as winstonLogger } from './winston.logger.class';
15
- import { getRequestId, getUserId, getTenantId, getCompanyId } from '../middlewares/logger.middleware';
16
- /**
17
- * Get correlation context for logging
18
- * Automatically includes requestId, userId, tenantId, companyId if available
19
- */ function getCorrelationMeta() {
20
- const meta = {};
21
- const requestId = getRequestId();
22
- const userId = getUserId();
23
- const tenantId = getTenantId();
24
- const companyId = getCompanyId();
25
- if (requestId) meta.requestId = requestId;
26
- if (userId) meta.userId = userId;
27
- if (tenantId) meta.tenantId = tenantId;
28
- if (companyId) meta.companyId = companyId;
29
- return meta;
30
- }
31
- /**
32
- * Winston Logger Adapter
33
- * Adapts Winston logger to ILogger interface for dependency injection
34
- *
35
- * Features:
36
- * - Automatic correlation ID injection
37
- * - User ID tracking
38
- * - Structured metadata logging
39
- *
40
- * Usage:
41
- * ```typescript
42
- * const logger = new WinstonLoggerAdapter('MyService');
43
- * logger.log('Operation completed', undefined, { orderId: '123' });
44
- * // Output: { requestId: 'uuid', userId: 'user-id', context: 'MyService', message: 'Operation completed', orderId: '123' }
45
- * ```
46
- */ export class WinstonLoggerAdapter {
47
- buildLogMeta(context, args, extra) {
48
- const meta = args?.length && typeof args[0] === 'object' ? args[0] : {};
49
- return {
50
- context: context || this.context,
51
- ...getCorrelationMeta(),
52
- ...meta,
53
- ...extra
54
- };
55
- }
56
- log(message, context, ...args) {
57
- winstonLogger.info(message, this.buildLogMeta(context, args));
58
- }
59
- error(message, trace, context, ...args) {
60
- winstonLogger.error(message, this.buildLogMeta(context, args, {
61
- stack: trace
62
- }));
63
- }
64
- warn(message, context, ...args) {
65
- winstonLogger.warn(message, this.buildLogMeta(context, args));
66
- }
67
- debug(message, context, ...args) {
68
- winstonLogger.debug(message, this.buildLogMeta(context, args));
69
- }
70
- verbose(message, context, ...args) {
71
- winstonLogger.verbose(message, this.buildLogMeta(context, args));
72
- }
73
- constructor(context){
74
- _define_property(this, "context", void 0);
75
- this.context = context;
76
- }
77
- }
78
- /**
79
- * NestJS Logger Adapter
80
- * Adapts NestJS Logger to ILogger interface
81
- *
82
- * Use this when you need to use NestJS's built-in logger
83
- * instead of Winston (e.g., for testing)
84
- */ export class NestLoggerAdapter {
85
- formatMessage(message, args) {
86
- return args?.length ? `${message} ${JSON.stringify(args)}` : message;
87
- }
88
- log(message, context, ...args) {
89
- this.logger.log(this.formatMessage(message, args), context);
90
- }
91
- error(message, trace, context, ...args) {
92
- this.logger.error(this.formatMessage(message, args), trace, context);
93
- }
94
- warn(message, context, ...args) {
95
- this.logger.warn(this.formatMessage(message, args), context);
96
- }
97
- debug(message, context, ...args) {
98
- this.logger.debug(this.formatMessage(message, args), context);
99
- }
100
- verbose(message, context, ...args) {
101
- this.logger.verbose(this.formatMessage(message, args), context);
102
- }
103
- constructor(logger){
104
- _define_property(this, "logger", void 0);
105
- this.logger = logger;
106
- }
107
- }
@@ -1,45 +0,0 @@
1
- import { Transform } from 'class-transformer';
2
- import { escapeHtml } from '../utils/html-sanitizer.util';
3
- /**
4
- * Decorator that sanitizes HTML content in string fields to prevent XSS attacks.
5
- * Applies HTML escaping during transformation (when class-transformer processes the DTO).
6
- *
7
- * @example
8
- * ```typescript
9
- * class CreateCommentDto {
10
- * @SanitizeHtml()
11
- * @IsString()
12
- * content: string;
13
- * }
14
- * ```
15
- *
16
- * Input: '<script>alert("xss")</script>'
17
- * Output: '&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;'
18
- */ export function SanitizeHtml() {
19
- return Transform(({ value })=>{
20
- if (typeof value === 'string') {
21
- return escapeHtml(value);
22
- }
23
- return value;
24
- });
25
- }
26
- /**
27
- * Decorator that sanitizes HTML and trims whitespace from string fields.
28
- * Combines sanitization with trimming for cleaner input handling.
29
- *
30
- * @example
31
- * ```typescript
32
- * class CreatePostDto {
33
- * @SanitizeAndTrim()
34
- * @IsString()
35
- * title: string;
36
- * }
37
- * ```
38
- */ export function SanitizeAndTrim() {
39
- return Transform(({ value })=>{
40
- if (typeof value === 'string') {
41
- return escapeHtml(value.trim());
42
- }
43
- return value;
44
- });
45
- }
@@ -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,4 +0,0 @@
1
- /**
2
- * Logger interface for dependency injection
3
- * Compatible with Winston, NestJS Logger, and console
4
- */ export { };
@@ -1,107 +0,0 @@
1
- function _ts_decorate(decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- 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;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- }
7
- import { MODULE_OPTIONS } from '@flusys/nestjs-core';
8
- import { Module } from '@nestjs/common';
9
- import { MultiTenantDataSourceService } from './multi-tenant-datasource.service';
10
- export class DataSourceModule {
11
- /**
12
- * Register with static options
13
- */ static forRoot(options) {
14
- const { global = false, ...moduleOptions } = options;
15
- return {
16
- module: DataSourceModule,
17
- global,
18
- providers: [
19
- {
20
- provide: MODULE_OPTIONS,
21
- useValue: moduleOptions
22
- },
23
- MultiTenantDataSourceService
24
- ],
25
- exports: [
26
- MODULE_OPTIONS,
27
- MultiTenantDataSourceService
28
- ]
29
- };
30
- }
31
- /**
32
- * Register with async options
33
- */ static forRootAsync(asyncOptions) {
34
- const { global = false, imports = [] } = asyncOptions;
35
- return {
36
- module: DataSourceModule,
37
- global,
38
- imports,
39
- providers: [
40
- ...this.createAsyncProviders(asyncOptions),
41
- MultiTenantDataSourceService
42
- ],
43
- exports: [
44
- MODULE_OPTIONS,
45
- MultiTenantDataSourceService
46
- ]
47
- };
48
- }
49
- /**
50
- * Import for child modules (uses existing MODULE_OPTIONS)
51
- */ static forFeature() {
52
- return {
53
- module: DataSourceModule,
54
- providers: [
55
- MultiTenantDataSourceService
56
- ],
57
- exports: [
58
- MultiTenantDataSourceService
59
- ]
60
- };
61
- }
62
- /**
63
- * Create async providers based on options
64
- */ static createAsyncProviders(options) {
65
- if (options.useFactory) {
66
- return [
67
- {
68
- provide: MODULE_OPTIONS,
69
- useFactory: options.useFactory,
70
- inject: options.inject || []
71
- }
72
- ];
73
- }
74
- if (options.useClass) {
75
- return [
76
- {
77
- provide: options.useClass,
78
- useClass: options.useClass
79
- },
80
- this.createFactoryProvider(options.useClass)
81
- ];
82
- }
83
- if (options.useExisting) {
84
- return [
85
- this.createFactoryProvider(options.useExisting)
86
- ];
87
- }
88
- return [
89
- {
90
- provide: MODULE_OPTIONS,
91
- useValue: {}
92
- }
93
- ];
94
- }
95
- static createFactoryProvider(factoryClass) {
96
- return {
97
- provide: MODULE_OPTIONS,
98
- useFactory: async (factory)=>factory.createOptions(),
99
- inject: [
100
- factoryClass
101
- ]
102
- };
103
- }
104
- }
105
- DataSourceModule = _ts_decorate([
106
- Module({})
107
- ], DataSourceModule);
@@ -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,7 +0,0 @@
1
- export interface ILogger {
2
- log(message: string, context?: string, ...args: any[]): void;
3
- error(message: string, trace?: string, context?: string, ...args: any[]): void;
4
- warn(message: string, context?: string, ...args: any[]): void;
5
- debug(message: string, context?: string, ...args: any[]): void;
6
- verbose(message: string, context?: string, ...args: any[]): void;
7
- }
@@ -1,19 +0,0 @@
1
- import { IAsyncModuleOptions, IDataSourceServiceOptions, IModuleOptionsFactory } from '@flusys/nestjs-core';
2
- import { DynamicModule, Type } from '@nestjs/common';
3
- export interface DataSourceModuleOptions extends IDataSourceServiceOptions {
4
- global?: boolean;
5
- }
6
- export interface DataSourceOptionsFactory extends IModuleOptionsFactory<IDataSourceServiceOptions> {
7
- createOptions(): Promise<IDataSourceServiceOptions> | IDataSourceServiceOptions;
8
- }
9
- export interface DataSourceModuleAsyncOptions extends IAsyncModuleOptions<IDataSourceServiceOptions> {
10
- useClass?: Type<DataSourceOptionsFactory>;
11
- useExisting?: Type<DataSourceOptionsFactory>;
12
- }
13
- export declare class DataSourceModule {
14
- static forRoot(options: DataSourceModuleOptions): DynamicModule;
15
- static forRootAsync(asyncOptions: DataSourceModuleAsyncOptions): DynamicModule;
16
- static forFeature(): DynamicModule;
17
- private static createAsyncProviders;
18
- private static createFactoryProvider;
19
- }
@@ -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
- }