@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
|
@@ -15,6 +15,7 @@ const _decorators = require("../decorators");
|
|
|
15
15
|
const _apiresponsedecorator = require("../decorators/api-response.decorator");
|
|
16
16
|
const _dtos = require("../dtos");
|
|
17
17
|
const _exceptions = require("../exceptions");
|
|
18
|
+
const _messagekeys = require("../constants/message-keys");
|
|
18
19
|
const _guards = require("../guards");
|
|
19
20
|
const _interceptors = require("../interceptors");
|
|
20
21
|
function _define_property(obj, key, value) {
|
|
@@ -152,7 +153,14 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
|
|
|
152
153
|
}
|
|
153
154
|
async insert(addDto, user) {
|
|
154
155
|
if (!this.isEnabled('insert')) {
|
|
155
|
-
throw new _exceptions.
|
|
156
|
+
throw new _exceptions.BaseAppException({
|
|
157
|
+
message: `Endpoint 'insert' is disabled`,
|
|
158
|
+
messageKey: _messagekeys.ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
159
|
+
messageVariables: {
|
|
160
|
+
endpoint: 'insert'
|
|
161
|
+
},
|
|
162
|
+
status: _common.HttpStatus.FORBIDDEN
|
|
163
|
+
});
|
|
156
164
|
}
|
|
157
165
|
const entity = await this.service.insert(addDto, user);
|
|
158
166
|
const data = (0, _classtransformer.plainToInstance)(responseDtoClass, entity);
|
|
@@ -165,7 +173,14 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
|
|
|
165
173
|
}
|
|
166
174
|
async insertMany(addDto, user) {
|
|
167
175
|
if (!this.isEnabled('insertMany')) {
|
|
168
|
-
throw new _exceptions.
|
|
176
|
+
throw new _exceptions.BaseAppException({
|
|
177
|
+
message: `Endpoint 'insertMany' is disabled`,
|
|
178
|
+
messageKey: _messagekeys.ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
179
|
+
messageVariables: {
|
|
180
|
+
endpoint: 'insertMany'
|
|
181
|
+
},
|
|
182
|
+
status: _common.HttpStatus.FORBIDDEN
|
|
183
|
+
});
|
|
169
184
|
}
|
|
170
185
|
const entities = await this.service.insertMany(addDto, user);
|
|
171
186
|
const data = entities.map((item)=>(0, _classtransformer.plainToInstance)(responseDtoClass, item));
|
|
@@ -186,7 +201,14 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
|
|
|
186
201
|
}
|
|
187
202
|
async getById(id, body, user) {
|
|
188
203
|
if (!this.isEnabled('getById')) {
|
|
189
|
-
throw new _exceptions.
|
|
204
|
+
throw new _exceptions.BaseAppException({
|
|
205
|
+
message: `Endpoint 'getById' is disabled`,
|
|
206
|
+
messageKey: _messagekeys.ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
207
|
+
messageVariables: {
|
|
208
|
+
endpoint: 'getById'
|
|
209
|
+
},
|
|
210
|
+
status: _common.HttpStatus.FORBIDDEN
|
|
211
|
+
});
|
|
190
212
|
}
|
|
191
213
|
const entity = await this.service.findById(id, user, body?.select);
|
|
192
214
|
const data = (0, _classtransformer.plainToInstance)(responseDtoClass, entity);
|
|
@@ -199,7 +221,14 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
|
|
|
199
221
|
}
|
|
200
222
|
async getByIds(body, user) {
|
|
201
223
|
if (!this.isEnabled('getByIds')) {
|
|
202
|
-
throw new _exceptions.
|
|
224
|
+
throw new _exceptions.BaseAppException({
|
|
225
|
+
message: `Endpoint 'getByIds' is disabled`,
|
|
226
|
+
messageKey: _messagekeys.ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
227
|
+
messageVariables: {
|
|
228
|
+
endpoint: 'getByIds'
|
|
229
|
+
},
|
|
230
|
+
status: _common.HttpStatus.FORBIDDEN
|
|
231
|
+
});
|
|
203
232
|
}
|
|
204
233
|
const entities = await this.service.findByIds(body.ids, user, body?.select);
|
|
205
234
|
const data = (0, _classtransformer.plainToInstance)(responseDtoClass, entities);
|
|
@@ -219,7 +248,14 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
|
|
|
219
248
|
}
|
|
220
249
|
async update(updateDto, user) {
|
|
221
250
|
if (!this.isEnabled('update')) {
|
|
222
|
-
throw new _exceptions.
|
|
251
|
+
throw new _exceptions.BaseAppException({
|
|
252
|
+
message: `Endpoint 'update' is disabled`,
|
|
253
|
+
messageKey: _messagekeys.ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
254
|
+
messageVariables: {
|
|
255
|
+
endpoint: 'update'
|
|
256
|
+
},
|
|
257
|
+
status: _common.HttpStatus.FORBIDDEN
|
|
258
|
+
});
|
|
223
259
|
}
|
|
224
260
|
const entity = await this.service.update(updateDto, user);
|
|
225
261
|
const data = (0, _classtransformer.plainToInstance)(responseDtoClass, entity);
|
|
@@ -232,7 +268,14 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
|
|
|
232
268
|
}
|
|
233
269
|
async updateMany(updateDtos, user) {
|
|
234
270
|
if (!this.isEnabled('updateMany')) {
|
|
235
|
-
throw new _exceptions.
|
|
271
|
+
throw new _exceptions.BaseAppException({
|
|
272
|
+
message: `Endpoint 'updateMany' is disabled`,
|
|
273
|
+
messageKey: _messagekeys.ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
274
|
+
messageVariables: {
|
|
275
|
+
endpoint: 'updateMany'
|
|
276
|
+
},
|
|
277
|
+
status: _common.HttpStatus.FORBIDDEN
|
|
278
|
+
});
|
|
236
279
|
}
|
|
237
280
|
const entities = await this.service.updateMany(updateDtos, user);
|
|
238
281
|
const data = (0, _classtransformer.plainToInstance)(responseDtoClass, entities);
|
|
@@ -253,7 +296,14 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
|
|
|
253
296
|
}
|
|
254
297
|
async bulkUpsert(dtos, user) {
|
|
255
298
|
if (!this.isEnabled('bulkUpsert')) {
|
|
256
|
-
throw new _exceptions.
|
|
299
|
+
throw new _exceptions.BaseAppException({
|
|
300
|
+
message: `Endpoint 'bulkUpsert' is disabled`,
|
|
301
|
+
messageKey: _messagekeys.ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
302
|
+
messageVariables: {
|
|
303
|
+
endpoint: 'bulkUpsert'
|
|
304
|
+
},
|
|
305
|
+
status: _common.HttpStatus.FORBIDDEN
|
|
306
|
+
});
|
|
257
307
|
}
|
|
258
308
|
const toInsert = [];
|
|
259
309
|
const toUpdate = [];
|
|
@@ -283,7 +333,14 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
|
|
|
283
333
|
}
|
|
284
334
|
async getByFilter(filter, user) {
|
|
285
335
|
if (!this.isEnabled('getByFilter')) {
|
|
286
|
-
throw new _exceptions.
|
|
336
|
+
throw new _exceptions.BaseAppException({
|
|
337
|
+
message: `Endpoint 'getByFilter' is disabled`,
|
|
338
|
+
messageKey: _messagekeys.ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
339
|
+
messageVariables: {
|
|
340
|
+
endpoint: 'getByFilter'
|
|
341
|
+
},
|
|
342
|
+
status: _common.HttpStatus.FORBIDDEN
|
|
343
|
+
});
|
|
287
344
|
}
|
|
288
345
|
const result = await this.service.getAll('', {
|
|
289
346
|
filter,
|
|
@@ -306,7 +363,14 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
|
|
|
306
363
|
}
|
|
307
364
|
async getAll(filterAndPaginationDto, user, search) {
|
|
308
365
|
if (!this.isEnabled('getAll')) {
|
|
309
|
-
throw new _exceptions.
|
|
366
|
+
throw new _exceptions.BaseAppException({
|
|
367
|
+
message: `Endpoint 'getAll' is disabled`,
|
|
368
|
+
messageKey: _messagekeys.ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
369
|
+
messageVariables: {
|
|
370
|
+
endpoint: 'getAll'
|
|
371
|
+
},
|
|
372
|
+
status: _common.HttpStatus.FORBIDDEN
|
|
373
|
+
});
|
|
310
374
|
}
|
|
311
375
|
const result = await this.service.getAll(search ?? '', filterAndPaginationDto, user);
|
|
312
376
|
const data = (0, _classtransformer.plainToInstance)(responseDtoClass, result.data);
|
|
@@ -330,7 +394,14 @@ function createApiController(createDtoClass, updateDtoClass, responseDtoClass, o
|
|
|
330
394
|
}
|
|
331
395
|
async delete(deleteDto, user) {
|
|
332
396
|
if (!this.isEnabled('delete')) {
|
|
333
|
-
throw new _exceptions.
|
|
397
|
+
throw new _exceptions.BaseAppException({
|
|
398
|
+
message: `Endpoint 'delete' is disabled`,
|
|
399
|
+
messageKey: _messagekeys.ERROR_MESSAGES.ENDPOINT_DISABLED,
|
|
400
|
+
messageVariables: {
|
|
401
|
+
endpoint: 'delete'
|
|
402
|
+
},
|
|
403
|
+
status: _common.HttpStatus.FORBIDDEN
|
|
404
|
+
});
|
|
334
405
|
}
|
|
335
406
|
await this.service.delete(deleteDto, user);
|
|
336
407
|
const count = Array.isArray(deleteDto.id) ? deleteDto.id.length : 1;
|
|
@@ -125,7 +125,7 @@ let ApiService = class ApiService {
|
|
|
125
125
|
const result = this.convertEntityListToResponseListDto(output, isRaw);
|
|
126
126
|
if (!result || !result.length) throw new _common.NotFoundException({
|
|
127
127
|
message: 'No Data Found',
|
|
128
|
-
messageKey: _constants.
|
|
128
|
+
messageKey: _constants.ERROR_MESSAGES.NOT_FOUND
|
|
129
129
|
});
|
|
130
130
|
return result;
|
|
131
131
|
} catch (error) {
|
|
@@ -159,7 +159,7 @@ let ApiService = class ApiService {
|
|
|
159
159
|
output = await finalQuery.getOne();
|
|
160
160
|
if (!output) throw new _common.NotFoundException({
|
|
161
161
|
message: 'No Data Found',
|
|
162
|
-
messageKey: _constants.
|
|
162
|
+
messageKey: _constants.ERROR_MESSAGES.NOT_FOUND
|
|
163
163
|
});
|
|
164
164
|
result = this.convertEntityToResponseDto(output, false);
|
|
165
165
|
}
|
|
@@ -249,18 +249,20 @@ let ApiService = class ApiService {
|
|
|
249
249
|
`;
|
|
250
250
|
const parameters = rawSubQuery.getParameters();
|
|
251
251
|
const orderedValues = [];
|
|
252
|
+
const isPostgres = this.repository.manager.connection.options.type === 'postgres';
|
|
253
|
+
let paramIndex = 0;
|
|
252
254
|
const convertedQuery = countSql.replace(/:(\w+)/g, (_, key)=>{
|
|
253
255
|
if (!(key in parameters)) {
|
|
254
256
|
throw new _common.InternalServerErrorException({
|
|
255
257
|
message: `Missing parameter value for: ${key}`,
|
|
256
258
|
messageKey: _constants.SYSTEM_MESSAGES.MISSING_PARAMETER,
|
|
257
|
-
|
|
259
|
+
messageVariables: {
|
|
258
260
|
key
|
|
259
261
|
}
|
|
260
262
|
});
|
|
261
263
|
}
|
|
262
264
|
orderedValues.push(parameters[key]);
|
|
263
|
-
return '?';
|
|
265
|
+
return isPostgres ? `$${++paramIndex}` : '?';
|
|
264
266
|
});
|
|
265
267
|
const result = await this.repository.query(convertedQuery, orderedValues);
|
|
266
268
|
total = Number(result[0]?.count || 0);
|
|
@@ -337,7 +339,7 @@ let ApiService = class ApiService {
|
|
|
337
339
|
}
|
|
338
340
|
throw new _common.InternalServerErrorException({
|
|
339
341
|
message: typeof error === 'string' ? error : 'Unknown error',
|
|
340
|
-
messageKey: _constants.
|
|
342
|
+
messageKey: _constants.ERROR_MESSAGES.INTERNAL
|
|
341
343
|
});
|
|
342
344
|
}
|
|
343
345
|
/** Ensures value is always an array */ ensureArray(value) {
|
|
@@ -437,7 +439,7 @@ let ApiService = class ApiService {
|
|
|
437
439
|
});
|
|
438
440
|
if (!existing) throw new _common.NotFoundException({
|
|
439
441
|
message: 'No such entity data found for update! Please, Try Again.',
|
|
440
|
-
messageKey: _constants.
|
|
442
|
+
messageKey: _constants.ERROR_MESSAGES.NOT_FOUND
|
|
441
443
|
});
|
|
442
444
|
return Object.assign(existing, d);
|
|
443
445
|
}
|
|
@@ -451,7 +453,7 @@ let ApiService = class ApiService {
|
|
|
451
453
|
return Object.assign({}, entity);
|
|
452
454
|
}
|
|
453
455
|
convertEntityListToResponseListDto(entities, _isRaw) {
|
|
454
|
-
return entities.map((entity)=>
|
|
456
|
+
return entities.map((entity)=>this.convertEntityToResponseDto(entity, _isRaw));
|
|
455
457
|
}
|
|
456
458
|
async getEntityClass() {
|
|
457
459
|
return await this.repository.create();
|
package/cjs/classes/index.js
CHANGED
|
@@ -6,7 +6,6 @@ _export_star(require("./api-controller.class"), exports);
|
|
|
6
6
|
_export_star(require("./api-service.class"), exports);
|
|
7
7
|
_export_star(require("./request-scoped-api.service"), exports);
|
|
8
8
|
_export_star(require("./hybrid-cache.class"), exports);
|
|
9
|
-
_export_star(require("./winston-logger-adapter.class"), exports);
|
|
10
9
|
_export_star(require("./winston.logger.class"), exports);
|
|
11
10
|
_export_star(require("../constants/permissions"), exports);
|
|
12
11
|
function _export_star(from, to) {
|
package/cjs/constants/index.js
CHANGED
|
@@ -25,9 +25,6 @@ _export(exports, {
|
|
|
25
25
|
get IS_PUBLIC_KEY () {
|
|
26
26
|
return IS_PUBLIC_KEY;
|
|
27
27
|
},
|
|
28
|
-
get LOGGER_INSTANCE () {
|
|
29
|
-
return LOGGER_INSTANCE;
|
|
30
|
-
},
|
|
31
28
|
get PERMISSIONS_CACHE_PREFIX () {
|
|
32
29
|
return PERMISSIONS_CACHE_PREFIX;
|
|
33
30
|
},
|
|
@@ -60,7 +57,6 @@ const IS_PUBLIC_KEY = 'isPublic';
|
|
|
60
57
|
const PERMISSIONS_KEY = 'permissions';
|
|
61
58
|
const CACHE_INSTANCE = 'CACHE_INSTANCE';
|
|
62
59
|
const PERMISSION_GUARD_CONFIG = 'PERMISSION_GUARD_CONFIG';
|
|
63
|
-
const LOGGER_INSTANCE = 'LOGGER_INSTANCE';
|
|
64
60
|
const IDEMPOTENCY_KEY_HEADER = 'x-idempotency-key';
|
|
65
61
|
const REQUEST_ID_HEADER = 'x-request-id';
|
|
66
62
|
const CLIENT_TYPE_HEADER = 'x-client-type';
|
|
@@ -1,13 +1,3 @@
|
|
|
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
|
"use strict";
|
|
@@ -27,9 +17,6 @@ _export(exports, {
|
|
|
27
17
|
get ERROR_MESSAGES () {
|
|
28
18
|
return ERROR_MESSAGES;
|
|
29
19
|
},
|
|
30
|
-
get MESSAGE_KEYS () {
|
|
31
|
-
return MESSAGE_KEYS;
|
|
32
|
-
},
|
|
33
20
|
get SYSTEM_MESSAGES () {
|
|
34
21
|
return SYSTEM_MESSAGES;
|
|
35
22
|
}
|
|
@@ -37,7 +24,7 @@ _export(exports, {
|
|
|
37
24
|
const AUTH_MESSAGES = {
|
|
38
25
|
TOKEN_REQUIRED: 'auth.token.required',
|
|
39
26
|
TOKEN_INVALID: 'auth.token.invalid',
|
|
40
|
-
|
|
27
|
+
ENTITY_BELOG_ANOTHER_COMPANY: 'entity.belongs.another.company',
|
|
41
28
|
COMPANY_NO_ACCESS: 'auth.company.no.access'
|
|
42
29
|
};
|
|
43
30
|
const ERROR_MESSAGES = {
|
|
@@ -54,7 +41,8 @@ const ERROR_MESSAGES = {
|
|
|
54
41
|
PERMISSION_SYSTEM_UNAVAILABLE: 'error.permission.system.unavailable',
|
|
55
42
|
INSUFFICIENT_PERMISSIONS: 'error.insufficient.permissions',
|
|
56
43
|
INSUFFICIENT_PERMISSIONS_OR: 'error.insufficient.permissions.or',
|
|
57
|
-
NO_PERMISSIONS_FOUND: 'error.no.permissions.found'
|
|
44
|
+
NO_PERMISSIONS_FOUND: 'error.no.permissions.found',
|
|
45
|
+
ENDPOINT_DISABLED: 'error.endpoint.disabled'
|
|
58
46
|
};
|
|
59
47
|
const SYSTEM_MESSAGES = {
|
|
60
48
|
REPOSITORY_NOT_AVAILABLE: 'system.repository.not.available',
|
|
@@ -63,7 +51,6 @@ const SYSTEM_MESSAGES = {
|
|
|
63
51
|
SERVICE_NOT_AVAILABLE: 'system.service.not.available',
|
|
64
52
|
CONFIG_REQUIRED: 'system.config.required',
|
|
65
53
|
INTERNAL_ERROR: 'system.internal.error',
|
|
66
|
-
NOT_FOUND: 'system.not.found',
|
|
67
54
|
DUPLICATE_REQUEST: 'system.duplicate.request',
|
|
68
55
|
INVALID_TENANT_ID: 'system.invalid.tenant.id',
|
|
69
56
|
TENANT_NOT_FOUND: 'system.tenant.not.found',
|
|
@@ -73,8 +60,3 @@ const SYSTEM_MESSAGES = {
|
|
|
73
60
|
PATH_TRAVERSAL_DETECTED: 'system.path.traversal.detected',
|
|
74
61
|
INVALID_FILE_KEY: 'system.invalid.file.key'
|
|
75
62
|
};
|
|
76
|
-
const MESSAGE_KEYS = {
|
|
77
|
-
AUTH: AUTH_MESSAGES,
|
|
78
|
-
ERROR: ERROR_MESSAGES,
|
|
79
|
-
SYSTEM: SYSTEM_MESSAGES
|
|
80
|
-
};
|
|
@@ -28,9 +28,6 @@ _export(exports, {
|
|
|
28
28
|
get EMAIL_TEMPLATE_PERMISSIONS () {
|
|
29
29
|
return EMAIL_TEMPLATE_PERMISSIONS;
|
|
30
30
|
},
|
|
31
|
-
get EVENT_PARTICIPANT_PERMISSIONS () {
|
|
32
|
-
return EVENT_PARTICIPANT_PERMISSIONS;
|
|
33
|
-
},
|
|
34
31
|
get EVENT_PERMISSIONS () {
|
|
35
32
|
return EVENT_PERMISSIONS;
|
|
36
33
|
},
|
|
@@ -174,12 +171,6 @@ const EVENT_PERMISSIONS = {
|
|
|
174
171
|
UPDATE: 'event.update',
|
|
175
172
|
DELETE: 'event.delete'
|
|
176
173
|
};
|
|
177
|
-
const EVENT_PARTICIPANT_PERMISSIONS = {
|
|
178
|
-
CREATE: 'event-participant.create',
|
|
179
|
-
READ: 'event-participant.read',
|
|
180
|
-
UPDATE: 'event-participant.update',
|
|
181
|
-
DELETE: 'event-participant.delete'
|
|
182
|
-
};
|
|
183
174
|
const NOTIFICATION_PERMISSIONS = {
|
|
184
175
|
CREATE: 'notification.create',
|
|
185
176
|
READ: 'notification.read',
|
|
@@ -228,7 +219,6 @@ const PERMISSIONS = {
|
|
|
228
219
|
FORM_RESULT: FORM_RESULT_PERMISSIONS,
|
|
229
220
|
// Event Manager
|
|
230
221
|
EVENT: EVENT_PERMISSIONS,
|
|
231
|
-
EVENT_PARTICIPANT: EVENT_PARTICIPANT_PERMISSIONS,
|
|
232
222
|
// Notification
|
|
233
223
|
NOTIFICATION: NOTIFICATION_PERMISSIONS,
|
|
234
224
|
// Localization
|
|
@@ -12,10 +12,9 @@ const _dtos = require("../dtos");
|
|
|
12
12
|
const _common = require("@nestjs/common");
|
|
13
13
|
const _swagger = require("@nestjs/swagger");
|
|
14
14
|
const ApiResponseDto = (dto, isArray = false, arrayType = 'list')=>{
|
|
15
|
-
// Select appropriate wrapper based on response type
|
|
16
15
|
let wrapperDto;
|
|
17
16
|
let metaDto = null;
|
|
18
|
-
if (!isArray) {
|
|
17
|
+
if (!isArray || arrayType === 'single') {
|
|
19
18
|
wrapperDto = _dtos.SingleResponseDto;
|
|
20
19
|
} else if (arrayType === 'bulk') {
|
|
21
20
|
wrapperDto = _dtos.BulkResponseDto;
|
package/cjs/decorators/index.js
CHANGED
|
@@ -7,7 +7,6 @@ _export_star(require("./current-user.decorator"), exports);
|
|
|
7
7
|
_export_star(require("./log-action.decorator"), exports);
|
|
8
8
|
_export_star(require("./public.decorator"), exports);
|
|
9
9
|
_export_star(require("./require-permission.decorator"), exports);
|
|
10
|
-
_export_star(require("./sanitize-html.decorator"), exports);
|
|
11
10
|
function _export_star(from, to) {
|
|
12
11
|
Object.keys(from).forEach(function(k) {
|
|
13
12
|
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
@@ -15,9 +15,6 @@ _export(exports, {
|
|
|
15
15
|
get RequirePermission () {
|
|
16
16
|
return RequirePermission;
|
|
17
17
|
},
|
|
18
|
-
get RequirePermissionCondition () {
|
|
19
|
-
return RequirePermissionCondition;
|
|
20
|
-
},
|
|
21
18
|
get RequirePermissionLogic () {
|
|
22
19
|
return RequirePermissionLogic;
|
|
23
20
|
}
|
|
@@ -33,4 +30,3 @@ const RequireAnyPermission = (...permissions)=>(0, _common.SetMetadata)(_constan
|
|
|
33
30
|
operator: 'OR'
|
|
34
31
|
});
|
|
35
32
|
const RequirePermissionLogic = (logic)=>(0, _common.SetMetadata)(_constants.PERMISSIONS_KEY, logic);
|
|
36
|
-
const RequirePermissionCondition = RequirePermissionLogic;
|
|
@@ -56,11 +56,11 @@ let BaseAppException = class BaseAppException extends _common.HttpException {
|
|
|
56
56
|
success: false,
|
|
57
57
|
message: options.message,
|
|
58
58
|
messageKey: options.messageKey || _messagekeys.ERROR_MESSAGES.GENERIC,
|
|
59
|
-
|
|
59
|
+
messageVariables: options.messageVariables,
|
|
60
60
|
errors: options.errors
|
|
61
|
-
}, status), _define_property(this, "messageKey", void 0), _define_property(this, "
|
|
61
|
+
}, 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);
|
|
62
62
|
this.messageKey = options.messageKey || _messagekeys.ERROR_MESSAGES.GENERIC;
|
|
63
|
-
this.
|
|
63
|
+
this.messageVariables = options.messageVariables;
|
|
64
64
|
this.errors = options.errors;
|
|
65
65
|
this.metadata = options.metadata;
|
|
66
66
|
}
|
|
@@ -133,7 +133,7 @@ let ServiceUnavailableException = class ServiceUnavailableException extends Base
|
|
|
133
133
|
super({
|
|
134
134
|
message: `${service} is temporarily unavailable`,
|
|
135
135
|
messageKey: _messagekeys.ERROR_MESSAGES.SERVICE_UNAVAILABLE,
|
|
136
|
-
|
|
136
|
+
messageVariables: {
|
|
137
137
|
service
|
|
138
138
|
},
|
|
139
139
|
status: _common.HttpStatus.SERVICE_UNAVAILABLE,
|
|
@@ -37,7 +37,7 @@ let InsufficientPermissionsException = class InsufficientPermissionsException ex
|
|
|
37
37
|
success: false,
|
|
38
38
|
message: 'Insufficient permissions',
|
|
39
39
|
messageKey,
|
|
40
|
-
|
|
40
|
+
messageVariables: {
|
|
41
41
|
permissions: missingPermissions.join(', ')
|
|
42
42
|
},
|
|
43
43
|
missingPermissions,
|
|
@@ -71,7 +71,7 @@ let GlobalExceptionFilter = class GlobalExceptionFilter {
|
|
|
71
71
|
success: false,
|
|
72
72
|
message: exception.message,
|
|
73
73
|
messageKey: exception.messageKey,
|
|
74
|
-
|
|
74
|
+
messageVariables: exception.messageVariables,
|
|
75
75
|
errors: exception.errors,
|
|
76
76
|
_meta: {
|
|
77
77
|
requestId,
|
|
@@ -82,12 +82,12 @@ let GlobalExceptionFilter = class GlobalExceptionFilter {
|
|
|
82
82
|
}
|
|
83
83
|
if (exception instanceof _common.HttpException) {
|
|
84
84
|
const response = exception.getResponse();
|
|
85
|
-
const { message, messageKey,
|
|
85
|
+
const { message, messageKey, messageVariables, errors } = this.extractHttpExceptionDetails(response);
|
|
86
86
|
return {
|
|
87
87
|
success: false,
|
|
88
88
|
message,
|
|
89
89
|
messageKey,
|
|
90
|
-
|
|
90
|
+
messageVariables,
|
|
91
91
|
errors,
|
|
92
92
|
_meta: {
|
|
93
93
|
requestId,
|
|
@@ -134,7 +134,7 @@ let GlobalExceptionFilter = class GlobalExceptionFilter {
|
|
|
134
134
|
return {
|
|
135
135
|
message: String(obj.message || 'Unknown error'),
|
|
136
136
|
messageKey: String(obj.messageKey || _messagekeys.ERROR_MESSAGES.HTTP),
|
|
137
|
-
|
|
137
|
+
messageVariables: obj.messageVariables,
|
|
138
138
|
errors: obj.errors
|
|
139
139
|
};
|
|
140
140
|
}
|
package/cjs/interfaces/index.js
CHANGED
|
@@ -7,7 +7,6 @@ _export_star(require("./datasource.interface"), exports);
|
|
|
7
7
|
_export_star(require("./event-manager-adapter.interface"), exports);
|
|
8
8
|
_export_star(require("./identity.interface"), exports);
|
|
9
9
|
_export_star(require("./logged-user-info.interface"), exports);
|
|
10
|
-
_export_star(require("./logger.interface"), exports);
|
|
11
10
|
_export_star(require("./module-config.interface"), exports);
|
|
12
11
|
_export_star(require("./notification-adapter.interface"), exports);
|
|
13
12
|
_export_star(require("./permission.interface"), exports);
|
|
@@ -98,7 +98,7 @@ let MultiTenantDataSourceService = class MultiTenantDataSourceService {
|
|
|
98
98
|
throw new _common.BadRequestException({
|
|
99
99
|
message: `Tenant '${tenantId}' not found`,
|
|
100
100
|
messageKey: _constants.SYSTEM_MESSAGES.TENANT_NOT_FOUND,
|
|
101
|
-
|
|
101
|
+
messageVariables: {
|
|
102
102
|
tenantId
|
|
103
103
|
}
|
|
104
104
|
});
|
|
@@ -193,7 +193,7 @@ let MultiTenantDataSourceService = class MultiTenantDataSourceService {
|
|
|
193
193
|
throw new _common.BadRequestException({
|
|
194
194
|
message: `Tenant not found. Ensure '${this.tenantHeader}' header is set.`,
|
|
195
195
|
messageKey: _constants.SYSTEM_MESSAGES.TENANT_HEADER_REQUIRED,
|
|
196
|
-
|
|
196
|
+
messageVariables: {
|
|
197
197
|
header: this.tenantHeader
|
|
198
198
|
}
|
|
199
199
|
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get formatInTimezone () {
|
|
13
|
+
return formatInTimezone;
|
|
14
|
+
},
|
|
15
|
+
get getTodayInTimezone () {
|
|
16
|
+
return getTodayInTimezone;
|
|
17
|
+
},
|
|
18
|
+
get localToUtc () {
|
|
19
|
+
return localToUtc;
|
|
20
|
+
},
|
|
21
|
+
get utcToLocal () {
|
|
22
|
+
return utcToLocal;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
function getOffsetMinutes(utcDate, timezone) {
|
|
26
|
+
const extract = (tz)=>{
|
|
27
|
+
const parts = new Intl.DateTimeFormat('en-US', {
|
|
28
|
+
timeZone: tz,
|
|
29
|
+
year: 'numeric',
|
|
30
|
+
month: '2-digit',
|
|
31
|
+
day: '2-digit',
|
|
32
|
+
hour: '2-digit',
|
|
33
|
+
minute: '2-digit',
|
|
34
|
+
second: '2-digit',
|
|
35
|
+
hour12: false
|
|
36
|
+
}).formatToParts(utcDate);
|
|
37
|
+
const p = Object.fromEntries(parts.filter((x)=>x.type !== 'literal').map((x)=>[
|
|
38
|
+
x.type,
|
|
39
|
+
parseInt(x.value)
|
|
40
|
+
]));
|
|
41
|
+
return Date.UTC(p['year'], p['month'] - 1, p['day'], p['hour'], p['minute'], p['second']);
|
|
42
|
+
};
|
|
43
|
+
return (extract(timezone) - extract('UTC')) / 60_000;
|
|
44
|
+
}
|
|
45
|
+
function localToUtc(dateStr, timeStr, timezone) {
|
|
46
|
+
const [year, month, day] = dateStr.split('-').map(Number);
|
|
47
|
+
const [hours, minutes] = timeStr.split(':').map(Number);
|
|
48
|
+
const approx = new Date(Date.UTC(year, month - 1, day, hours, minutes, 0));
|
|
49
|
+
const offset = getOffsetMinutes(approx, timezone);
|
|
50
|
+
const utcDate = new Date(approx.getTime() - offset * 60_000);
|
|
51
|
+
// DST boundary guard: re-check offset after adjustment
|
|
52
|
+
const finalOffset = getOffsetMinutes(utcDate, timezone);
|
|
53
|
+
return finalOffset !== offset ? new Date(approx.getTime() - finalOffset * 60_000) : utcDate;
|
|
54
|
+
}
|
|
55
|
+
function utcToLocal(utcDate, timezone) {
|
|
56
|
+
const d = typeof utcDate === 'string' ? new Date(utcDate) : utcDate;
|
|
57
|
+
const parts = new Intl.DateTimeFormat('en-CA', {
|
|
58
|
+
timeZone: timezone,
|
|
59
|
+
year: 'numeric',
|
|
60
|
+
month: '2-digit',
|
|
61
|
+
day: '2-digit',
|
|
62
|
+
hour: '2-digit',
|
|
63
|
+
minute: '2-digit',
|
|
64
|
+
hour12: false
|
|
65
|
+
}).formatToParts(d);
|
|
66
|
+
const p = Object.fromEntries(parts.filter((x)=>x.type !== 'literal').map((x)=>[
|
|
67
|
+
x.type,
|
|
68
|
+
x.value
|
|
69
|
+
]));
|
|
70
|
+
// en-CA formats midnight hour as '24' — normalize to '00'
|
|
71
|
+
const hour = p['hour'] === '24' ? '00' : p['hour'];
|
|
72
|
+
return {
|
|
73
|
+
date: `${p['year']}-${p['month']}-${p['day']}`,
|
|
74
|
+
time: `${hour}:${p['minute']}`,
|
|
75
|
+
display: new Intl.DateTimeFormat('en-US', {
|
|
76
|
+
timeZone: timezone,
|
|
77
|
+
dateStyle: 'medium',
|
|
78
|
+
timeStyle: 'short'
|
|
79
|
+
}).format(d)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function formatInTimezone(utcDate, timezone, options = {
|
|
83
|
+
dateStyle: 'medium',
|
|
84
|
+
timeStyle: 'short'
|
|
85
|
+
}) {
|
|
86
|
+
const d = typeof utcDate === 'string' ? new Date(utcDate) : utcDate;
|
|
87
|
+
return new Intl.DateTimeFormat('en-US', {
|
|
88
|
+
...options,
|
|
89
|
+
timeZone: timezone
|
|
90
|
+
}).format(d);
|
|
91
|
+
}
|
|
92
|
+
function getTodayInTimezone(timezone) {
|
|
93
|
+
return utcToLocal(new Date(), timezone).date;
|
|
94
|
+
}
|
package/cjs/utils/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
+
_export_star(require("./date-time.util"), exports);
|
|
5
6
|
_export_star(require("./html-sanitizer.util"), exports);
|
|
6
7
|
_export_star(require("./query-helpers.util"), exports);
|
|
7
8
|
_export_star(require("./request.util"), exports);
|
|
@@ -50,8 +50,8 @@ function validateCompanyOwnership(entity, user, isCompanyFeatureEnabled, entityN
|
|
|
50
50
|
if (entity.companyId && entity.companyId !== user.companyId) {
|
|
51
51
|
throw new _common.BadRequestException({
|
|
52
52
|
message: `${entityName} belongs to another company`,
|
|
53
|
-
messageKey: _constants.AUTH_MESSAGES.
|
|
54
|
-
|
|
53
|
+
messageKey: _constants.AUTH_MESSAGES.ENTITY_BELOG_ANOTHER_COMPANY,
|
|
54
|
+
messageVariables: {
|
|
55
55
|
entity: entityName
|
|
56
56
|
}
|
|
57
57
|
});
|
|
@@ -12,6 +12,12 @@ _export(exports, {
|
|
|
12
12
|
get buildCookieOptions () {
|
|
13
13
|
return buildCookieOptions;
|
|
14
14
|
},
|
|
15
|
+
get buildFrontendUrl () {
|
|
16
|
+
return buildFrontendUrl;
|
|
17
|
+
},
|
|
18
|
+
get extractFrontendUrl () {
|
|
19
|
+
return extractFrontendUrl;
|
|
20
|
+
},
|
|
15
21
|
get isBrowserRequest () {
|
|
16
22
|
return isBrowserRequest;
|
|
17
23
|
},
|
|
@@ -69,3 +75,22 @@ function parseDurationToMs(duration, defaultMs = TIME_UNIT_MS.w) {
|
|
|
69
75
|
const unit = match[2];
|
|
70
76
|
return value * (TIME_UNIT_MS[unit] ?? TIME_UNIT_MS.d);
|
|
71
77
|
}
|
|
78
|
+
function extractFrontendUrl(req) {
|
|
79
|
+
const allowedOrigins = _config.envConfig.getOrigins();
|
|
80
|
+
const origin = (req.get('origin') ?? req.get('referer') ?? '').trim();
|
|
81
|
+
if (origin && allowedOrigins.length) {
|
|
82
|
+
const matched = allowedOrigins.find((u)=>origin.startsWith(u));
|
|
83
|
+
if (matched) {
|
|
84
|
+
return matched;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const host = req.get('host');
|
|
88
|
+
if (!host) {
|
|
89
|
+
throw new Error('Unable to determine frontend URL from request');
|
|
90
|
+
}
|
|
91
|
+
return `${req.protocol}://${host}`;
|
|
92
|
+
}
|
|
93
|
+
function buildFrontendUrl(req, path) {
|
|
94
|
+
const baseUrl = extractFrontendUrl(req);
|
|
95
|
+
return `${baseUrl}${path}`;
|
|
96
|
+
}
|
package/classes/index.d.ts
CHANGED
|
@@ -2,6 +2,5 @@ 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
|
export * from '../constants/permissions';
|
package/constants/index.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ export declare const IS_PUBLIC_KEY = "isPublic";
|
|
|
2
2
|
export declare const PERMISSIONS_KEY = "permissions";
|
|
3
3
|
export declare const CACHE_INSTANCE = "CACHE_INSTANCE";
|
|
4
4
|
export declare const PERMISSION_GUARD_CONFIG = "PERMISSION_GUARD_CONFIG";
|
|
5
|
-
export declare const LOGGER_INSTANCE = "LOGGER_INSTANCE";
|
|
6
5
|
export declare const IDEMPOTENCY_KEY_HEADER = "x-idempotency-key";
|
|
7
6
|
export declare const REQUEST_ID_HEADER = "x-request-id";
|
|
8
7
|
export declare const CLIENT_TYPE_HEADER = "x-client-type";
|