@flusys/nestjs-shared 3.0.0 → 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.
Files changed (103) hide show
  1. package/README.md +160 -80
  2. package/cjs/classes/api-controller.class.js +26 -8
  3. package/cjs/classes/api-service.class.js +100 -17
  4. package/cjs/classes/winston-logger-adapter.class.js +15 -20
  5. package/cjs/classes/winston.logger.class.js +103 -70
  6. package/cjs/constants/index.js +1 -0
  7. package/cjs/constants/message-keys.js +80 -0
  8. package/cjs/constants/permissions.js +65 -11
  9. package/cjs/decorators/index.js +1 -0
  10. package/cjs/decorators/log-action.decorator.js +149 -0
  11. package/cjs/dtos/response-payload.dto.js +72 -0
  12. package/cjs/enums/index.js +20 -0
  13. package/cjs/enums/notification-type.enum.js +17 -0
  14. package/cjs/enums/participant-status.enum.js +17 -0
  15. package/cjs/enums/recurrence-type.enum.js +18 -0
  16. package/cjs/exceptions/base-app.exception.js +145 -0
  17. package/cjs/exceptions/index.js +1 -0
  18. package/cjs/exceptions/permission.exception.js +12 -8
  19. package/cjs/filters/global-exception.filter.js +167 -0
  20. package/cjs/filters/index.js +18 -0
  21. package/cjs/guards/jwt-auth.guard.js +4 -1
  22. package/cjs/guards/permission.guard.js +6 -13
  23. package/cjs/index.js +2 -0
  24. package/cjs/interceptors/idempotency.interceptor.js +1 -1
  25. package/cjs/interceptors/index.js +0 -1
  26. package/cjs/interfaces/event-manager-adapter.interface.js +11 -0
  27. package/cjs/interfaces/index.js +2 -0
  28. package/cjs/interfaces/logger.interface.js +1 -4
  29. package/cjs/interfaces/notification-adapter.interface.js +11 -0
  30. package/cjs/middlewares/logger.middleware.js +83 -26
  31. package/cjs/modules/datasource/multi-tenant-datasource.service.js +33 -11
  32. package/cjs/modules/utils/utils.service.js +4 -20
  33. package/cjs/utils/index.js +0 -1
  34. package/cjs/utils/query-helpers.util.js +8 -1
  35. package/classes/api-controller.class.d.ts +1 -0
  36. package/classes/api-service.class.d.ts +5 -10
  37. package/classes/winston-logger-adapter.class.d.ts +12 -11
  38. package/classes/winston.logger.class.d.ts +1 -0
  39. package/constants/index.d.ts +1 -0
  40. package/constants/message-keys.d.ts +81 -0
  41. package/constants/permissions.d.ts +72 -0
  42. package/decorators/index.d.ts +1 -0
  43. package/decorators/log-action.decorator.d.ts +8 -0
  44. package/dtos/response-payload.dto.d.ts +8 -0
  45. package/enums/index.d.ts +3 -0
  46. package/enums/notification-type.enum.d.ts +6 -0
  47. package/enums/participant-status.enum.d.ts +6 -0
  48. package/enums/recurrence-type.enum.d.ts +7 -0
  49. package/exceptions/base-app.exception.d.ts +41 -0
  50. package/exceptions/index.d.ts +1 -0
  51. package/exceptions/permission.exception.d.ts +1 -1
  52. package/fesm/classes/api-controller.class.js +26 -8
  53. package/fesm/classes/api-service.class.js +101 -18
  54. package/fesm/classes/winston-logger-adapter.class.js +18 -44
  55. package/fesm/classes/winston.logger.class.js +100 -68
  56. package/fesm/constants/index.js +2 -0
  57. package/fesm/constants/message-keys.js +59 -0
  58. package/fesm/constants/permissions.js +51 -14
  59. package/fesm/decorators/index.js +1 -0
  60. package/fesm/decorators/log-action.decorator.js +139 -0
  61. package/fesm/dtos/response-payload.dto.js +72 -0
  62. package/fesm/enums/index.js +3 -0
  63. package/fesm/enums/notification-type.enum.js +7 -0
  64. package/fesm/enums/participant-status.enum.js +7 -0
  65. package/fesm/enums/recurrence-type.enum.js +8 -0
  66. package/fesm/exceptions/base-app.exception.js +109 -0
  67. package/fesm/exceptions/index.js +1 -0
  68. package/fesm/exceptions/permission.exception.js +15 -17
  69. package/fesm/filters/global-exception.filter.js +157 -0
  70. package/fesm/filters/index.js +1 -0
  71. package/fesm/guards/jwt-auth.guard.js +5 -2
  72. package/fesm/guards/permission.guard.js +8 -15
  73. package/fesm/index.js +2 -0
  74. package/fesm/interceptors/idempotency.interceptor.js +2 -2
  75. package/fesm/interceptors/index.js +0 -1
  76. package/fesm/interfaces/event-manager-adapter.interface.js +1 -0
  77. package/fesm/interfaces/index.js +2 -0
  78. package/fesm/interfaces/logger.interface.js +1 -4
  79. package/fesm/interfaces/notification-adapter.interface.js +1 -0
  80. package/fesm/middlewares/logger.middleware.js +83 -26
  81. package/fesm/modules/datasource/multi-tenant-datasource.service.js +34 -12
  82. package/fesm/modules/utils/utils.service.js +5 -21
  83. package/fesm/utils/index.js +0 -1
  84. package/fesm/utils/query-helpers.util.js +8 -1
  85. package/filters/global-exception.filter.d.ts +10 -0
  86. package/filters/index.d.ts +1 -0
  87. package/guards/permission.guard.d.ts +1 -3
  88. package/index.d.ts +2 -0
  89. package/interceptors/index.d.ts +0 -1
  90. package/interfaces/event-manager-adapter.interface.d.ts +43 -0
  91. package/interfaces/index.d.ts +2 -0
  92. package/interfaces/logger.interface.d.ts +5 -5
  93. package/interfaces/notification-adapter.interface.d.ts +22 -0
  94. package/modules/datasource/multi-tenant-datasource.service.d.ts +1 -2
  95. package/modules/utils/utils.service.d.ts +0 -1
  96. package/package.json +10 -3
  97. package/utils/index.d.ts +0 -1
  98. package/cjs/interceptors/query-performance.interceptor.js +0 -66
  99. package/cjs/utils/error-handler.util.js +0 -90
  100. package/fesm/interceptors/query-performance.interceptor.js +0 -56
  101. package/fesm/utils/error-handler.util.js +0 -82
  102. package/interceptors/query-performance.interceptor.d.ts +0 -8
  103. package/utils/error-handler.util.d.ts +0 -19
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Shared Package Guide
2
2
 
3
3
  > **Package:** `@flusys/nestjs-shared`
4
- > **Version:** 3.0.0
4
+ > **Version:** 3.0.1
5
5
  > **Type:** Shared NestJS utilities, classes, decorators, guards, and modules
6
6
 
7
7
  This comprehensive guide covers the shared package - the shared NestJS infrastructure layer.
@@ -134,7 +134,6 @@ nestjs-shared/
134
134
  │ │ └── utils.service.ts # Cache helpers, string utilities
135
135
  │ │
136
136
  │ └── utils/ # Utility functions
137
- │ ├── error-handler.util.ts # ErrorHandler class
138
137
  │ ├── html-sanitizer.util.ts # escapeHtml, escapeHtmlVariables
139
138
  │ ├── query-helpers.util.ts # applyCompanyFilter, validateCompanyOwnership
140
139
  │ ├── request.util.ts # isBrowserRequest, buildCookieOptions, parseDurationToMs
@@ -582,6 +581,45 @@ export class CreateCommentDto {
582
581
  }
583
582
  ```
584
583
 
584
+ ### @LogAction
585
+
586
+ Method-level logging decorator with automatic correlation context and error handling:
587
+
588
+ ```typescript
589
+ import { LogAction } from '@flusys/nestjs-shared';
590
+
591
+ @Injectable()
592
+ export class UserService {
593
+ // Module name for routing logs to module-specific files (production)
594
+ protected readonly moduleName = 'auth';
595
+
596
+ // Basic usage - logs start, success (with duration), and errors
597
+ @LogAction({ action: 'user.create' })
598
+ async createUser(dto: CreateUserDto): Promise<User> {
599
+ return this.repository.save(dto);
600
+ }
601
+
602
+ // With all options
603
+ @LogAction({
604
+ action: 'user.update', // Action name (default: ClassName.methodName)
605
+ module: 'auth', // Override module routing
606
+ includeParams: true, // Log method parameters (sensitive data redacted)
607
+ includeResult: true, // Log result preview
608
+ logLevel: 'info' // 'debug' | 'info' | 'warn' (default: 'debug')
609
+ })
610
+ async updateUser(dto: UpdateUserDto): Promise<User> {
611
+ return this.repository.save(dto);
612
+ }
613
+ }
614
+ ```
615
+
616
+ **Features:**
617
+ - Automatic start/end logging with duration
618
+ - Error logging with stack trace (then re-throws)
619
+ - Sensitive data redaction (password, secret, token, apiKey, authorization)
620
+ - Request context (requestId, userId, tenantId, companyId)
621
+ - Module-specific log routing (production mode)
622
+
585
623
  ### @ApiResponseDto
586
624
 
587
625
  Generates Swagger schema for response:
@@ -872,20 +910,6 @@ Removes empty/null `id` fields from request body (single objects and arrays).
872
910
  // Output: [{ name: 'A' }, { id: '123', name: 'B' }]
873
911
  ```
874
912
 
875
- ### QueryPerformanceInterceptor
876
-
877
- Monitors endpoint execution time and logs warnings for slow requests.
878
-
879
- ```typescript
880
- import { QueryPerformanceInterceptor } from '@flusys/nestjs-shared';
881
-
882
- // Default threshold: 1000ms
883
- app.useGlobalInterceptors(new QueryPerformanceInterceptor());
884
-
885
- // Custom threshold: 500ms
886
- app.useGlobalInterceptors(new QueryPerformanceInterceptor(500));
887
- ```
888
-
889
913
  ### Slug Interceptor
890
914
 
891
915
  Auto-generates `slug` from `name` field if not provided.
@@ -1202,66 +1226,92 @@ const safeVars = escapeHtmlVariables({
1202
1226
 
1203
1227
  ## Error Handling
1204
1228
 
1205
- ### ErrorHandler Class
1229
+ ### BaseAppException
1206
1230
 
1207
- Centralized error handling with automatic sensitive data redaction.
1231
+ Structured exceptions with i18n support and validation errors:
1208
1232
 
1209
1233
  ```typescript
1210
- import { ErrorHandler, IErrorContext } from '@flusys/nestjs-shared';
1211
- import { Logger } from '@nestjs/common';
1234
+ import {
1235
+ BaseAppException,
1236
+ NotFoundException,
1237
+ ValidationException,
1238
+ UnauthorizedException,
1239
+ ForbiddenException,
1240
+ ConflictException,
1241
+ InternalServerException,
1242
+ ServiceUnavailableException,
1243
+ IValidationError,
1244
+ } from '@flusys/nestjs-shared';
1212
1245
 
1213
- const logger = new Logger('MyService');
1246
+ // Custom exception with all options
1247
+ throw new BaseAppException({
1248
+ message: 'User registration failed',
1249
+ code: 'REGISTRATION_FAILED',
1250
+ messageKey: 'error.registration.failed', // For i18n
1251
+ status: HttpStatus.BAD_REQUEST,
1252
+ errors: [
1253
+ { field: 'email', message: 'Email already exists', code: 'DUPLICATE_EMAIL' }
1254
+ ],
1255
+ metadata: { attemptedEmail: email },
1256
+ });
1214
1257
 
1215
- // Error context interface
1216
- interface IErrorContext {
1217
- operation?: string;
1218
- entity?: string;
1219
- userId?: string;
1220
- id?: string;
1221
- companyId?: string;
1222
- branchId?: string;
1223
- sectionId?: string;
1224
- data?: Record<string, unknown>;
1225
- }
1258
+ // Pre-built exceptions
1259
+ throw new NotFoundException('User', userId);
1260
+ // → { message: "User with id 'abc' not found", code: "NOT_FOUND", messageKey: "error.notFound" }
1226
1261
 
1227
- // Safe error message extraction from unknown error
1228
- const message = ErrorHandler.getErrorMessage(error);
1229
- // Returns: 'Error message' | 'Unknown error occurred'
1262
+ throw new ValidationException([
1263
+ { field: 'email', message: 'Invalid format' },
1264
+ { field: 'password', message: 'Too short' },
1265
+ ]);
1230
1266
 
1231
- // Log error with sensitive key redaction
1232
- // Automatically redacts: password, secret, token, apiKey, credential, authorization
1233
- ErrorHandler.logError(logger, error, 'createUser', {
1234
- entity: 'User',
1235
- userId: user.id,
1236
- data: { email: 'test@example.com', password: 'secret123' }, // password will be [REDACTED]
1237
- });
1267
+ throw new UnauthorizedException('Invalid credentials');
1268
+ throw new ForbiddenException('Admin access required');
1269
+ throw new ConflictException('User', 'email');
1270
+ throw new InternalServerException('Database connection failed');
1271
+ throw new ServiceUnavailableException('Email Service');
1272
+ ```
1238
1273
 
1239
- // Type-safe rethrow (preserves Error instances, wraps others)
1240
- ErrorHandler.rethrowError(error); // throws: never
1274
+ ### GlobalExceptionFilter
1241
1275
 
1242
- // Combined log + rethrow (common pattern)
1243
- ErrorHandler.logAndRethrow(logger, error, 'updateUser', { entity: 'User', id: userId });
1276
+ Unified exception handling with structured responses and logging:
1244
1277
 
1245
- // Typical usage in service
1246
- async createUser(dto: CreateUserDto): Promise<User> {
1247
- try {
1248
- return await this.repository.save(dto);
1249
- } catch (error) {
1250
- ErrorHandler.logAndRethrow(this.logger, error, 'createUser', {
1251
- entity: 'User',
1252
- data: dto,
1253
- });
1278
+ ```typescript
1279
+ import { GlobalExceptionFilter } from '@flusys/nestjs-shared';
1280
+
1281
+ // Register in main.ts
1282
+ app.useGlobalFilters(new GlobalExceptionFilter());
1283
+
1284
+ // Or in app.module.ts
1285
+ @Module({
1286
+ providers: [
1287
+ { provide: APP_FILTER, useClass: GlobalExceptionFilter },
1288
+ ],
1289
+ })
1290
+ export class AppModule {}
1291
+ ```
1292
+
1293
+ **Response format (all errors):**
1294
+ ```json
1295
+ {
1296
+ "success": false,
1297
+ "message": "User with id 'abc' not found",
1298
+ "code": "NOT_FOUND",
1299
+ "messageKey": "error.notFound",
1300
+ "errors": [...],
1301
+ "_meta": {
1302
+ "requestId": "uuid",
1303
+ "timestamp": "2024-01-15T10:30:00.000Z",
1304
+ "responseTime": 45
1254
1305
  }
1255
1306
  }
1256
1307
  ```
1257
1308
 
1258
- **Sensitive Keys (automatically redacted in logs):**
1259
- - `password`
1260
- - `secret`
1261
- - `token`
1262
- - `apiKey`
1263
- - `credential`
1264
- - `authorization`
1309
+ **Features:**
1310
+ - Consistent error response format
1311
+ - Request correlation (requestId, userId, tenantId)
1312
+ - Log level by status (500+ → error, 400+ → warn)
1313
+ - Handles BaseAppException, HttpException, and generic errors
1314
+ - class-validator error transformation
1265
1315
 
1266
1316
  ---
1267
1317
 
@@ -1376,11 +1426,34 @@ type PermissionCode = 'user.create' | 'user.read' | ... ; // Union of all permis
1376
1426
  Production-ready logging with tenant-aware routing and daily rotation.
1377
1427
 
1378
1428
  **Configuration via environment:**
1379
- - `LOG_DIR` - Directory for log files (default: `logs/`)
1380
- - `LOG_LEVEL` - Minimum log level (default: `info`)
1381
- - `LOG_MAX_SIZE` - Max file size before rotation
1382
- - `LOG_MAX_FILES` - Max number of log files to keep
1383
- - `USE_TENANT_MODE` - Enable tenant-aware log routing
1429
+ | Variable | Description | Default |
1430
+ |----------|-------------|---------|
1431
+ | `LOG_DIR` | Directory for log files | `logs/` |
1432
+ | `LOG_LEVEL` | Minimum log level | `info` (prod), `debug` (dev) |
1433
+ | `LOG_MAX_SIZE` | Max file size before rotation | `20m` |
1434
+ | `LOG_MAX_FILES` | Max number of log files to keep | `14d` |
1435
+ | `USE_TENANT_MODE` | Enable tenant-aware log routing | `false` |
1436
+ | `DISABLE_HTTP_LOGGING` | Disable HTTP request/response logs | `false` |
1437
+
1438
+ **Disable HTTP Logging:**
1439
+ ```bash
1440
+ # .env - Disable middleware HTTP logs (keep service-level @LogAction logs)
1441
+ DISABLE_HTTP_LOGGING=true
1442
+ ```
1443
+
1444
+ When disabled, LoggerMiddleware skips request/response logging but preserves:
1445
+ - `@LogAction` decorator logs
1446
+ - Manual `logger.log()` calls
1447
+ - Error logs from GlobalExceptionFilter
1448
+
1449
+ **Log Format (Production):**
1450
+ ```
1451
+ ────────────────────────────────────────────────────────────────────────────────
1452
+ 2024-01-15 10:30:45.123 | Information | [request-uuid]
1453
+ Context: HTTP | Endpoint: POST /api/users | Status: 200 | Duration: 45ms
1454
+ Request finished "HTTP/1.1" "POST" "/api/users" - 200 534 "application/json" 45.00ms
1455
+ Metadata: {"userId":"user-123","tenantId":"tenant-1"}
1456
+ ```
1384
1457
 
1385
1458
  **Logger Modes:**
1386
1459
 
@@ -1464,6 +1537,8 @@ import {
1464
1537
  SanitizeAndTrim,
1465
1538
  ApiResponseDto,
1466
1539
  ArrayResponseType,
1540
+ LogAction,
1541
+ ILogActionOptions,
1467
1542
 
1468
1543
  // Guards
1469
1544
  JwtAuthGuard,
@@ -1477,7 +1552,6 @@ import {
1477
1552
  SetDeletedByOnBody,
1478
1553
  createSetUserFieldInterceptor, // Factory function
1479
1554
  DeleteEmptyIdFromBodyInterceptor,
1480
- QueryPerformanceInterceptor,
1481
1555
  Slug,
1482
1556
 
1483
1557
  // Modules
@@ -1532,7 +1606,20 @@ import {
1532
1606
  getUserId,
1533
1607
  getCompanyId,
1534
1608
 
1609
+ // Filters
1610
+ GlobalExceptionFilter,
1611
+
1535
1612
  // Exceptions
1613
+ BaseAppException,
1614
+ IBaseAppExceptionOptions,
1615
+ IValidationError,
1616
+ NotFoundException,
1617
+ ValidationException,
1618
+ UnauthorizedException,
1619
+ ForbiddenException,
1620
+ ConflictException,
1621
+ InternalServerException,
1622
+ ServiceUnavailableException,
1536
1623
  InsufficientPermissionsException,
1537
1624
  NoPermissionsFoundException,
1538
1625
  PermissionSystemUnavailableException,
@@ -1569,8 +1656,6 @@ import {
1569
1656
  FORM_RESULT_PERMISSIONS,
1570
1657
 
1571
1658
  // Utilities
1572
- ErrorHandler,
1573
- IErrorContext,
1574
1659
  escapeHtml,
1575
1660
  escapeHtmlVariables,
1576
1661
  applyCompanyFilter,
@@ -1758,18 +1843,13 @@ validateCompanyOwnership(entity, user, this.config.isCompanyFeatureEnabled(), 'P
1758
1843
  ### 7. Error Handling Pattern
1759
1844
 
1760
1845
  ```typescript
1761
- import { ErrorHandler } from '@flusys/nestjs-shared';
1846
+ import { LogAction } from '@flusys/nestjs-shared';
1762
1847
 
1763
- // Use ErrorHandler for consistent logging with sensitive data redaction
1848
+ // Use @LogAction for consistent logging with sensitive data redaction
1849
+ @LogAction({ action: 'user.create', includeParams: false })
1764
1850
  async createUser(dto: CreateUserDto): Promise<User> {
1765
- try {
1766
- return await this.repository.save(dto);
1767
- } catch (error) {
1768
- ErrorHandler.logAndRethrow(this.logger, error, 'createUser', {
1769
- entity: 'User',
1770
- data: dto, // Sensitive fields auto-redacted
1771
- });
1772
- }
1851
+ return this.repository.save(dto);
1852
+ // Errors automatically logged with stack trace, then re-thrown
1773
1853
  }
1774
1854
  ```
1775
1855
 
@@ -88,6 +88,8 @@ function _ts_param(paramIndex, decorator) {
88
88
  return (0, _common.applyDecorators)(...decorators);
89
89
  }
90
90
  function createApiController(createDtoClass, updateDtoClass, responseDtoClass, options = {}) {
91
+ // Entity name for message keys (defaults to 'item')
92
+ const entityName = options.entityName ?? 'item';
91
93
  // Determine if security is global (applies to all) or per-endpoint
92
94
  const securityConfig = options.security;
93
95
  const endpointKeys = [
@@ -124,7 +126,8 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
124
126
  const data = (0, _classtransformer.plainToInstance)(responseDtoClass, entity);
125
127
  return {
126
128
  success: true,
127
- message: 'Item created successfully',
129
+ message: `${entityName.charAt(0).toUpperCase() + entityName.slice(1)} created successfully`,
130
+ messageKey: `${entityName}.create.success`,
128
131
  data
129
132
  };
130
133
  }
@@ -133,7 +136,11 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
133
136
  const data = entities.map((item)=>(0, _classtransformer.plainToInstance)(responseDtoClass, item));
134
137
  return {
135
138
  success: true,
136
- message: `${data.length} items created successfully`,
139
+ message: `${data.length} ${entityName}s created successfully`,
140
+ messageKey: `${entityName}.create.many.success`,
141
+ messageVariables: {
142
+ count: data.length
143
+ },
137
144
  data,
138
145
  meta: {
139
146
  count: data.length,
@@ -147,7 +154,8 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
147
154
  const data = (0, _classtransformer.plainToInstance)(responseDtoClass, entity);
148
155
  return {
149
156
  success: true,
150
- message: 'Item retrieved successfully',
157
+ message: `${entityName.charAt(0).toUpperCase() + entityName.slice(1)} retrieved successfully`,
158
+ messageKey: `${entityName}.get.success`,
151
159
  data
152
160
  };
153
161
  }
@@ -156,7 +164,8 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
156
164
  const data = (0, _classtransformer.plainToInstance)(responseDtoClass, entity);
157
165
  return {
158
166
  success: true,
159
- message: 'Item updated successfully',
167
+ message: `${entityName.charAt(0).toUpperCase() + entityName.slice(1)} updated successfully`,
168
+ messageKey: `${entityName}.update.success`,
160
169
  data
161
170
  };
162
171
  }
@@ -165,7 +174,11 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
165
174
  const data = (0, _classtransformer.plainToInstance)(responseDtoClass, entities);
166
175
  return {
167
176
  success: true,
168
- message: `${data.length} items updated successfully`,
177
+ message: `${data.length} ${entityName}s updated successfully`,
178
+ messageKey: `${entityName}.update.many.success`,
179
+ messageVariables: {
180
+ count: data.length
181
+ },
169
182
  data,
170
183
  meta: {
171
184
  count: data.length,
@@ -182,7 +195,8 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
182
195
  const totalPages = pageSize > 0 ? Math.ceil(result.total / pageSize) : 1;
183
196
  return {
184
197
  success: true,
185
- message: 'Data retrieved successfully',
198
+ message: `${entityName.charAt(0).toUpperCase() + entityName.slice(1)}s retrieved successfully`,
199
+ messageKey: `${entityName}.get.all.success`,
186
200
  data,
187
201
  meta: {
188
202
  total: result.total,
@@ -197,10 +211,14 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
197
211
  async delete(deleteDto, user) {
198
212
  await this.service.delete(deleteDto, user);
199
213
  const count = Array.isArray(deleteDto.id) ? deleteDto.id.length : 1;
200
- const action = deleteDto.type === 'restore' ? 'restored' : 'deleted';
214
+ const action = deleteDto.type === 'restore' ? 'restore' : 'delete';
201
215
  return {
202
216
  success: true,
203
- message: `${count} item${count > 1 ? 's' : ''} ${action} successfully`
217
+ message: `${count} ${entityName}${count > 1 ? 's' : ''} ${action}d successfully`,
218
+ messageKey: `${entityName}.${action}.success`,
219
+ messageVariables: {
220
+ count
221
+ }
204
222
  };
205
223
  }
206
224
  constructor(service){
@@ -8,9 +8,11 @@ Object.defineProperty(exports, "ApiService", {
8
8
  return ApiService;
9
9
  }
10
10
  });
11
- const _errorhandlerutil = require("../utils/error-handler.util");
11
+ const _dtos = require("../dtos");
12
12
  const _common = require("@nestjs/common");
13
+ const _constants = require("../constants");
13
14
  const _typeorm = require("typeorm");
15
+ const _logactiondecorator = require("../decorators/log-action.decorator");
14
16
  function _define_property(obj, key, value) {
15
17
  if (key in obj) {
16
18
  Object.defineProperty(obj, key, {
@@ -24,6 +26,15 @@ function _define_property(obj, key, value) {
24
26
  }
25
27
  return obj;
26
28
  }
29
+ function _ts_decorate(decorators, target, key, desc) {
30
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
31
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
32
+ 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;
33
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
34
+ }
35
+ function _ts_metadata(k, v) {
36
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
37
+ }
27
38
  let ApiService = class ApiService {
28
39
  async insert(dto, user) {
29
40
  return this.executeInTransaction('insert', async (qr)=>{
@@ -88,7 +99,10 @@ let ApiService = class ApiService {
88
99
  output = await finalQuery.getMany();
89
100
  }
90
101
  const result = this.convertEntityListToResponseListDto(output, isRaw);
91
- if (!result || !result.length) throw new _common.NotFoundException('No Data Found');
102
+ if (!result || !result.length) throw new _common.NotFoundException({
103
+ message: 'No Data Found',
104
+ messageKey: _constants.SYSTEM_MESSAGES.NOT_FOUND
105
+ });
92
106
  return result;
93
107
  } catch (error) {
94
108
  if (error instanceof _common.NotFoundException) {
@@ -119,7 +133,10 @@ let ApiService = class ApiService {
119
133
  if (convertResult.length) result = convertResult[0];
120
134
  } else {
121
135
  output = await finalQuery.getOne();
122
- if (!output) throw new _common.NotFoundException('No Data Found');
136
+ if (!output) throw new _common.NotFoundException({
137
+ message: 'No Data Found',
138
+ messageKey: _constants.SYSTEM_MESSAGES.NOT_FOUND
139
+ });
123
140
  result = this.convertEntityToResponseDto(output, false);
124
141
  }
125
142
  if (this.isCacheable) {
@@ -209,7 +226,15 @@ let ApiService = class ApiService {
209
226
  const parameters = rawSubQuery.getParameters();
210
227
  const orderedValues = [];
211
228
  const convertedQuery = countSql.replace(/:(\w+)/g, (_, key)=>{
212
- if (!(key in parameters)) throw new Error(`Missing parameter value for: ${key}`);
229
+ if (!(key in parameters)) {
230
+ throw new _common.InternalServerErrorException({
231
+ message: `Missing parameter value for: ${key}`,
232
+ messageKey: _constants.SYSTEM_MESSAGES.MISSING_PARAMETER,
233
+ messageParams: {
234
+ key
235
+ }
236
+ });
237
+ }
213
238
  orderedValues.push(parameters[key]);
214
239
  return '?';
215
240
  });
@@ -282,13 +307,14 @@ let ApiService = class ApiService {
282
307
  async clearCacheForId(entities) {
283
308
  await Promise.all(entities.map((item)=>this.utilsService.clearCache(this.entityName, this.cacheManager, item.id)));
284
309
  }
285
- /**
286
- * Helper method to handle errors with proper logging and type safety
287
- */ handleError(error, operation) {
288
- _errorhandlerutil.ErrorHandler.logError(this.logger, error, operation, {
289
- entity: this.entityName
310
+ handleError(error, _operation) {
311
+ if (error instanceof Error) {
312
+ throw error;
313
+ }
314
+ throw new _common.InternalServerErrorException({
315
+ message: typeof error === 'string' ? error : 'Unknown error',
316
+ messageKey: _constants.SYSTEM_MESSAGES.INTERNAL_ERROR
290
317
  });
291
- _errorhandlerutil.ErrorHandler.rethrowError(error);
292
318
  }
293
319
  /** Ensures value is always an array */ ensureArray(value) {
294
320
  return Array.isArray(value) ? value : [
@@ -385,7 +411,10 @@ let ApiService = class ApiService {
385
411
  id: d.id
386
412
  }
387
413
  });
388
- if (!existing) throw new _common.NotFoundException('No such entity data found for update! Please, Try Again.');
414
+ if (!existing) throw new _common.NotFoundException({
415
+ message: 'No such entity data found for update! Please, Try Again.',
416
+ messageKey: _constants.SYSTEM_MESSAGES.NOT_FOUND
417
+ });
389
418
  return Object.assign(existing, d);
390
419
  }
391
420
  delete d.id;
@@ -403,21 +432,75 @@ let ApiService = class ApiService {
403
432
  async getEntityClass() {
404
433
  return await this.repository.create();
405
434
  }
406
- constructor(entityName, repository, cacheManager, utilsService, loggerName, isCacheable = false){
435
+ constructor(entityName, repository, cacheManager, utilsService, _loggerName, isCacheable = false, moduleName){
407
436
  _define_property(this, "entityName", void 0);
408
437
  _define_property(this, "repository", void 0);
409
438
  _define_property(this, "cacheManager", void 0);
410
439
  _define_property(this, "utilsService", void 0);
411
- _define_property(this, "loggerName", void 0);
440
+ _define_property(this, "_loggerName", void 0);
412
441
  _define_property(this, "isCacheable", void 0);
413
- _define_property(this, "logger", void 0);
442
+ _define_property(this, "moduleName", void 0);
414
443
  this.entityName = entityName;
415
444
  this.repository = repository;
416
445
  this.cacheManager = cacheManager;
417
446
  this.utilsService = utilsService;
418
- this.loggerName = loggerName;
447
+ this._loggerName = _loggerName;
419
448
  this.isCacheable = isCacheable;
420
- this.logger = new _common.Logger('ApiService');
421
- this.logger = new _common.Logger(loggerName);
449
+ this.moduleName = moduleName;
422
450
  }
423
451
  };
452
+ _ts_decorate([
453
+ (0, _logactiondecorator.LogAction)({
454
+ action: 'create'
455
+ }),
456
+ _ts_metadata("design:type", Function),
457
+ _ts_metadata("design:paramtypes", [
458
+ typeof CreateDtoT === "undefined" ? Object : CreateDtoT,
459
+ Object
460
+ ]),
461
+ _ts_metadata("design:returntype", Promise)
462
+ ], ApiService.prototype, "insert", null);
463
+ _ts_decorate([
464
+ (0, _logactiondecorator.LogAction)({
465
+ action: 'createMany'
466
+ }),
467
+ _ts_metadata("design:type", Function),
468
+ _ts_metadata("design:paramtypes", [
469
+ typeof Array === "undefined" ? Object : Array,
470
+ Object
471
+ ]),
472
+ _ts_metadata("design:returntype", Promise)
473
+ ], ApiService.prototype, "insertMany", null);
474
+ _ts_decorate([
475
+ (0, _logactiondecorator.LogAction)({
476
+ action: 'update'
477
+ }),
478
+ _ts_metadata("design:type", Function),
479
+ _ts_metadata("design:paramtypes", [
480
+ typeof UpdateDtoT === "undefined" ? Object : UpdateDtoT,
481
+ Object
482
+ ]),
483
+ _ts_metadata("design:returntype", Promise)
484
+ ], ApiService.prototype, "update", null);
485
+ _ts_decorate([
486
+ (0, _logactiondecorator.LogAction)({
487
+ action: 'updateMany'
488
+ }),
489
+ _ts_metadata("design:type", Function),
490
+ _ts_metadata("design:paramtypes", [
491
+ Array,
492
+ Object
493
+ ]),
494
+ _ts_metadata("design:returntype", Promise)
495
+ ], ApiService.prototype, "updateMany", null);
496
+ _ts_decorate([
497
+ (0, _logactiondecorator.LogAction)({
498
+ action: 'delete'
499
+ }),
500
+ _ts_metadata("design:type", Function),
501
+ _ts_metadata("design:paramtypes", [
502
+ typeof _dtos.DeleteDto === "undefined" ? Object : _dtos.DeleteDto,
503
+ Object
504
+ ]),
505
+ _ts_metadata("design:returntype", Promise)
506
+ ], ApiService.prototype, "delete", null);
@@ -31,20 +31,13 @@ function _define_property(obj, key, value) {
31
31
  }
32
32
  return obj;
33
33
  }
34
- /**
35
- * Get correlation context for logging
36
- * Automatically includes requestId, userId, tenantId, companyId if available
37
- */ function getCorrelationMeta() {
38
- const meta = {};
39
- const requestId = (0, _loggermiddleware.getRequestId)();
40
- const userId = (0, _loggermiddleware.getUserId)();
41
- const tenantId = (0, _loggermiddleware.getTenantId)();
42
- const companyId = (0, _loggermiddleware.getCompanyId)();
43
- if (requestId) meta.requestId = requestId;
44
- if (userId) meta.userId = userId;
45
- if (tenantId) meta.tenantId = tenantId;
46
- if (companyId) meta.companyId = companyId;
47
- return meta;
34
+ function getCorrelationMeta() {
35
+ return Object.fromEntries(Object.entries({
36
+ requestId: (0, _loggermiddleware.getRequestId)(),
37
+ userId: (0, _loggermiddleware.getUserId)(),
38
+ tenantId: (0, _loggermiddleware.getTenantId)(),
39
+ companyId: (0, _loggermiddleware.getCompanyId)()
40
+ }).filter(([, v])=>v != null));
48
41
  }
49
42
  let WinstonLoggerAdapter = class WinstonLoggerAdapter {
50
43
  buildLogMeta(context, args, extra) {
@@ -57,25 +50,27 @@ let WinstonLoggerAdapter = class WinstonLoggerAdapter {
57
50
  };
58
51
  }
59
52
  log(message, context, ...args) {
60
- _winstonloggerclass.instance.info(message, this.buildLogMeta(context, args));
53
+ this.logger.info(message, this.buildLogMeta(context, args));
61
54
  }
62
55
  error(message, trace, context, ...args) {
63
- _winstonloggerclass.instance.error(message, this.buildLogMeta(context, args, {
56
+ this.logger.error(message, this.buildLogMeta(context, args, {
64
57
  stack: trace
65
58
  }));
66
59
  }
67
60
  warn(message, context, ...args) {
68
- _winstonloggerclass.instance.warn(message, this.buildLogMeta(context, args));
61
+ this.logger.warn(message, this.buildLogMeta(context, args));
69
62
  }
70
63
  debug(message, context, ...args) {
71
- _winstonloggerclass.instance.debug(message, this.buildLogMeta(context, args));
64
+ this.logger.debug(message, this.buildLogMeta(context, args));
72
65
  }
73
66
  verbose(message, context, ...args) {
74
- _winstonloggerclass.instance.verbose(message, this.buildLogMeta(context, args));
67
+ this.logger.verbose(message, this.buildLogMeta(context, args));
75
68
  }
76
- constructor(context){
69
+ constructor(context, moduleName){
77
70
  _define_property(this, "context", void 0);
71
+ _define_property(this, "logger", void 0);
78
72
  this.context = context;
73
+ this.logger = moduleName ? (0, _winstonloggerclass.createModuleLogger)(moduleName) : _winstonloggerclass.instance;
79
74
  }
80
75
  };
81
76
  let NestLoggerAdapter = class NestLoggerAdapter {