@flusys/nestjs-shared 4.1.0 → 5.0.0
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 +96 -606
- package/cjs/classes/api-controller.class.js +81 -10
- package/cjs/classes/api-service.class.js +9 -7
- package/cjs/classes/index.js +0 -1
- package/cjs/constants/index.js +0 -4
- package/cjs/constants/message-keys.js +3 -21
- package/cjs/constants/permissions.js +0 -10
- package/cjs/decorators/api-response.decorator.js +1 -2
- package/cjs/decorators/index.js +0 -1
- package/cjs/decorators/require-permission.decorator.js +0 -4
- package/cjs/exceptions/base-app.exception.js +4 -4
- package/cjs/exceptions/permission.exception.js +1 -1
- package/cjs/filters/global-exception.filter.js +4 -4
- package/cjs/interfaces/index.js +0 -1
- package/cjs/modules/datasource/multi-tenant-datasource.service.js +2 -2
- package/cjs/utils/date-time.util.js +94 -0
- package/cjs/utils/index.js +1 -0
- package/cjs/utils/query-helpers.util.js +2 -2
- package/cjs/utils/request.util.js +25 -0
- package/classes/index.d.ts +0 -1
- package/constants/index.d.ts +0 -1
- package/constants/message-keys.d.ts +2 -44
- package/constants/permissions.d.ts +0 -12
- package/decorators/api-response.decorator.d.ts +1 -1
- package/decorators/index.d.ts +0 -1
- package/decorators/require-permission.decorator.d.ts +0 -1
- package/exceptions/base-app.exception.d.ts +2 -2
- package/fesm/classes/api-controller.class.js +82 -11
- package/fesm/classes/api-service.class.js +10 -8
- package/fesm/classes/index.js +0 -1
- package/fesm/constants/index.js +0 -1
- package/fesm/constants/message-keys.js +3 -19
- package/fesm/constants/permissions.js +0 -7
- package/fesm/decorators/api-response.decorator.js +2 -20
- package/fesm/decorators/index.js +0 -1
- package/fesm/decorators/require-permission.decorator.js +0 -1
- package/fesm/exceptions/base-app.exception.js +4 -4
- package/fesm/exceptions/permission.exception.js +1 -1
- package/fesm/filters/global-exception.filter.js +4 -4
- package/fesm/interfaces/index.js +0 -1
- package/fesm/modules/datasource/multi-tenant-datasource.service.js +2 -2
- package/fesm/utils/date-time.util.js +70 -0
- package/fesm/utils/index.js +1 -0
- package/fesm/utils/query-helpers.util.js +2 -2
- package/fesm/utils/request.util.js +22 -0
- package/interfaces/event-manager-adapter.interface.d.ts +12 -12
- package/interfaces/index.d.ts +0 -1
- package/package.json +2 -2
- package/utils/date-time.util.d.ts +8 -0
- package/utils/index.d.ts +1 -0
- package/utils/request.util.d.ts +2 -0
- package/cjs/classes/winston-logger-adapter.class.js +0 -99
- package/cjs/decorators/sanitize-html.decorator.js +0 -36
- package/cjs/interfaces/logger.interface.js +0 -4
- package/classes/winston-logger-adapter.class.d.ts +0 -23
- package/decorators/sanitize-html.decorator.d.ts +0 -2
- package/fesm/classes/winston-logger-adapter.class.js +0 -81
- package/fesm/decorators/sanitize-html.decorator.js +0 -45
- package/fesm/interfaces/logger.interface.js +0 -1
- package/interfaces/logger.interface.d.ts +0 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const AUTH_MESSAGES: {
|
|
2
2
|
readonly TOKEN_REQUIRED: "auth.token.required";
|
|
3
3
|
readonly TOKEN_INVALID: "auth.token.invalid";
|
|
4
|
-
readonly
|
|
4
|
+
readonly ENTITY_BELOG_ANOTHER_COMPANY: "entity.belongs.another.company";
|
|
5
5
|
readonly COMPANY_NO_ACCESS: "auth.company.no.access";
|
|
6
6
|
};
|
|
7
7
|
export declare const ERROR_MESSAGES: {
|
|
@@ -19,6 +19,7 @@ export declare const ERROR_MESSAGES: {
|
|
|
19
19
|
readonly INSUFFICIENT_PERMISSIONS: "error.insufficient.permissions";
|
|
20
20
|
readonly INSUFFICIENT_PERMISSIONS_OR: "error.insufficient.permissions.or";
|
|
21
21
|
readonly NO_PERMISSIONS_FOUND: "error.no.permissions.found";
|
|
22
|
+
readonly ENDPOINT_DISABLED: "error.endpoint.disabled";
|
|
22
23
|
};
|
|
23
24
|
export declare const SYSTEM_MESSAGES: {
|
|
24
25
|
readonly REPOSITORY_NOT_AVAILABLE: "system.repository.not.available";
|
|
@@ -27,7 +28,6 @@ export declare const SYSTEM_MESSAGES: {
|
|
|
27
28
|
readonly SERVICE_NOT_AVAILABLE: "system.service.not.available";
|
|
28
29
|
readonly CONFIG_REQUIRED: "system.config.required";
|
|
29
30
|
readonly INTERNAL_ERROR: "system.internal.error";
|
|
30
|
-
readonly NOT_FOUND: "system.not.found";
|
|
31
31
|
readonly DUPLICATE_REQUEST: "system.duplicate.request";
|
|
32
32
|
readonly INVALID_TENANT_ID: "system.invalid.tenant.id";
|
|
33
33
|
readonly TENANT_NOT_FOUND: "system.tenant.not.found";
|
|
@@ -37,45 +37,3 @@ export declare const SYSTEM_MESSAGES: {
|
|
|
37
37
|
readonly PATH_TRAVERSAL_DETECTED: "system.path.traversal.detected";
|
|
38
38
|
readonly INVALID_FILE_KEY: "system.invalid.file.key";
|
|
39
39
|
};
|
|
40
|
-
export declare const MESSAGE_KEYS: {
|
|
41
|
-
readonly AUTH: {
|
|
42
|
-
readonly TOKEN_REQUIRED: "auth.token.required";
|
|
43
|
-
readonly TOKEN_INVALID: "auth.token.invalid";
|
|
44
|
-
readonly TOKEN_EXPIRED: "auth.token.expired";
|
|
45
|
-
readonly COMPANY_NO_ACCESS: "auth.company.no.access";
|
|
46
|
-
};
|
|
47
|
-
readonly ERROR: {
|
|
48
|
-
readonly NOT_FOUND: "error.not.found";
|
|
49
|
-
readonly VALIDATION: "error.validation";
|
|
50
|
-
readonly UNAUTHORIZED: "error.unauthorized";
|
|
51
|
-
readonly FORBIDDEN: "error.forbidden";
|
|
52
|
-
readonly CONFLICT: "error.conflict";
|
|
53
|
-
readonly INTERNAL: "error.internal";
|
|
54
|
-
readonly SERVICE_UNAVAILABLE: "error.service.unavailable";
|
|
55
|
-
readonly UNKNOWN: "error.unknown";
|
|
56
|
-
readonly HTTP: "error.http";
|
|
57
|
-
readonly GENERIC: "error.generic";
|
|
58
|
-
readonly PERMISSION_SYSTEM_UNAVAILABLE: "error.permission.system.unavailable";
|
|
59
|
-
readonly INSUFFICIENT_PERMISSIONS: "error.insufficient.permissions";
|
|
60
|
-
readonly INSUFFICIENT_PERMISSIONS_OR: "error.insufficient.permissions.or";
|
|
61
|
-
readonly NO_PERMISSIONS_FOUND: "error.no.permissions.found";
|
|
62
|
-
};
|
|
63
|
-
readonly SYSTEM: {
|
|
64
|
-
readonly REPOSITORY_NOT_AVAILABLE: "system.repository.not.available";
|
|
65
|
-
readonly DATASOURCE_NOT_AVAILABLE: "system.datasource.not.available";
|
|
66
|
-
readonly DATABASE_CONFIG_NOT_AVAILABLE: "system.database.config.not.available";
|
|
67
|
-
readonly SERVICE_NOT_AVAILABLE: "system.service.not.available";
|
|
68
|
-
readonly CONFIG_REQUIRED: "system.config.required";
|
|
69
|
-
readonly INTERNAL_ERROR: "system.internal.error";
|
|
70
|
-
readonly NOT_FOUND: "system.not.found";
|
|
71
|
-
readonly DUPLICATE_REQUEST: "system.duplicate.request";
|
|
72
|
-
readonly INVALID_TENANT_ID: "system.invalid.tenant.id";
|
|
73
|
-
readonly TENANT_NOT_FOUND: "system.tenant.not.found";
|
|
74
|
-
readonly TENANT_HEADER_REQUIRED: "system.tenant.header.required";
|
|
75
|
-
readonly MISSING_PARAMETER: "system.missing.parameter";
|
|
76
|
-
readonly SDK_NOT_INSTALLED: "system.sdk.not.installed";
|
|
77
|
-
readonly PATH_TRAVERSAL_DETECTED: "system.path.traversal.detected";
|
|
78
|
-
readonly INVALID_FILE_KEY: "system.invalid.file.key";
|
|
79
|
-
};
|
|
80
|
-
};
|
|
81
|
-
export type MessageKey = (typeof MESSAGE_KEYS)[keyof typeof MESSAGE_KEYS][keyof (typeof MESSAGE_KEYS)[keyof typeof MESSAGE_KEYS]];
|
|
@@ -92,12 +92,6 @@ export declare const EVENT_PERMISSIONS: {
|
|
|
92
92
|
readonly UPDATE: "event.update";
|
|
93
93
|
readonly DELETE: "event.delete";
|
|
94
94
|
};
|
|
95
|
-
export declare const EVENT_PARTICIPANT_PERMISSIONS: {
|
|
96
|
-
readonly CREATE: "event-participant.create";
|
|
97
|
-
readonly READ: "event-participant.read";
|
|
98
|
-
readonly UPDATE: "event-participant.update";
|
|
99
|
-
readonly DELETE: "event-participant.delete";
|
|
100
|
-
};
|
|
101
95
|
export declare const NOTIFICATION_PERMISSIONS: {
|
|
102
96
|
readonly CREATE: "notification.create";
|
|
103
97
|
readonly READ: "notification.read";
|
|
@@ -217,12 +211,6 @@ export declare const PERMISSIONS: {
|
|
|
217
211
|
readonly UPDATE: "event.update";
|
|
218
212
|
readonly DELETE: "event.delete";
|
|
219
213
|
};
|
|
220
|
-
readonly EVENT_PARTICIPANT: {
|
|
221
|
-
readonly CREATE: "event-participant.create";
|
|
222
|
-
readonly READ: "event-participant.read";
|
|
223
|
-
readonly UPDATE: "event-participant.update";
|
|
224
|
-
readonly DELETE: "event-participant.delete";
|
|
225
|
-
};
|
|
226
214
|
readonly NOTIFICATION: {
|
|
227
215
|
readonly CREATE: "notification.create";
|
|
228
216
|
readonly READ: "notification.read";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Type } from '@nestjs/common';
|
|
2
|
-
export type ArrayResponseType = 'list' | 'bulk';
|
|
2
|
+
export type ArrayResponseType = 'list' | 'bulk' | 'single';
|
|
3
3
|
export declare const ApiResponseDto: <T extends Type<unknown>>(dto: T, isArray?: boolean, arrayType?: ArrayResponseType) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
|
package/decorators/index.d.ts
CHANGED
|
@@ -2,4 +2,3 @@ import { IPermissionLogic } from '../interfaces/permission.interface';
|
|
|
2
2
|
export declare const RequirePermission: (...permissions: string[]) => import("@nestjs/common").CustomDecorator<string>;
|
|
3
3
|
export declare const RequireAnyPermission: (...permissions: string[]) => import("@nestjs/common").CustomDecorator<string>;
|
|
4
4
|
export declare const RequirePermissionLogic: (logic: IPermissionLogic) => import("@nestjs/common").CustomDecorator<string>;
|
|
5
|
-
export declare const RequirePermissionCondition: (logic: IPermissionLogic) => import("@nestjs/common").CustomDecorator<string>;
|
|
@@ -6,14 +6,14 @@ export interface IValidationError {
|
|
|
6
6
|
export interface IBaseAppExceptionOptions {
|
|
7
7
|
message: string;
|
|
8
8
|
messageKey?: string;
|
|
9
|
-
|
|
9
|
+
messageVariables?: Record<string, unknown>;
|
|
10
10
|
status?: HttpStatus;
|
|
11
11
|
errors?: IValidationError[];
|
|
12
12
|
metadata?: Record<string, unknown>;
|
|
13
13
|
}
|
|
14
14
|
export declare class BaseAppException extends HttpException {
|
|
15
15
|
readonly messageKey: string;
|
|
16
|
-
readonly
|
|
16
|
+
readonly messageVariables?: Record<string, unknown>;
|
|
17
17
|
readonly errors?: IValidationError[];
|
|
18
18
|
readonly metadata?: Record<string, unknown>;
|
|
19
19
|
constructor(options: IBaseAppExceptionOptions);
|
|
@@ -31,7 +31,8 @@ import { plainToInstance } from 'class-transformer';
|
|
|
31
31
|
import { CurrentUser, Public, RequireAnyPermission, RequirePermission, RequirePermissionLogic } from '../decorators';
|
|
32
32
|
import { ApiResponseDto } from '../decorators/api-response.decorator';
|
|
33
33
|
import { DeleteDto, FilterAndPaginationDto, GetByIdBodyDto, GetByIdsDto } from '../dtos';
|
|
34
|
-
import {
|
|
34
|
+
import { BaseAppException, NotFoundException } from '../exceptions';
|
|
35
|
+
import { ERROR_MESSAGES } from '../constants/message-keys';
|
|
35
36
|
import { JwtAuthGuard, PermissionGuard } from '../guards';
|
|
36
37
|
import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpdateByOnBody, Slug } from '../interceptors';
|
|
37
38
|
/**
|
|
@@ -142,7 +143,14 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
142
143
|
}
|
|
143
144
|
async insert(addDto, user) {
|
|
144
145
|
if (!this.isEnabled('insert')) {
|
|
145
|
-
throw new
|
|
146
|
+
throw new BaseAppException({
|
|
147
|
+
message: `Endpoint 'insert' is disabled`,
|
|
148
|
+
messageKey: ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
149
|
+
messageVariables: {
|
|
150
|
+
endpoint: 'insert'
|
|
151
|
+
},
|
|
152
|
+
status: HttpStatus.FORBIDDEN
|
|
153
|
+
});
|
|
146
154
|
}
|
|
147
155
|
const entity = await this.service.insert(addDto, user);
|
|
148
156
|
const data = plainToInstance(responseDtoClass, entity);
|
|
@@ -155,7 +163,14 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
155
163
|
}
|
|
156
164
|
async insertMany(addDto, user) {
|
|
157
165
|
if (!this.isEnabled('insertMany')) {
|
|
158
|
-
throw new
|
|
166
|
+
throw new BaseAppException({
|
|
167
|
+
message: `Endpoint 'insertMany' is disabled`,
|
|
168
|
+
messageKey: ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
169
|
+
messageVariables: {
|
|
170
|
+
endpoint: 'insertMany'
|
|
171
|
+
},
|
|
172
|
+
status: HttpStatus.FORBIDDEN
|
|
173
|
+
});
|
|
159
174
|
}
|
|
160
175
|
const entities = await this.service.insertMany(addDto, user);
|
|
161
176
|
const data = entities.map((item)=>plainToInstance(responseDtoClass, item));
|
|
@@ -176,7 +191,14 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
176
191
|
}
|
|
177
192
|
async getById(id, body, user) {
|
|
178
193
|
if (!this.isEnabled('getById')) {
|
|
179
|
-
throw new
|
|
194
|
+
throw new BaseAppException({
|
|
195
|
+
message: `Endpoint 'getById' is disabled`,
|
|
196
|
+
messageKey: ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
197
|
+
messageVariables: {
|
|
198
|
+
endpoint: 'getById'
|
|
199
|
+
},
|
|
200
|
+
status: HttpStatus.FORBIDDEN
|
|
201
|
+
});
|
|
180
202
|
}
|
|
181
203
|
const entity = await this.service.findById(id, user, body?.select);
|
|
182
204
|
const data = plainToInstance(responseDtoClass, entity);
|
|
@@ -189,7 +211,14 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
189
211
|
}
|
|
190
212
|
async getByIds(body, user) {
|
|
191
213
|
if (!this.isEnabled('getByIds')) {
|
|
192
|
-
throw new
|
|
214
|
+
throw new BaseAppException({
|
|
215
|
+
message: `Endpoint 'getByIds' is disabled`,
|
|
216
|
+
messageKey: ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
217
|
+
messageVariables: {
|
|
218
|
+
endpoint: 'getByIds'
|
|
219
|
+
},
|
|
220
|
+
status: HttpStatus.FORBIDDEN
|
|
221
|
+
});
|
|
193
222
|
}
|
|
194
223
|
const entities = await this.service.findByIds(body.ids, user, body?.select);
|
|
195
224
|
const data = plainToInstance(responseDtoClass, entities);
|
|
@@ -209,7 +238,14 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
209
238
|
}
|
|
210
239
|
async update(updateDto, user) {
|
|
211
240
|
if (!this.isEnabled('update')) {
|
|
212
|
-
throw new
|
|
241
|
+
throw new BaseAppException({
|
|
242
|
+
message: `Endpoint 'update' is disabled`,
|
|
243
|
+
messageKey: ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
244
|
+
messageVariables: {
|
|
245
|
+
endpoint: 'update'
|
|
246
|
+
},
|
|
247
|
+
status: HttpStatus.FORBIDDEN
|
|
248
|
+
});
|
|
213
249
|
}
|
|
214
250
|
const entity = await this.service.update(updateDto, user);
|
|
215
251
|
const data = plainToInstance(responseDtoClass, entity);
|
|
@@ -222,7 +258,14 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
222
258
|
}
|
|
223
259
|
async updateMany(updateDtos, user) {
|
|
224
260
|
if (!this.isEnabled('updateMany')) {
|
|
225
|
-
throw new
|
|
261
|
+
throw new BaseAppException({
|
|
262
|
+
message: `Endpoint 'updateMany' is disabled`,
|
|
263
|
+
messageKey: ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
264
|
+
messageVariables: {
|
|
265
|
+
endpoint: 'updateMany'
|
|
266
|
+
},
|
|
267
|
+
status: HttpStatus.FORBIDDEN
|
|
268
|
+
});
|
|
226
269
|
}
|
|
227
270
|
const entities = await this.service.updateMany(updateDtos, user);
|
|
228
271
|
const data = plainToInstance(responseDtoClass, entities);
|
|
@@ -243,7 +286,14 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
243
286
|
}
|
|
244
287
|
async bulkUpsert(dtos, user) {
|
|
245
288
|
if (!this.isEnabled('bulkUpsert')) {
|
|
246
|
-
throw new
|
|
289
|
+
throw new BaseAppException({
|
|
290
|
+
message: `Endpoint 'bulkUpsert' is disabled`,
|
|
291
|
+
messageKey: ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
292
|
+
messageVariables: {
|
|
293
|
+
endpoint: 'bulkUpsert'
|
|
294
|
+
},
|
|
295
|
+
status: HttpStatus.FORBIDDEN
|
|
296
|
+
});
|
|
247
297
|
}
|
|
248
298
|
const toInsert = [];
|
|
249
299
|
const toUpdate = [];
|
|
@@ -273,7 +323,14 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
273
323
|
}
|
|
274
324
|
async getByFilter(filter, user) {
|
|
275
325
|
if (!this.isEnabled('getByFilter')) {
|
|
276
|
-
throw new
|
|
326
|
+
throw new BaseAppException({
|
|
327
|
+
message: `Endpoint 'getByFilter' is disabled`,
|
|
328
|
+
messageKey: ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
329
|
+
messageVariables: {
|
|
330
|
+
endpoint: 'getByFilter'
|
|
331
|
+
},
|
|
332
|
+
status: HttpStatus.FORBIDDEN
|
|
333
|
+
});
|
|
277
334
|
}
|
|
278
335
|
const result = await this.service.getAll('', {
|
|
279
336
|
filter,
|
|
@@ -296,7 +353,14 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
296
353
|
}
|
|
297
354
|
async getAll(filterAndPaginationDto, user, search) {
|
|
298
355
|
if (!this.isEnabled('getAll')) {
|
|
299
|
-
throw new
|
|
356
|
+
throw new BaseAppException({
|
|
357
|
+
message: `Endpoint 'getAll' is disabled`,
|
|
358
|
+
messageKey: ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
359
|
+
messageVariables: {
|
|
360
|
+
endpoint: 'getAll'
|
|
361
|
+
},
|
|
362
|
+
status: HttpStatus.FORBIDDEN
|
|
363
|
+
});
|
|
300
364
|
}
|
|
301
365
|
const result = await this.service.getAll(search ?? '', filterAndPaginationDto, user);
|
|
302
366
|
const data = plainToInstance(responseDtoClass, result.data);
|
|
@@ -320,7 +384,14 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
320
384
|
}
|
|
321
385
|
async delete(deleteDto, user) {
|
|
322
386
|
if (!this.isEnabled('delete')) {
|
|
323
|
-
throw new
|
|
387
|
+
throw new BaseAppException({
|
|
388
|
+
message: `Endpoint 'delete' is disabled`,
|
|
389
|
+
messageKey: ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
390
|
+
messageVariables: {
|
|
391
|
+
endpoint: 'delete'
|
|
392
|
+
},
|
|
393
|
+
status: HttpStatus.FORBIDDEN
|
|
394
|
+
});
|
|
324
395
|
}
|
|
325
396
|
await this.service.delete(deleteDto, user);
|
|
326
397
|
const count = Array.isArray(deleteDto.id) ? deleteDto.id.length : 1;
|
|
@@ -22,7 +22,7 @@ function _ts_metadata(k, v) {
|
|
|
22
22
|
}
|
|
23
23
|
import { InternalServerErrorException, NotFoundException } from '@nestjs/common';
|
|
24
24
|
import { In } from 'typeorm';
|
|
25
|
-
import { SYSTEM_MESSAGES } from '../constants';
|
|
25
|
+
import { ERROR_MESSAGES, SYSTEM_MESSAGES } from '../constants';
|
|
26
26
|
import { LogAction } from '../decorators/log-action.decorator';
|
|
27
27
|
import { DeleteDto } from '../dtos';
|
|
28
28
|
/** Generic API service with CRUD operations and caching support */ export class ApiService {
|
|
@@ -115,7 +115,7 @@ import { DeleteDto } from '../dtos';
|
|
|
115
115
|
const result = this.convertEntityListToResponseListDto(output, isRaw);
|
|
116
116
|
if (!result || !result.length) throw new NotFoundException({
|
|
117
117
|
message: 'No Data Found',
|
|
118
|
-
messageKey:
|
|
118
|
+
messageKey: ERROR_MESSAGES.NOT_FOUND
|
|
119
119
|
});
|
|
120
120
|
return result;
|
|
121
121
|
} catch (error) {
|
|
@@ -149,7 +149,7 @@ import { DeleteDto } from '../dtos';
|
|
|
149
149
|
output = await finalQuery.getOne();
|
|
150
150
|
if (!output) throw new NotFoundException({
|
|
151
151
|
message: 'No Data Found',
|
|
152
|
-
messageKey:
|
|
152
|
+
messageKey: ERROR_MESSAGES.NOT_FOUND
|
|
153
153
|
});
|
|
154
154
|
result = this.convertEntityToResponseDto(output, false);
|
|
155
155
|
}
|
|
@@ -239,18 +239,20 @@ import { DeleteDto } from '../dtos';
|
|
|
239
239
|
`;
|
|
240
240
|
const parameters = rawSubQuery.getParameters();
|
|
241
241
|
const orderedValues = [];
|
|
242
|
+
const isPostgres = this.repository.manager.connection.options.type === 'postgres';
|
|
243
|
+
let paramIndex = 0;
|
|
242
244
|
const convertedQuery = countSql.replace(/:(\w+)/g, (_, key)=>{
|
|
243
245
|
if (!(key in parameters)) {
|
|
244
246
|
throw new InternalServerErrorException({
|
|
245
247
|
message: `Missing parameter value for: ${key}`,
|
|
246
248
|
messageKey: SYSTEM_MESSAGES.MISSING_PARAMETER,
|
|
247
|
-
|
|
249
|
+
messageVariables: {
|
|
248
250
|
key
|
|
249
251
|
}
|
|
250
252
|
});
|
|
251
253
|
}
|
|
252
254
|
orderedValues.push(parameters[key]);
|
|
253
|
-
return '?';
|
|
255
|
+
return isPostgres ? `$${++paramIndex}` : '?';
|
|
254
256
|
});
|
|
255
257
|
const result = await this.repository.query(convertedQuery, orderedValues);
|
|
256
258
|
total = Number(result[0]?.count || 0);
|
|
@@ -327,7 +329,7 @@ import { DeleteDto } from '../dtos';
|
|
|
327
329
|
}
|
|
328
330
|
throw new InternalServerErrorException({
|
|
329
331
|
message: typeof error === 'string' ? error : 'Unknown error',
|
|
330
|
-
messageKey:
|
|
332
|
+
messageKey: ERROR_MESSAGES.INTERNAL
|
|
331
333
|
});
|
|
332
334
|
}
|
|
333
335
|
/** Ensures value is always an array */ ensureArray(value) {
|
|
@@ -427,7 +429,7 @@ import { DeleteDto } from '../dtos';
|
|
|
427
429
|
});
|
|
428
430
|
if (!existing) throw new NotFoundException({
|
|
429
431
|
message: 'No such entity data found for update! Please, Try Again.',
|
|
430
|
-
messageKey:
|
|
432
|
+
messageKey: ERROR_MESSAGES.NOT_FOUND
|
|
431
433
|
});
|
|
432
434
|
return Object.assign(existing, d);
|
|
433
435
|
}
|
|
@@ -441,7 +443,7 @@ import { DeleteDto } from '../dtos';
|
|
|
441
443
|
return Object.assign({}, entity);
|
|
442
444
|
}
|
|
443
445
|
convertEntityListToResponseListDto(entities, _isRaw) {
|
|
444
|
-
return entities.map((entity)=>
|
|
446
|
+
return entities.map((entity)=>this.convertEntityToResponseDto(entity, _isRaw));
|
|
445
447
|
}
|
|
446
448
|
async getEntityClass() {
|
|
447
449
|
return await this.repository.create();
|
package/fesm/classes/index.js
CHANGED
|
@@ -2,7 +2,6 @@ export * from './api-controller.class';
|
|
|
2
2
|
export * from './api-service.class';
|
|
3
3
|
export * from './request-scoped-api.service';
|
|
4
4
|
export * from './hybrid-cache.class';
|
|
5
|
-
export * from './winston-logger-adapter.class';
|
|
6
5
|
export * from './winston.logger.class';
|
|
7
6
|
// Re-export permission constants for convenience
|
|
8
7
|
export * from '../constants/permissions';
|
package/fesm/constants/index.js
CHANGED
|
@@ -4,7 +4,6 @@ export const PERMISSIONS_KEY = 'permissions';
|
|
|
4
4
|
// Injection tokens
|
|
5
5
|
export const CACHE_INSTANCE = 'CACHE_INSTANCE';
|
|
6
6
|
export const PERMISSION_GUARD_CONFIG = 'PERMISSION_GUARD_CONFIG';
|
|
7
|
-
export const LOGGER_INSTANCE = 'LOGGER_INSTANCE';
|
|
8
7
|
// Header names
|
|
9
8
|
export const IDEMPOTENCY_KEY_HEADER = 'x-idempotency-key';
|
|
10
9
|
export const REQUEST_ID_HEADER = 'x-request-id';
|
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
// ==================== SHARED/SYSTEM MESSAGE KEYS ====================
|
|
2
|
-
// Package-specific messages are now in their respective packages:
|
|
3
|
-
// - nestjs-auth/src/config/message-keys.ts
|
|
4
|
-
// - nestjs-iam/src/config/message-keys.ts
|
|
5
|
-
// - nestjs-storage/src/config/message-keys.ts
|
|
6
|
-
// - nestjs-email/src/config/message-keys.ts
|
|
7
|
-
// - nestjs-form-builder/src/config/message-keys.ts
|
|
8
|
-
// - nestjs-event-manager/src/config/message-keys.ts
|
|
9
|
-
// - nestjs-notification/src/config/message-keys.ts
|
|
10
|
-
// - nestjs-localization/src/config/message-keys.ts
|
|
11
1
|
// ==================== AUTH (Shared across guards/interceptors) ====================
|
|
12
2
|
// These are duplicated in nestjs-auth but needed here to avoid circular dependencies
|
|
13
3
|
export const AUTH_MESSAGES = {
|
|
14
4
|
TOKEN_REQUIRED: 'auth.token.required',
|
|
15
5
|
TOKEN_INVALID: 'auth.token.invalid',
|
|
16
|
-
|
|
6
|
+
ENTITY_BELOG_ANOTHER_COMPANY: 'entity.belongs.another.company',
|
|
17
7
|
COMPANY_NO_ACCESS: 'auth.company.no.access'
|
|
18
8
|
};
|
|
19
9
|
// ==================== ERROR (HTTP Exceptions) ====================
|
|
@@ -31,7 +21,8 @@ export const ERROR_MESSAGES = {
|
|
|
31
21
|
PERMISSION_SYSTEM_UNAVAILABLE: 'error.permission.system.unavailable',
|
|
32
22
|
INSUFFICIENT_PERMISSIONS: 'error.insufficient.permissions',
|
|
33
23
|
INSUFFICIENT_PERMISSIONS_OR: 'error.insufficient.permissions.or',
|
|
34
|
-
NO_PERMISSIONS_FOUND: 'error.no.permissions.found'
|
|
24
|
+
NO_PERMISSIONS_FOUND: 'error.no.permissions.found',
|
|
25
|
+
ENDPOINT_DISABLED: 'error.endpoint.disabled'
|
|
35
26
|
};
|
|
36
27
|
// ==================== SYSTEM (Infrastructure) ====================
|
|
37
28
|
export const SYSTEM_MESSAGES = {
|
|
@@ -41,7 +32,6 @@ export const SYSTEM_MESSAGES = {
|
|
|
41
32
|
SERVICE_NOT_AVAILABLE: 'system.service.not.available',
|
|
42
33
|
CONFIG_REQUIRED: 'system.config.required',
|
|
43
34
|
INTERNAL_ERROR: 'system.internal.error',
|
|
44
|
-
NOT_FOUND: 'system.not.found',
|
|
45
35
|
DUPLICATE_REQUEST: 'system.duplicate.request',
|
|
46
36
|
INVALID_TENANT_ID: 'system.invalid.tenant.id',
|
|
47
37
|
TENANT_NOT_FOUND: 'system.tenant.not.found',
|
|
@@ -51,9 +41,3 @@ export const SYSTEM_MESSAGES = {
|
|
|
51
41
|
PATH_TRAVERSAL_DETECTED: 'system.path.traversal.detected',
|
|
52
42
|
INVALID_FILE_KEY: 'system.invalid.file.key'
|
|
53
43
|
};
|
|
54
|
-
// ==================== AGGREGATED EXPORTS ====================
|
|
55
|
-
export const MESSAGE_KEYS = {
|
|
56
|
-
AUTH: AUTH_MESSAGES,
|
|
57
|
-
ERROR: ERROR_MESSAGES,
|
|
58
|
-
SYSTEM: SYSTEM_MESSAGES
|
|
59
|
-
};
|
|
@@ -98,12 +98,6 @@ export const EVENT_PERMISSIONS = {
|
|
|
98
98
|
UPDATE: 'event.update',
|
|
99
99
|
DELETE: 'event.delete'
|
|
100
100
|
};
|
|
101
|
-
export const EVENT_PARTICIPANT_PERMISSIONS = {
|
|
102
|
-
CREATE: 'event-participant.create',
|
|
103
|
-
READ: 'event-participant.read',
|
|
104
|
-
UPDATE: 'event-participant.update',
|
|
105
|
-
DELETE: 'event-participant.delete'
|
|
106
|
-
};
|
|
107
101
|
// ==================== NOTIFICATION MODULE ====================
|
|
108
102
|
export const NOTIFICATION_PERMISSIONS = {
|
|
109
103
|
CREATE: 'notification.create',
|
|
@@ -155,7 +149,6 @@ export const PERMISSIONS = {
|
|
|
155
149
|
FORM_RESULT: FORM_RESULT_PERMISSIONS,
|
|
156
150
|
// Event Manager
|
|
157
151
|
EVENT: EVENT_PERMISSIONS,
|
|
158
|
-
EVENT_PARTICIPANT: EVENT_PARTICIPANT_PERMISSIONS,
|
|
159
152
|
// Notification
|
|
160
153
|
NOTIFICATION: NOTIFICATION_PERMISSIONS,
|
|
161
154
|
// Localization
|
|
@@ -1,28 +1,10 @@
|
|
|
1
1
|
import { BulkMetaDto, BulkResponseDto, ListResponseDto, PaginationMetaDto, SingleResponseDto } from '../dtos';
|
|
2
2
|
import { applyDecorators } from '@nestjs/common';
|
|
3
3
|
import { ApiExtraModels, ApiOkResponse, getSchemaPath } from '@nestjs/swagger';
|
|
4
|
-
|
|
5
|
-
* API Response Decorator
|
|
6
|
-
* Wraps response with the appropriate response structure
|
|
7
|
-
*
|
|
8
|
-
* @param dto - The DTO class for the data
|
|
9
|
-
* @param isArray - Whether the data is an array (default: false)
|
|
10
|
-
* @param arrayType - For arrays: 'list' (paginated) or 'bulk' (operations) (default: 'list')
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* // Single item response
|
|
14
|
-
* @ApiResponseDto(UserDto)
|
|
15
|
-
*
|
|
16
|
-
* // Paginated list response (get-all)
|
|
17
|
-
* @ApiResponseDto(UserDto, true, 'list')
|
|
18
|
-
*
|
|
19
|
-
* // Bulk operation response (insert-many, update-many)
|
|
20
|
-
* @ApiResponseDto(UserDto, true, 'bulk')
|
|
21
|
-
*/ export const ApiResponseDto = (dto, isArray = false, arrayType = 'list')=>{
|
|
22
|
-
// Select appropriate wrapper based on response type
|
|
4
|
+
export const ApiResponseDto = (dto, isArray = false, arrayType = 'list')=>{
|
|
23
5
|
let wrapperDto;
|
|
24
6
|
let metaDto = null;
|
|
25
|
-
if (!isArray) {
|
|
7
|
+
if (!isArray || arrayType === 'single') {
|
|
26
8
|
wrapperDto = SingleResponseDto;
|
|
27
9
|
} else if (arrayType === 'bulk') {
|
|
28
10
|
wrapperDto = BulkResponseDto;
|
package/fesm/decorators/index.js
CHANGED
|
@@ -25,4 +25,3 @@ import { PERMISSIONS_KEY } from '../constants';
|
|
|
25
25
|
* ],
|
|
26
26
|
* })
|
|
27
27
|
*/ export const RequirePermissionLogic = (logic)=>SetMetadata(PERMISSIONS_KEY, logic);
|
|
28
|
-
/** @deprecated Use RequirePermissionLogic instead */ export const RequirePermissionCondition = RequirePermissionLogic;
|
|
@@ -20,11 +20,11 @@ export class BaseAppException extends HttpException {
|
|
|
20
20
|
success: false,
|
|
21
21
|
message: options.message,
|
|
22
22
|
messageKey: options.messageKey || ERROR_MESSAGES.GENERIC,
|
|
23
|
-
|
|
23
|
+
messageVariables: options.messageVariables,
|
|
24
24
|
errors: options.errors
|
|
25
|
-
}, status), _define_property(this, "messageKey", void 0), _define_property(this, "
|
|
25
|
+
}, status), _define_property(this, "messageKey", void 0), _define_property(this, "messageVariables", void 0), _define_property(this, "errors", void 0), _define_property(this, "metadata", void 0);
|
|
26
26
|
this.messageKey = options.messageKey || ERROR_MESSAGES.GENERIC;
|
|
27
|
-
this.
|
|
27
|
+
this.messageVariables = options.messageVariables;
|
|
28
28
|
this.errors = options.errors;
|
|
29
29
|
this.metadata = options.metadata;
|
|
30
30
|
}
|
|
@@ -97,7 +97,7 @@ export class ServiceUnavailableException extends BaseAppException {
|
|
|
97
97
|
super({
|
|
98
98
|
message: `${service} is temporarily unavailable`,
|
|
99
99
|
messageKey: ERROR_MESSAGES.SERVICE_UNAVAILABLE,
|
|
100
|
-
|
|
100
|
+
messageVariables: {
|
|
101
101
|
service
|
|
102
102
|
},
|
|
103
103
|
status: HttpStatus.SERVICE_UNAVAILABLE,
|
|
@@ -16,7 +16,7 @@ export class InsufficientPermissionsException extends ForbiddenException {
|
|
|
16
16
|
success: false,
|
|
17
17
|
message: 'Insufficient permissions',
|
|
18
18
|
messageKey,
|
|
19
|
-
|
|
19
|
+
messageVariables: {
|
|
20
20
|
permissions: missingPermissions.join(', ')
|
|
21
21
|
},
|
|
22
22
|
missingPermissions,
|
|
@@ -61,7 +61,7 @@ export class GlobalExceptionFilter {
|
|
|
61
61
|
success: false,
|
|
62
62
|
message: exception.message,
|
|
63
63
|
messageKey: exception.messageKey,
|
|
64
|
-
|
|
64
|
+
messageVariables: exception.messageVariables,
|
|
65
65
|
errors: exception.errors,
|
|
66
66
|
_meta: {
|
|
67
67
|
requestId,
|
|
@@ -72,12 +72,12 @@ export class GlobalExceptionFilter {
|
|
|
72
72
|
}
|
|
73
73
|
if (exception instanceof HttpException) {
|
|
74
74
|
const response = exception.getResponse();
|
|
75
|
-
const { message, messageKey,
|
|
75
|
+
const { message, messageKey, messageVariables, errors } = this.extractHttpExceptionDetails(response);
|
|
76
76
|
return {
|
|
77
77
|
success: false,
|
|
78
78
|
message,
|
|
79
79
|
messageKey,
|
|
80
|
-
|
|
80
|
+
messageVariables,
|
|
81
81
|
errors,
|
|
82
82
|
_meta: {
|
|
83
83
|
requestId,
|
|
@@ -124,7 +124,7 @@ export class GlobalExceptionFilter {
|
|
|
124
124
|
return {
|
|
125
125
|
message: String(obj.message || 'Unknown error'),
|
|
126
126
|
messageKey: String(obj.messageKey || ERROR_MESSAGES.HTTP),
|
|
127
|
-
|
|
127
|
+
messageVariables: obj.messageVariables,
|
|
128
128
|
errors: obj.errors
|
|
129
129
|
};
|
|
130
130
|
}
|
package/fesm/interfaces/index.js
CHANGED
|
@@ -3,7 +3,6 @@ export * from './datasource.interface';
|
|
|
3
3
|
export * from './event-manager-adapter.interface';
|
|
4
4
|
export * from './identity.interface';
|
|
5
5
|
export * from './logged-user-info.interface';
|
|
6
|
-
export * from './logger.interface';
|
|
7
6
|
export * from './module-config.interface';
|
|
8
7
|
export * from './notification-adapter.interface';
|
|
9
8
|
export * from './permission.interface';
|
|
@@ -88,7 +88,7 @@ export class MultiTenantDataSourceService {
|
|
|
88
88
|
throw new BadRequestException({
|
|
89
89
|
message: `Tenant '${tenantId}' not found`,
|
|
90
90
|
messageKey: SYSTEM_MESSAGES.TENANT_NOT_FOUND,
|
|
91
|
-
|
|
91
|
+
messageVariables: {
|
|
92
92
|
tenantId
|
|
93
93
|
}
|
|
94
94
|
});
|
|
@@ -183,7 +183,7 @@ export class MultiTenantDataSourceService {
|
|
|
183
183
|
throw new BadRequestException({
|
|
184
184
|
message: `Tenant not found. Ensure '${this.tenantHeader}' header is set.`,
|
|
185
185
|
messageKey: SYSTEM_MESSAGES.TENANT_HEADER_REQUIRED,
|
|
186
|
-
|
|
186
|
+
messageVariables: {
|
|
187
187
|
header: this.tenantHeader
|
|
188
188
|
}
|
|
189
189
|
});
|