@flusys/nestjs-shared 9.1.2 → 9.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -18
- package/classes/api-controller.class.d.ts +1 -0
- package/classes/api-service.class.d.ts +7 -2
- package/classes/hybrid-cache.class.d.ts +17 -4
- package/constants/index.d.ts +1 -0
- package/constants/permissions.d.ts +9 -0
- package/fesm/183.js +7 -7
- package/fesm/{282.js → 47.js} +98 -158
- package/fesm/470.js +333 -382
- package/fesm/667.js +17 -17
- package/fesm/681.js +326 -129
- package/fesm/{948.js → 997.js} +46 -24
- package/fesm/chunks/123.js +17 -9
- package/fesm/chunks/37.js +5 -5
- package/fesm/classes/index.js +4 -3
- package/fesm/constants/index.js +19 -8
- package/fesm/decorators/index.js +120 -39
- package/fesm/dtos/index.js +1 -1
- package/fesm/entities/index.js +8 -8
- package/fesm/enums/index.js +2 -2
- package/fesm/exceptions/index.js +12 -12
- package/fesm/guards/index.js +201 -68
- package/fesm/index.js +50 -41
- package/fesm/interceptors/index.js +290 -590
- package/fesm/interfaces/index.js +17 -8
- package/fesm/middlewares/index.js +4 -4
- package/fesm/modules/index.js +2 -2
- package/fesm/pipes/index.js +8 -8
- package/fesm/utils/index.js +137 -478
- package/interceptors/idempotency.interceptor.d.ts +14 -2
- package/interceptors/slug.interceptor.d.ts +1 -0
- package/interfaces/permission-action-registry.interface.d.ts +1 -0
- package/interfaces/permission.interface.d.ts +1 -0
- package/modules/shared-permission-cache/shared-permission-cache.service.d.ts +3 -1
- package/modules/utils/utils.service.d.ts +6 -6
- package/package.json +2 -2
- package/utils/date-time.util.d.ts +0 -1
- package/utils/event-pattern.util.d.ts +1 -0
- package/utils/permission-cache-key.util.d.ts +3 -0
- package/utils/query-helpers.util.d.ts +2 -2
package/fesm/470.js
CHANGED
|
@@ -4,8 +4,8 @@ import * as __rspack_external_rxjs_operators_2eaa0997 from "rxjs/operators";
|
|
|
4
4
|
export const __rspack_esm_id = 470;
|
|
5
5
|
export const __rspack_esm_ids = [470];
|
|
6
6
|
export const __webpack_modules__ = {
|
|
7
|
-
|
|
8
|
-
/* import */ var _flusys_nestjs_core__rspack_import_0 = __webpack_require__(
|
|
7
|
+
8504(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
8
|
+
/* import */ var _flusys_nestjs_core__rspack_import_0 = __webpack_require__(8436);
|
|
9
9
|
|
|
10
10
|
function getJsonColumnType() {
|
|
11
11
|
const driver = _flusys_nestjs_core__rspack_import_0.envConfig.getTypeOrmConfig().type;
|
|
@@ -34,7 +34,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
},
|
|
37
|
-
|
|
37
|
+
9405(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
38
38
|
|
|
39
39
|
// EXPORTS
|
|
40
40
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -44,6 +44,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
44
44
|
wA: () => (/* reexport */ permissions/* .BRANCH_PERMISSIONS */.wA),
|
|
45
45
|
aO: () => (/* reexport */ permissions/* .COMPANY_ACTION_PERMISSIONS */.aO),
|
|
46
46
|
t$: () => (/* reexport */ permissions/* .COMPANY_PERMISSIONS */.t$),
|
|
47
|
+
IX: () => (/* reexport */ permissions/* .CROSS_COMPANY_PERMISSIONS */.IX),
|
|
47
48
|
xC: () => (/* reexport */ (/* inlined export .DOMAIN_EVENT_VERSION */1)),
|
|
48
49
|
XI: () => (/* reexport */ disabled_event_bus_class/* .DisabledEventBus */.X),
|
|
49
50
|
V0: () => (/* reexport */ permissions/* .EMAIL_CONFIG_PERMISSIONS */.V0),
|
|
@@ -93,27 +94,27 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
93
94
|
});
|
|
94
95
|
|
|
95
96
|
// EXTERNAL MODULE: external "@nestjs/common"
|
|
96
|
-
var common_ = __webpack_require__(
|
|
97
|
+
var common_ = __webpack_require__(6157);
|
|
97
98
|
// EXTERNAL MODULE: external "@nestjs/swagger"
|
|
98
|
-
var swagger_ = __webpack_require__(
|
|
99
|
+
var swagger_ = __webpack_require__(6176);
|
|
99
100
|
// EXTERNAL MODULE: external "class-transformer"
|
|
100
|
-
var external_class_transformer_ = __webpack_require__(
|
|
101
|
+
var external_class_transformer_ = __webpack_require__(5812);
|
|
101
102
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/constants/message-keys.ts
|
|
102
|
-
var message_keys = __webpack_require__(
|
|
103
|
+
var message_keys = __webpack_require__(4389);
|
|
103
104
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/decorators/index.ts + 4 modules
|
|
104
|
-
var src_decorators = __webpack_require__(
|
|
105
|
+
var src_decorators = __webpack_require__(9523);
|
|
105
106
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/decorators/api-response.decorator.ts
|
|
106
107
|
var api_response_decorator = __webpack_require__(997);
|
|
107
108
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/dtos/index.ts + 6 modules
|
|
108
|
-
var src_dtos = __webpack_require__(
|
|
109
|
+
var src_dtos = __webpack_require__(3746);
|
|
109
110
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/exceptions/index.ts
|
|
110
|
-
var exceptions = __webpack_require__(
|
|
111
|
+
var exceptions = __webpack_require__(9448);
|
|
111
112
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/guards/index.ts + 4 modules
|
|
112
|
-
var guards = __webpack_require__(
|
|
113
|
+
var guards = __webpack_require__(3510);
|
|
113
114
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/interceptors/index.ts + 7 modules
|
|
114
|
-
var interceptors = __webpack_require__(
|
|
115
|
+
var interceptors = __webpack_require__(6863);
|
|
115
116
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/pipes/index.ts + 1 modules
|
|
116
|
-
var pipes = __webpack_require__(
|
|
117
|
+
var pipes = __webpack_require__(3928);
|
|
117
118
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/classes/api-controller.class.ts
|
|
118
119
|
function _ts_decorate(decorators, target, key, desc) {
|
|
119
120
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -149,61 +150,147 @@ function _ts_param(paramIndex, decorator) {
|
|
|
149
150
|
|
|
150
151
|
|
|
151
152
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
153
|
+
const ENDPOINT_KEYS = [
|
|
154
|
+
'insert',
|
|
155
|
+
'insertMany',
|
|
156
|
+
'getById',
|
|
157
|
+
'getByIds',
|
|
158
|
+
'getAll',
|
|
159
|
+
'bulkUpsert',
|
|
160
|
+
'getByFilter',
|
|
161
|
+
'update',
|
|
162
|
+
'updateMany',
|
|
163
|
+
'delete'
|
|
164
|
+
];
|
|
165
|
+
const DEFAULT_SECURITY = {
|
|
166
|
+
level: 'jwt'
|
|
167
|
+
};
|
|
168
|
+
const SECURITY_RANK = {
|
|
169
|
+
public: 0,
|
|
170
|
+
jwt: 1,
|
|
171
|
+
permission: 2
|
|
172
|
+
};
|
|
173
|
+
/** Where an endpoint left out of a per-endpoint map takes its security from. */ const INHERITED_SECURITY = {
|
|
174
|
+
insertMany: [
|
|
175
|
+
'insert'
|
|
176
|
+
],
|
|
177
|
+
updateMany: [
|
|
178
|
+
'update'
|
|
179
|
+
],
|
|
180
|
+
getByIds: [
|
|
181
|
+
'getById',
|
|
182
|
+
'getAll'
|
|
183
|
+
],
|
|
184
|
+
getByFilter: [
|
|
185
|
+
'getById',
|
|
186
|
+
'getAll'
|
|
187
|
+
],
|
|
188
|
+
bulkUpsert: [
|
|
189
|
+
'insert',
|
|
190
|
+
'update'
|
|
191
|
+
]
|
|
192
|
+
};
|
|
193
|
+
function normalizeSecurity(config) {
|
|
194
|
+
return typeof config === 'string' ? {
|
|
159
195
|
level: config
|
|
196
|
+
} : config;
|
|
197
|
+
}
|
|
198
|
+
function toLogicNode(security) {
|
|
199
|
+
if (security.logic) {
|
|
200
|
+
return typeof security.logic === 'string' ? {
|
|
201
|
+
type: 'action',
|
|
202
|
+
actionId: security.logic
|
|
203
|
+
} : security.logic;
|
|
204
|
+
}
|
|
205
|
+
if (!security.permissions?.length) return null;
|
|
206
|
+
return {
|
|
207
|
+
type: 'group',
|
|
208
|
+
operator: security.operator ?? 'AND',
|
|
209
|
+
children: security.permissions.map((actionId)=>({
|
|
210
|
+
type: 'action',
|
|
211
|
+
actionId
|
|
212
|
+
}))
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/** Every requirement of every source must hold - an endpoint doing both an insert and an update needs both. */ function combineSecurity(sources) {
|
|
216
|
+
const strictest = sources.reduce((a, b)=>SECURITY_RANK[b.level] > SECURITY_RANK[a.level] ? b : a);
|
|
217
|
+
if (strictest.level !== 'permission') return strictest;
|
|
218
|
+
const nodes = sources.filter((source)=>source.level === 'permission').map(toLogicNode).filter((node)=>node !== null);
|
|
219
|
+
if (nodes.length <= 1) return nodes.length ? {
|
|
220
|
+
level: 'permission',
|
|
221
|
+
logic: nodes[0]
|
|
222
|
+
} : strictest;
|
|
223
|
+
return {
|
|
224
|
+
level: 'permission',
|
|
225
|
+
logic: {
|
|
226
|
+
type: 'group',
|
|
227
|
+
operator: 'AND',
|
|
228
|
+
children: nodes
|
|
229
|
+
}
|
|
160
230
|
};
|
|
161
|
-
return config;
|
|
162
231
|
}
|
|
163
232
|
/**
|
|
164
|
-
*
|
|
165
|
-
|
|
233
|
+
* A string or a lone `{ level }` object applies to every endpoint; otherwise it is a per-endpoint map.
|
|
234
|
+
* An endpoint left out of the map inherits from the endpoints it does the work of (`getByFilter` from
|
|
235
|
+
* `getById` / `getAll`, `bulkUpsert` from both `insert` and `update`, ...), and anything still unset -
|
|
236
|
+
* no `security` at all included - requires a JWT, so a forgotten endpoint is never public.
|
|
237
|
+
*/ function resolveEndpointSecurity(config) {
|
|
238
|
+
const isGlobal = typeof config === 'string' || !!config && 'level' in config && !ENDPOINT_KEYS.some((key)=>key in config);
|
|
239
|
+
if (isGlobal) {
|
|
240
|
+
const security = normalizeSecurity(config);
|
|
241
|
+
return Object.fromEntries(ENDPOINT_KEYS.map((key)=>[
|
|
242
|
+
key,
|
|
243
|
+
security
|
|
244
|
+
]));
|
|
245
|
+
}
|
|
246
|
+
const map = config ?? {};
|
|
247
|
+
const explicit = (key)=>{
|
|
248
|
+
const value = map[key];
|
|
249
|
+
return value ? normalizeSecurity(value) : undefined;
|
|
250
|
+
};
|
|
251
|
+
const resolve = (key)=>{
|
|
252
|
+
const own = explicit(key);
|
|
253
|
+
if (own) return own;
|
|
254
|
+
const inherited = (INHERITED_SECURITY[key] ?? []).map(explicit).filter((source)=>source !== undefined);
|
|
255
|
+
if (!inherited.length) return DEFAULT_SECURITY;
|
|
256
|
+
return key === 'bulkUpsert' ? combineSecurity(inherited) : inherited[0];
|
|
257
|
+
};
|
|
258
|
+
return Object.fromEntries(ENDPOINT_KEYS.map((key)=>[
|
|
259
|
+
key,
|
|
260
|
+
resolve(key)
|
|
261
|
+
]));
|
|
262
|
+
}
|
|
263
|
+
function isEndpointEnabled(endpoint, enabledEndpoints) {
|
|
166
264
|
if (!enabledEndpoints || enabledEndpoints === 'all') return true;
|
|
167
265
|
return enabledEndpoints.includes(endpoint);
|
|
168
266
|
}
|
|
169
|
-
|
|
170
|
-
* Helper to conditionally exclude endpoint from Swagger if disabled
|
|
171
|
-
*/ function createEndpointDecorators(security, endpoint, enabledEndpoints) {
|
|
267
|
+
function createEndpointDecorators(security, endpoint, enabledEndpoints) {
|
|
172
268
|
const decorators = [];
|
|
173
|
-
// Add security decorators
|
|
174
269
|
decorators.push(createSecurityDecorators(security));
|
|
175
|
-
// Exclude from Swagger if endpoint is disabled
|
|
176
270
|
if (!isEndpointEnabled(endpoint, enabledEndpoints)) {
|
|
177
271
|
decorators.push((0,swagger_.ApiExcludeEndpoint)());
|
|
178
272
|
}
|
|
179
273
|
return (0,common_.applyDecorators)(...decorators);
|
|
180
274
|
}
|
|
181
|
-
|
|
182
|
-
* Creates security decorators based on configuration
|
|
183
|
-
*/ function createSecurityDecorators(security) {
|
|
275
|
+
function createSecurityDecorators(security) {
|
|
184
276
|
const decorators = [];
|
|
185
277
|
switch(security.level){
|
|
186
278
|
case 'public':
|
|
187
279
|
decorators.push((0,src_decorators/* .Public */.w3)());
|
|
188
280
|
break;
|
|
189
281
|
case 'jwt':
|
|
190
|
-
// Apply JWT authentication guard
|
|
191
282
|
decorators.push((0,common_.UseGuards)(guards/* .JwtAuthGuard */.TD));
|
|
192
283
|
decorators.push((0,swagger_.ApiBearerAuth)());
|
|
193
284
|
break;
|
|
194
285
|
case 'permission':
|
|
195
|
-
// Apply JWT authentication guard (required for permission checks)
|
|
196
|
-
// Apply PermissionGuard to check permissions from cache
|
|
197
286
|
decorators.push((0,common_.UseGuards)(guards/* .JwtAuthGuard */.TD, guards/* .PermissionGuard */.LQ));
|
|
198
287
|
decorators.push((0,swagger_.ApiBearerAuth)());
|
|
199
|
-
// Check for complex logic first
|
|
200
288
|
if (security.logic) {
|
|
201
289
|
decorators.push((0,src_decorators/* .RequirePermissionLogic */.rY)(security.logic));
|
|
202
290
|
} else if (security.permissions && security.permissions.length > 0) {
|
|
203
291
|
if (security.operator === 'OR') {
|
|
204
292
|
decorators.push((0,src_decorators/* .RequireAnyPermission */.Dz)(...security.permissions));
|
|
205
293
|
} else {
|
|
206
|
-
// AND is default and most secure
|
|
207
294
|
decorators.push((0,src_decorators/* .RequirePermission */.Tw)(...security.permissions));
|
|
208
295
|
}
|
|
209
296
|
}
|
|
@@ -218,7 +305,6 @@ function _ts_param(paramIndex, decorator) {
|
|
|
218
305
|
excludeExtraneousValues
|
|
219
306
|
});
|
|
220
307
|
}
|
|
221
|
-
// Entity name for message keys (defaults to 'item')
|
|
222
308
|
const entityName = options.entityName ?? 'item';
|
|
223
309
|
const insertBodyPipe = pipes/* .DtoBodyValidationPipe["for"] */.zT["for"](createDtoClass, [
|
|
224
310
|
'createdById'
|
|
@@ -236,42 +322,8 @@ function _ts_param(paramIndex, decorator) {
|
|
|
236
322
|
'createdById',
|
|
237
323
|
'updatedById'
|
|
238
324
|
], true);
|
|
239
|
-
|
|
240
|
-
const
|
|
241
|
-
const endpointKeys = [
|
|
242
|
-
'insert',
|
|
243
|
-
'insertMany',
|
|
244
|
-
'getById',
|
|
245
|
-
'getByIds',
|
|
246
|
-
'getAll',
|
|
247
|
-
'bulkUpsert',
|
|
248
|
-
'getByFilter',
|
|
249
|
-
'update',
|
|
250
|
-
'updateMany',
|
|
251
|
-
'delete'
|
|
252
|
-
];
|
|
253
|
-
// Global security if:
|
|
254
|
-
// 1. It's a string (SecurityLevel)
|
|
255
|
-
// 2. It's an object with 'level' property but no endpoint keys
|
|
256
|
-
const isGlobalSecurity = typeof securityConfig === 'string' || securityConfig && typeof securityConfig === 'object' && 'level' in securityConfig && !endpointKeys.some((key)=>key in securityConfig);
|
|
257
|
-
// Normalize security config for each endpoint
|
|
258
|
-
// IMPORTANT: When per-endpoint security is specified, default to 'jwt' for unconfigured endpoints
|
|
259
|
-
// to prevent accidentally exposing endpoints without authentication
|
|
260
|
-
const defaultSecurity = isGlobalSecurity ? normalizeSecurity(securityConfig) : {
|
|
261
|
-
level: 'jwt'
|
|
262
|
-
};
|
|
263
|
-
const security = {
|
|
264
|
-
insert: isGlobalSecurity ? defaultSecurity : normalizeSecurity(securityConfig?.insert),
|
|
265
|
-
insertMany: isGlobalSecurity ? defaultSecurity : normalizeSecurity(securityConfig?.insertMany),
|
|
266
|
-
getById: isGlobalSecurity ? defaultSecurity : normalizeSecurity(securityConfig?.getById),
|
|
267
|
-
getByIds: isGlobalSecurity ? defaultSecurity : normalizeSecurity(securityConfig?.getByIds),
|
|
268
|
-
getAll: isGlobalSecurity ? defaultSecurity : normalizeSecurity(securityConfig?.getAll),
|
|
269
|
-
getByFilter: isGlobalSecurity ? defaultSecurity : normalizeSecurity(securityConfig?.getByFilter),
|
|
270
|
-
bulkUpsert: isGlobalSecurity ? defaultSecurity : normalizeSecurity(securityConfig?.bulkUpsert),
|
|
271
|
-
update: isGlobalSecurity ? defaultSecurity : normalizeSecurity(securityConfig?.update),
|
|
272
|
-
updateMany: isGlobalSecurity ? defaultSecurity : normalizeSecurity(securityConfig?.updateMany),
|
|
273
|
-
delete: isGlobalSecurity ? defaultSecurity : normalizeSecurity(securityConfig?.delete)
|
|
274
|
-
};
|
|
325
|
+
const security = resolveEndpointSecurity(options.security);
|
|
326
|
+
const label = entityName.charAt(0).toUpperCase() + entityName.slice(1);
|
|
275
327
|
let ApiController = class ApiController {
|
|
276
328
|
service;
|
|
277
329
|
enabledEndpoints = options.enabledEndpoints ?? 'all';
|
|
@@ -282,37 +334,30 @@ function _ts_param(paramIndex, decorator) {
|
|
|
282
334
|
if (this.enabledEndpoints === 'all') return true;
|
|
283
335
|
return Array.isArray(this.enabledEndpoints) && this.enabledEndpoints.includes(endpoint);
|
|
284
336
|
}
|
|
337
|
+
assertEnabled(endpoint) {
|
|
338
|
+
if (this.isEnabled(endpoint)) return;
|
|
339
|
+
throw new exceptions/* .BaseAppException */.m8({
|
|
340
|
+
message: `Endpoint '${endpoint}' is disabled`,
|
|
341
|
+
messageKey: message_keys/* .ERROR_MESSAGES.ENDPOINT_DISABLED */.UU.ENDPOINT_DISABLED,
|
|
342
|
+
messageVariables: {
|
|
343
|
+
endpoint
|
|
344
|
+
},
|
|
345
|
+
status: common_.HttpStatus.FORBIDDEN
|
|
346
|
+
});
|
|
347
|
+
}
|
|
285
348
|
async insert(addDto, user) {
|
|
286
|
-
|
|
287
|
-
throw new exceptions/* .BaseAppException */.m8({
|
|
288
|
-
message: `Endpoint 'insert' is disabled`,
|
|
289
|
-
messageKey: message_keys/* .ERROR_MESSAGES.ENDPOINT_DISABLED */.UU.ENDPOINT_DISABLED,
|
|
290
|
-
messageVariables: {
|
|
291
|
-
endpoint: 'insert'
|
|
292
|
-
},
|
|
293
|
-
status: common_.HttpStatus.FORBIDDEN
|
|
294
|
-
});
|
|
295
|
-
}
|
|
349
|
+
this.assertEnabled('insert');
|
|
296
350
|
const entity = await this.service.insert(addDto, user);
|
|
297
351
|
const data = toDto(responseDtoClass, entity);
|
|
298
352
|
return {
|
|
299
353
|
success: true,
|
|
300
|
-
message: `${
|
|
354
|
+
message: `${label} created successfully`,
|
|
301
355
|
messageKey: `${entityName}.create.success`,
|
|
302
356
|
data
|
|
303
357
|
};
|
|
304
358
|
}
|
|
305
359
|
async insertMany(addDto, user) {
|
|
306
|
-
|
|
307
|
-
throw new exceptions/* .BaseAppException */.m8({
|
|
308
|
-
message: `Endpoint 'insertMany' is disabled`,
|
|
309
|
-
messageKey: message_keys/* .ERROR_MESSAGES.ENDPOINT_DISABLED */.UU.ENDPOINT_DISABLED,
|
|
310
|
-
messageVariables: {
|
|
311
|
-
endpoint: 'insertMany'
|
|
312
|
-
},
|
|
313
|
-
status: common_.HttpStatus.FORBIDDEN
|
|
314
|
-
});
|
|
315
|
-
}
|
|
360
|
+
this.assertEnabled('insertMany');
|
|
316
361
|
const entities = await this.service.insertMany(addDto, user);
|
|
317
362
|
const data = entities.map((item)=>toDto(responseDtoClass, item));
|
|
318
363
|
return {
|
|
@@ -331,36 +376,18 @@ function _ts_param(paramIndex, decorator) {
|
|
|
331
376
|
};
|
|
332
377
|
}
|
|
333
378
|
async getById(id, body, user) {
|
|
334
|
-
|
|
335
|
-
throw new exceptions/* .BaseAppException */.m8({
|
|
336
|
-
message: `Endpoint 'getById' is disabled`,
|
|
337
|
-
messageKey: message_keys/* .ERROR_MESSAGES.ENDPOINT_DISABLED */.UU.ENDPOINT_DISABLED,
|
|
338
|
-
messageVariables: {
|
|
339
|
-
endpoint: 'getById'
|
|
340
|
-
},
|
|
341
|
-
status: common_.HttpStatus.FORBIDDEN
|
|
342
|
-
});
|
|
343
|
-
}
|
|
379
|
+
this.assertEnabled('getById');
|
|
344
380
|
const entity = await this.service.findById(id, user, body?.select);
|
|
345
381
|
const data = toDto(responseDtoClass, entity);
|
|
346
382
|
return {
|
|
347
383
|
success: true,
|
|
348
|
-
message: `${
|
|
384
|
+
message: `${label} retrieved successfully`,
|
|
349
385
|
messageKey: `${entityName}.get.success`,
|
|
350
386
|
data
|
|
351
387
|
};
|
|
352
388
|
}
|
|
353
389
|
async getByIds(body, user) {
|
|
354
|
-
|
|
355
|
-
throw new exceptions/* .BaseAppException */.m8({
|
|
356
|
-
message: `Endpoint 'getByIds' is disabled`,
|
|
357
|
-
messageKey: message_keys/* .ERROR_MESSAGES.ENDPOINT_DISABLED */.UU.ENDPOINT_DISABLED,
|
|
358
|
-
messageVariables: {
|
|
359
|
-
endpoint: 'getByIds'
|
|
360
|
-
},
|
|
361
|
-
status: common_.HttpStatus.FORBIDDEN
|
|
362
|
-
});
|
|
363
|
-
}
|
|
390
|
+
this.assertEnabled('getByIds');
|
|
364
391
|
const entities = await this.service.findByIds(body.ids, user, body?.select);
|
|
365
392
|
const data = entities.map((item)=>toDto(responseDtoClass, item));
|
|
366
393
|
return {
|
|
@@ -378,36 +405,18 @@ function _ts_param(paramIndex, decorator) {
|
|
|
378
405
|
};
|
|
379
406
|
}
|
|
380
407
|
async update(updateDto, user) {
|
|
381
|
-
|
|
382
|
-
throw new exceptions/* .BaseAppException */.m8({
|
|
383
|
-
message: `Endpoint 'update' is disabled`,
|
|
384
|
-
messageKey: message_keys/* .ERROR_MESSAGES.ENDPOINT_DISABLED */.UU.ENDPOINT_DISABLED,
|
|
385
|
-
messageVariables: {
|
|
386
|
-
endpoint: 'update'
|
|
387
|
-
},
|
|
388
|
-
status: common_.HttpStatus.FORBIDDEN
|
|
389
|
-
});
|
|
390
|
-
}
|
|
408
|
+
this.assertEnabled('update');
|
|
391
409
|
const entity = await this.service.update(updateDto, user);
|
|
392
410
|
const data = toDto(responseDtoClass, entity);
|
|
393
411
|
return {
|
|
394
412
|
success: true,
|
|
395
|
-
message: `${
|
|
413
|
+
message: `${label} updated successfully`,
|
|
396
414
|
messageKey: `${entityName}.update.success`,
|
|
397
415
|
data
|
|
398
416
|
};
|
|
399
417
|
}
|
|
400
418
|
async updateMany(updateDtos, user) {
|
|
401
|
-
|
|
402
|
-
throw new exceptions/* .BaseAppException */.m8({
|
|
403
|
-
message: `Endpoint 'updateMany' is disabled`,
|
|
404
|
-
messageKey: message_keys/* .ERROR_MESSAGES.ENDPOINT_DISABLED */.UU.ENDPOINT_DISABLED,
|
|
405
|
-
messageVariables: {
|
|
406
|
-
endpoint: 'updateMany'
|
|
407
|
-
},
|
|
408
|
-
status: common_.HttpStatus.FORBIDDEN
|
|
409
|
-
});
|
|
410
|
-
}
|
|
419
|
+
this.assertEnabled('updateMany');
|
|
411
420
|
const entities = await this.service.updateMany(updateDtos, user);
|
|
412
421
|
const data = entities.map((item)=>toDto(responseDtoClass, item));
|
|
413
422
|
return {
|
|
@@ -426,16 +435,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
426
435
|
};
|
|
427
436
|
}
|
|
428
437
|
async bulkUpsert(dtos, user) {
|
|
429
|
-
|
|
430
|
-
throw new exceptions/* .BaseAppException */.m8({
|
|
431
|
-
message: `Endpoint 'bulkUpsert' is disabled`,
|
|
432
|
-
messageKey: message_keys/* .ERROR_MESSAGES.ENDPOINT_DISABLED */.UU.ENDPOINT_DISABLED,
|
|
433
|
-
messageVariables: {
|
|
434
|
-
endpoint: 'bulkUpsert'
|
|
435
|
-
},
|
|
436
|
-
status: common_.HttpStatus.FORBIDDEN
|
|
437
|
-
});
|
|
438
|
-
}
|
|
438
|
+
this.assertEnabled('bulkUpsert');
|
|
439
439
|
const toInsert = [];
|
|
440
440
|
const toUpdate = [];
|
|
441
441
|
for (const dto of dtos){
|
|
@@ -463,16 +463,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
463
463
|
};
|
|
464
464
|
}
|
|
465
465
|
async getByFilter(filter, user) {
|
|
466
|
-
|
|
467
|
-
throw new exceptions/* .BaseAppException */.m8({
|
|
468
|
-
message: `Endpoint 'getByFilter' is disabled`,
|
|
469
|
-
messageKey: message_keys/* .ERROR_MESSAGES.ENDPOINT_DISABLED */.UU.ENDPOINT_DISABLED,
|
|
470
|
-
messageVariables: {
|
|
471
|
-
endpoint: 'getByFilter'
|
|
472
|
-
},
|
|
473
|
-
status: common_.HttpStatus.FORBIDDEN
|
|
474
|
-
});
|
|
475
|
-
}
|
|
466
|
+
this.assertEnabled('getByFilter');
|
|
476
467
|
const result = await this.service.getAll('', {
|
|
477
468
|
filter,
|
|
478
469
|
pagination: {
|
|
@@ -487,22 +478,13 @@ function _ts_param(paramIndex, decorator) {
|
|
|
487
478
|
const data = toDto(responseDtoClass, entity);
|
|
488
479
|
return {
|
|
489
480
|
success: true,
|
|
490
|
-
message: `${
|
|
481
|
+
message: `${label} retrieved successfully`,
|
|
491
482
|
messageKey: `${entityName}.get.by.filter.success`,
|
|
492
483
|
data
|
|
493
484
|
};
|
|
494
485
|
}
|
|
495
486
|
async getAll(filterAndPaginationDto, user, search) {
|
|
496
|
-
|
|
497
|
-
throw new exceptions/* .BaseAppException */.m8({
|
|
498
|
-
message: `Endpoint 'getAll' is disabled`,
|
|
499
|
-
messageKey: message_keys/* .ERROR_MESSAGES.ENDPOINT_DISABLED */.UU.ENDPOINT_DISABLED,
|
|
500
|
-
messageVariables: {
|
|
501
|
-
endpoint: 'getAll'
|
|
502
|
-
},
|
|
503
|
-
status: common_.HttpStatus.FORBIDDEN
|
|
504
|
-
});
|
|
505
|
-
}
|
|
487
|
+
this.assertEnabled('getAll');
|
|
506
488
|
const result = await this.service.getAll(search ?? '', filterAndPaginationDto, user);
|
|
507
489
|
const data = result.data.map((item)=>toDto(responseDtoClass, item));
|
|
508
490
|
const page = filterAndPaginationDto.pagination?.currentPage ?? 0;
|
|
@@ -510,7 +492,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
510
492
|
const totalPages = pageSize > 0 ? Math.ceil(result.total / pageSize) : 1;
|
|
511
493
|
return {
|
|
512
494
|
success: true,
|
|
513
|
-
message: `${
|
|
495
|
+
message: `${label}s retrieved successfully`,
|
|
514
496
|
messageKey: `${entityName}.get.all.success`,
|
|
515
497
|
data,
|
|
516
498
|
meta: {
|
|
@@ -524,16 +506,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
524
506
|
};
|
|
525
507
|
}
|
|
526
508
|
async delete(deleteDto, user) {
|
|
527
|
-
|
|
528
|
-
throw new exceptions/* .BaseAppException */.m8({
|
|
529
|
-
message: `Endpoint 'delete' is disabled`,
|
|
530
|
-
messageKey: message_keys/* .ERROR_MESSAGES.ENDPOINT_DISABLED */.UU.ENDPOINT_DISABLED,
|
|
531
|
-
messageVariables: {
|
|
532
|
-
endpoint: 'delete'
|
|
533
|
-
},
|
|
534
|
-
status: common_.HttpStatus.FORBIDDEN
|
|
535
|
-
});
|
|
536
|
-
}
|
|
509
|
+
this.assertEnabled('delete');
|
|
537
510
|
await this.service.delete(deleteDto, user);
|
|
538
511
|
const count = Array.isArray(deleteDto.id) ? deleteDto.id.length : 1;
|
|
539
512
|
const action = deleteDto.type === 'restore' ? 'restore' : 'delete';
|
|
@@ -847,23 +820,23 @@ function _ts_param(paramIndex, decorator) {
|
|
|
847
820
|
}
|
|
848
821
|
|
|
849
822
|
// EXTERNAL MODULE: external "typeorm"
|
|
850
|
-
var external_typeorm_ = __webpack_require__(
|
|
823
|
+
var external_typeorm_ = __webpack_require__(7158);
|
|
851
824
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/constants/index.ts
|
|
852
|
-
var constants = __webpack_require__(
|
|
825
|
+
var constants = __webpack_require__(6043);
|
|
853
826
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/decorators/log-action.decorator.ts
|
|
854
|
-
var log_action_decorator = __webpack_require__(
|
|
827
|
+
var log_action_decorator = __webpack_require__(1946);
|
|
855
828
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/modules/utils/utils.service.ts
|
|
856
|
-
var utils_service = __webpack_require__(
|
|
829
|
+
var utils_service = __webpack_require__(1169);
|
|
857
830
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/utils/cache-tenant.util.ts
|
|
858
|
-
var cache_tenant_util = __webpack_require__(
|
|
831
|
+
var cache_tenant_util = __webpack_require__(8154);
|
|
859
832
|
// EXTERNAL MODULE: external "crypto"
|
|
860
|
-
var external_crypto_ = __webpack_require__(
|
|
861
|
-
// EXTERNAL MODULE: ./projects/nestjs-shared/src/middlewares/logger.middleware.ts +
|
|
862
|
-
var logger_middleware = __webpack_require__(
|
|
833
|
+
var external_crypto_ = __webpack_require__(7823);
|
|
834
|
+
// EXTERNAL MODULE: ./projects/nestjs-shared/src/middlewares/logger.middleware.ts + 1 modules
|
|
835
|
+
var logger_middleware = __webpack_require__(8244);
|
|
863
836
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/utils/event-pattern.util.ts
|
|
864
|
-
var event_pattern_util = __webpack_require__(
|
|
837
|
+
var event_pattern_util = __webpack_require__(8456);
|
|
865
838
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/classes/event-bus.registry.ts
|
|
866
|
-
var event_bus_registry = __webpack_require__(
|
|
839
|
+
var event_bus_registry = __webpack_require__(3228);
|
|
867
840
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/classes/domain-event.publisher.ts
|
|
868
841
|
|
|
869
842
|
|
|
@@ -930,7 +903,7 @@ function collectIds(rows) {
|
|
|
930
903
|
}
|
|
931
904
|
|
|
932
905
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/classes/hybrid-cache.class.ts + 3 modules
|
|
933
|
-
var hybrid_cache_class = __webpack_require__(
|
|
906
|
+
var hybrid_cache_class = __webpack_require__(5375);
|
|
934
907
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/classes/api-service.class.ts
|
|
935
908
|
function api_service_class_ts_decorate(decorators, target, key, desc) {
|
|
936
909
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -975,6 +948,7 @@ class ApiService {
|
|
|
975
948
|
repositoryInitialized = false;
|
|
976
949
|
_entity;
|
|
977
950
|
_dataSourceProvider;
|
|
951
|
+
logger = new common_.Logger(ApiService.name);
|
|
978
952
|
/**
|
|
979
953
|
* `entity` is the table this service reads and writes. A service whose table
|
|
980
954
|
* depends on runtime config - the company feature, say - passes the ternary
|
|
@@ -995,6 +969,46 @@ class ApiService {
|
|
|
995
969
|
/** Cached rows belong to the current tenant; pass this to every `UtilsService` cache helper. */ cacheTenant() {
|
|
996
970
|
return (0,cache_tenant_util/* .cacheTenantId */.q)(this._dataSourceProvider);
|
|
997
971
|
}
|
|
972
|
+
/**
|
|
973
|
+
* Every entity whose rows end up in this service's cached reads. Override to add the entities a
|
|
974
|
+
* read joins or embeds, so a write to any of them also invalidates this service's cache.
|
|
975
|
+
*/ cacheDependencies() {
|
|
976
|
+
return [
|
|
977
|
+
this.entityName
|
|
978
|
+
];
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Override to send one list read straight to the database - e.g. a filter that reads tables whose
|
|
982
|
+
* writes never move this service's stamps. Decided per call, so concurrent reads never interfere.
|
|
983
|
+
*/ bypassListCache(_filterAndPaginationDto) {
|
|
984
|
+
return false;
|
|
985
|
+
}
|
|
986
|
+
/** Invalidates this entity's cached reads - and every service that lists it as a dependency */ async invalidateCache() {
|
|
987
|
+
await this.utilsService.clearCache(this.entityName, this.cacheManager, this.cacheTenant());
|
|
988
|
+
}
|
|
989
|
+
/** null = caching is off or the cache is unreachable; the read then goes straight to the database */ async readCacheStamp(bypass = false) {
|
|
990
|
+
if (!this.isCacheable || bypass) return null;
|
|
991
|
+
try {
|
|
992
|
+
return await this.utilsService.getCacheStamp(this.cacheManager, this.cacheDependencies(), this.cacheTenant());
|
|
993
|
+
} catch (error) {
|
|
994
|
+
this.logger.warn(`Cache unavailable, reading '${this.entityName}' from the database: ${error.message}`);
|
|
995
|
+
return null;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
async readCached(key) {
|
|
999
|
+
try {
|
|
1000
|
+
return await this.cacheManager.get(key);
|
|
1001
|
+
} catch {
|
|
1002
|
+
return undefined;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
async writeCached(key, value) {
|
|
1006
|
+
try {
|
|
1007
|
+
await this.cacheManager.set(key, value);
|
|
1008
|
+
} catch (error) {
|
|
1009
|
+
this.logger.warn(`Cache write failed for '${this.entityName}': ${error.message}`);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
998
1012
|
async ensureDataSourceRepository() {
|
|
999
1013
|
if (!this.repositoryInitialized) {
|
|
1000
1014
|
const provider = this.getDataSourceProvider();
|
|
@@ -1124,6 +1138,7 @@ class ApiService {
|
|
|
1124
1138
|
await this.ensureDataSourceRepository();
|
|
1125
1139
|
try {
|
|
1126
1140
|
select?.forEach((field)=>this.assertColumnProperty(field));
|
|
1141
|
+
const stamp = await this.readCacheStamp();
|
|
1127
1142
|
const query = this.repository.createQueryBuilder(this.entityName);
|
|
1128
1143
|
query.where({
|
|
1129
1144
|
id
|
|
@@ -1131,27 +1146,26 @@ class ApiService {
|
|
|
1131
1146
|
const { query: finalQuery, isRaw } = await this.getSelectQuery(query, user, select);
|
|
1132
1147
|
let result;
|
|
1133
1148
|
let cacheKey = '';
|
|
1134
|
-
if (
|
|
1135
|
-
cacheKey = this.utilsService.getCacheKey(this.entityName,
|
|
1136
|
-
|
|
1149
|
+
if (stamp !== null) {
|
|
1150
|
+
cacheKey = this.utilsService.getCacheKey(this.entityName, {
|
|
1151
|
+
raw: isRaw,
|
|
1152
|
+
query: finalQuery.getQueryAndParameters()
|
|
1153
|
+
}, id, this.cacheTenant(), stamp);
|
|
1154
|
+
result = await this.readCached(cacheKey);
|
|
1137
1155
|
}
|
|
1138
1156
|
if (!result) {
|
|
1139
1157
|
if (isRaw) {
|
|
1140
1158
|
const rawOutput = await finalQuery.getRawMany();
|
|
1141
|
-
|
|
1142
|
-
if (convertResult.length) result = convertResult[0];
|
|
1159
|
+
result = this.convertEntityListToResponseListDto(rawOutput, isRaw)[0];
|
|
1143
1160
|
} else {
|
|
1144
1161
|
const singleOutput = await finalQuery.getOne();
|
|
1145
|
-
if (
|
|
1146
|
-
message: 'No Data Found',
|
|
1147
|
-
messageKey: constants/* .ERROR_MESSAGES.NOT_FOUND */.UU.NOT_FOUND
|
|
1148
|
-
});
|
|
1149
|
-
result = this.convertEntityToResponseDto(singleOutput, false);
|
|
1150
|
-
}
|
|
1151
|
-
if (this.isCacheable) {
|
|
1152
|
-
await this.cacheManager.set(cacheKey, result);
|
|
1153
|
-
await this.utilsService.trackCacheKey(cacheKey, this.entityName, this.cacheManager, id, this.cacheTenant());
|
|
1162
|
+
if (singleOutput) result = this.convertEntityToResponseDto(singleOutput, false);
|
|
1154
1163
|
}
|
|
1164
|
+
if (!result) throw new common_.NotFoundException({
|
|
1165
|
+
message: 'No Data Found',
|
|
1166
|
+
messageKey: constants/* .ERROR_MESSAGES.NOT_FOUND */.UU.NOT_FOUND
|
|
1167
|
+
});
|
|
1168
|
+
if (stamp !== null) await this.writeCached(cacheKey, result);
|
|
1155
1169
|
}
|
|
1156
1170
|
return result;
|
|
1157
1171
|
} catch (error) {
|
|
@@ -1168,6 +1182,7 @@ class ApiService {
|
|
|
1168
1182
|
let total;
|
|
1169
1183
|
let isRaw = false;
|
|
1170
1184
|
filterAndPaginationDto.select?.forEach((field)=>this.assertColumnProperty(field));
|
|
1185
|
+
const stamp = await this.readCacheStamp(this.bypassListCache(filterAndPaginationDto));
|
|
1171
1186
|
let query = this.repository.createQueryBuilder(this.entityName);
|
|
1172
1187
|
if (filterAndPaginationDto.filter) {
|
|
1173
1188
|
const { query: filterQuery, isRaw: filterIsRaw } = await this.getFilterQuery(query, filterAndPaginationDto.filter, user);
|
|
@@ -1201,13 +1216,13 @@ class ApiService {
|
|
|
1201
1216
|
}
|
|
1202
1217
|
}
|
|
1203
1218
|
let cacheKey = '';
|
|
1204
|
-
if (
|
|
1219
|
+
if (stamp !== null) {
|
|
1205
1220
|
cacheKey = this.utilsService.getCacheKey(this.entityName, {
|
|
1206
1221
|
raw: isRaw,
|
|
1207
1222
|
pagination: filterAndPaginationDto.pagination,
|
|
1208
1223
|
query: query.getQueryAndParameters()
|
|
1209
|
-
}, undefined, this.cacheTenant());
|
|
1210
|
-
const cached = await this.
|
|
1224
|
+
}, undefined, this.cacheTenant(), stamp);
|
|
1225
|
+
const cached = await this.readCached(cacheKey);
|
|
1211
1226
|
if (cached) {
|
|
1212
1227
|
return cached;
|
|
1213
1228
|
}
|
|
@@ -1216,32 +1231,16 @@ class ApiService {
|
|
|
1216
1231
|
const rawSubQuery = query.clone().offset(undefined).limit(undefined);
|
|
1217
1232
|
rawSubQuery.expressionMap.orderBys = {};
|
|
1218
1233
|
rawSubQuery.distinct(true);
|
|
1234
|
+
const [subQuerySql, parameters] = rawSubQuery.getQueryAndParameters();
|
|
1219
1235
|
const countSql = `
|
|
1220
1236
|
SELECT COUNT(*) as count
|
|
1221
1237
|
FROM (
|
|
1222
1238
|
SELECT COUNT(*) as count
|
|
1223
|
-
FROM (${
|
|
1239
|
+
FROM (${subQuerySql}) AS subquery
|
|
1224
1240
|
GROUP BY subquery.${this.entityName}_id
|
|
1225
1241
|
) AS final
|
|
1226
1242
|
`;
|
|
1227
|
-
const
|
|
1228
|
-
const orderedValues = [];
|
|
1229
|
-
const isPostgres = this.repository.manager.connection.options.type === 'postgres';
|
|
1230
|
-
let paramIndex = 0;
|
|
1231
|
-
const convertedQuery = countSql.replace(/:(\w+)/g, (_, key)=>{
|
|
1232
|
-
if (!(key in parameters)) {
|
|
1233
|
-
throw new common_.InternalServerErrorException({
|
|
1234
|
-
message: `Missing parameter value for: ${key}`,
|
|
1235
|
-
messageKey: constants/* .SYSTEM_MESSAGES.MISSING_PARAMETER */.hg.MISSING_PARAMETER,
|
|
1236
|
-
messageVariables: {
|
|
1237
|
-
key
|
|
1238
|
-
}
|
|
1239
|
-
});
|
|
1240
|
-
}
|
|
1241
|
-
orderedValues.push(parameters[key]);
|
|
1242
|
-
return isPostgres ? `$${++paramIndex}` : '?';
|
|
1243
|
-
});
|
|
1244
|
-
const result = await this.repository.query(convertedQuery, orderedValues);
|
|
1243
|
+
const result = await this.repository.query(countSql, parameters);
|
|
1245
1244
|
total = Number(result[0]?.count || 0);
|
|
1246
1245
|
data = await query.getRawMany();
|
|
1247
1246
|
} else {
|
|
@@ -1252,10 +1251,7 @@ class ApiService {
|
|
|
1252
1251
|
data: convertedFinalData,
|
|
1253
1252
|
total
|
|
1254
1253
|
};
|
|
1255
|
-
if (this.
|
|
1256
|
-
await this.cacheManager.set(cacheKey, finalResponse);
|
|
1257
|
-
await this.utilsService.trackCacheKey(cacheKey, this.entityName, this.cacheManager, undefined, this.cacheTenant());
|
|
1258
|
-
}
|
|
1254
|
+
if (stamp !== null) await this.writeCached(cacheKey, finalResponse);
|
|
1259
1255
|
return finalResponse;
|
|
1260
1256
|
} catch (error) {
|
|
1261
1257
|
this.handleError(error);
|
|
@@ -1290,10 +1286,7 @@ class ApiService {
|
|
|
1290
1286
|
});
|
|
1291
1287
|
await this.afterDeleteOperation(ids, option, user, queryRunner);
|
|
1292
1288
|
await queryRunner.commitTransaction();
|
|
1293
|
-
await
|
|
1294
|
-
this.clearCacheForAll(),
|
|
1295
|
-
this.clearCacheForId(ids)
|
|
1296
|
-
]);
|
|
1289
|
+
await this.invalidateCache();
|
|
1297
1290
|
await this.publishLifecycleEvents([
|
|
1298
1291
|
{
|
|
1299
1292
|
action: DELETE_EVENT_ACTIONS[option.type],
|
|
@@ -1335,12 +1328,6 @@ class ApiService {
|
|
|
1335
1328
|
action
|
|
1336
1329
|
});
|
|
1337
1330
|
}
|
|
1338
|
-
async clearCacheForAll() {
|
|
1339
|
-
await this.utilsService.clearCache(this.entityName, this.cacheManager, undefined, this.cacheTenant());
|
|
1340
|
-
}
|
|
1341
|
-
async clearCacheForId(entities) {
|
|
1342
|
-
await Promise.all(entities.map((item)=>this.utilsService.clearCache(this.entityName, this.cacheManager, item.id, this.cacheTenant())));
|
|
1343
|
-
}
|
|
1344
1331
|
handleError(error) {
|
|
1345
1332
|
if (error instanceof Error) {
|
|
1346
1333
|
throw error;
|
|
@@ -1368,12 +1355,7 @@ class ApiService {
|
|
|
1368
1355
|
const { saved, returnFirst, eventGroups } = await fn(qr);
|
|
1369
1356
|
await qr.commitTransaction();
|
|
1370
1357
|
const savedArray = this.ensureArray(saved);
|
|
1371
|
-
|
|
1372
|
-
await Promise.all([
|
|
1373
|
-
this.clearCacheForAll(),
|
|
1374
|
-
this.clearCacheForId(savedArray)
|
|
1375
|
-
]);
|
|
1376
|
-
}
|
|
1358
|
+
await this.invalidateCache();
|
|
1377
1359
|
await this.publishLifecycleEvents(eventGroups ?? (action ? [
|
|
1378
1360
|
{
|
|
1379
1361
|
action,
|
|
@@ -1576,11 +1558,11 @@ ApiService = api_service_class_ts_decorate([
|
|
|
1576
1558
|
], ApiService);
|
|
1577
1559
|
|
|
1578
1560
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/classes/disabled-event-bus.class.ts
|
|
1579
|
-
var disabled_event_bus_class = __webpack_require__(
|
|
1561
|
+
var disabled_event_bus_class = __webpack_require__(1864);
|
|
1580
1562
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/classes/event-transports/event-transport.registry.ts
|
|
1581
|
-
var event_transport_registry = __webpack_require__(
|
|
1563
|
+
var event_transport_registry = __webpack_require__(7149);
|
|
1582
1564
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/classes/event-transports/memory-transport.ts + 1 modules
|
|
1583
|
-
var memory_transport = __webpack_require__(
|
|
1565
|
+
var memory_transport = __webpack_require__(9346);
|
|
1584
1566
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/classes/event-transports/index.ts
|
|
1585
1567
|
|
|
1586
1568
|
// Built-in transport (no external dependencies)
|
|
@@ -1590,13 +1572,13 @@ var memory_transport = __webpack_require__(346);
|
|
|
1590
1572
|
// - import { KafkaTransport } from '@flusys/nestjs-shared/classes/event-transports/kafka-transport.optional';
|
|
1591
1573
|
|
|
1592
1574
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/classes/handle-custome-db.ts
|
|
1593
|
-
var handle_custome_db = __webpack_require__(
|
|
1575
|
+
var handle_custome_db = __webpack_require__(8504);
|
|
1594
1576
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/classes/hybrid-event-bus.class.ts
|
|
1595
|
-
var hybrid_event_bus_class = __webpack_require__(
|
|
1577
|
+
var hybrid_event_bus_class = __webpack_require__(5710);
|
|
1596
1578
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/classes/winston.logger.class.ts + 5 modules
|
|
1597
|
-
var winston_logger_class = __webpack_require__(
|
|
1579
|
+
var winston_logger_class = __webpack_require__(6245);
|
|
1598
1580
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/constants/permissions.ts
|
|
1599
|
-
var permissions = __webpack_require__(
|
|
1581
|
+
var permissions = __webpack_require__(8975);
|
|
1600
1582
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/classes/index.ts
|
|
1601
1583
|
|
|
1602
1584
|
|
|
@@ -1614,9 +1596,9 @@ var permissions = __webpack_require__(975);
|
|
|
1614
1596
|
|
|
1615
1597
|
},
|
|
1616
1598
|
997(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1617
|
-
/* import */ var _dtos_index_js__rspack_import_0 = __webpack_require__(
|
|
1618
|
-
/* import */ var _nestjs_common__rspack_import_1 = __webpack_require__(
|
|
1619
|
-
/* import */ var _nestjs_swagger__rspack_import_2 = __webpack_require__(
|
|
1599
|
+
/* import */ var _dtos_index_js__rspack_import_0 = __webpack_require__(3746);
|
|
1600
|
+
/* import */ var _nestjs_common__rspack_import_1 = __webpack_require__(6157);
|
|
1601
|
+
/* import */ var _nestjs_swagger__rspack_import_2 = __webpack_require__(6176);
|
|
1620
1602
|
|
|
1621
1603
|
|
|
1622
1604
|
|
|
@@ -1667,7 +1649,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
1667
1649
|
|
|
1668
1650
|
|
|
1669
1651
|
},
|
|
1670
|
-
|
|
1652
|
+
9523(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1671
1653
|
|
|
1672
1654
|
// EXPORTS
|
|
1673
1655
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -1684,7 +1666,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
1684
1666
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/decorators/api-response.decorator.ts
|
|
1685
1667
|
var api_response_decorator = __webpack_require__(997);
|
|
1686
1668
|
// EXTERNAL MODULE: external "@nestjs/common"
|
|
1687
|
-
var common_ = __webpack_require__(
|
|
1669
|
+
var common_ = __webpack_require__(6157);
|
|
1688
1670
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/decorators/current-user.decorator.ts
|
|
1689
1671
|
|
|
1690
1672
|
/**
|
|
@@ -1706,9 +1688,9 @@ var common_ = __webpack_require__(157);
|
|
|
1706
1688
|
});
|
|
1707
1689
|
|
|
1708
1690
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/decorators/log-action.decorator.ts
|
|
1709
|
-
var log_action_decorator = __webpack_require__(
|
|
1691
|
+
var log_action_decorator = __webpack_require__(1946);
|
|
1710
1692
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/constants/index.ts
|
|
1711
|
-
var constants = __webpack_require__(
|
|
1693
|
+
var constants = __webpack_require__(6043);
|
|
1712
1694
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/decorators/on-domain-event.decorator.ts
|
|
1713
1695
|
|
|
1714
1696
|
|
|
@@ -1782,10 +1764,12 @@ var constants = __webpack_require__(43);
|
|
|
1782
1764
|
|
|
1783
1765
|
|
|
1784
1766
|
},
|
|
1785
|
-
|
|
1786
|
-
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(
|
|
1787
|
-
/* import */ var _classes_winston_logger_class_js__rspack_import_1 = __webpack_require__(
|
|
1788
|
-
/* import */ var _middlewares_logger_middleware_js__rspack_import_2 = __webpack_require__(
|
|
1767
|
+
1946(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1768
|
+
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
|
|
1769
|
+
/* import */ var _classes_winston_logger_class_js__rspack_import_1 = __webpack_require__(6245);
|
|
1770
|
+
/* import */ var _middlewares_logger_middleware_js__rspack_import_2 = __webpack_require__(8244);
|
|
1771
|
+
/* import */ var _utils_event_pattern_util_js__rspack_import_3 = __webpack_require__(8456);
|
|
1772
|
+
|
|
1789
1773
|
|
|
1790
1774
|
|
|
1791
1775
|
|
|
@@ -1825,7 +1809,6 @@ function LogAction(options = {}) {
|
|
|
1825
1809
|
const methodName = String(propertyKey);
|
|
1826
1810
|
descriptor.value = async function(...args) {
|
|
1827
1811
|
const startTime = Date.now();
|
|
1828
|
-
// Resolve module: decorator option > instance property > undefined
|
|
1829
1812
|
const moduleName = options.module || this.moduleName;
|
|
1830
1813
|
const logger = createLoggerAdapter(className, moduleName);
|
|
1831
1814
|
const action = options.action || `${this.entityName || className}.${methodName}`;
|
|
@@ -1841,7 +1824,7 @@ function LogAction(options = {}) {
|
|
|
1841
1824
|
const startMessage = `Executing action method "${action}"`;
|
|
1842
1825
|
const startContext = options.includeParams ? {
|
|
1843
1826
|
...context,
|
|
1844
|
-
params:
|
|
1827
|
+
params: (0,_utils_event_pattern_util_js__rspack_import_3/* .sanitizeEventPayload */.IN)(args)
|
|
1845
1828
|
} : context;
|
|
1846
1829
|
logger.log(logLevel, startMessage, startContext);
|
|
1847
1830
|
try {
|
|
@@ -1875,30 +1858,6 @@ function LogAction(options = {}) {
|
|
|
1875
1858
|
return descriptor;
|
|
1876
1859
|
};
|
|
1877
1860
|
}
|
|
1878
|
-
function sanitizeParams(args) {
|
|
1879
|
-
return args.map((arg)=>{
|
|
1880
|
-
if (arg === null || arg === undefined) return arg;
|
|
1881
|
-
if (typeof arg === 'object') {
|
|
1882
|
-
const sanitized = {
|
|
1883
|
-
...arg
|
|
1884
|
-
};
|
|
1885
|
-
const sensitiveKeys = [
|
|
1886
|
-
'password',
|
|
1887
|
-
'secret',
|
|
1888
|
-
'token',
|
|
1889
|
-
'apiKey',
|
|
1890
|
-
'authorization'
|
|
1891
|
-
];
|
|
1892
|
-
for (const key of Object.keys(sanitized)){
|
|
1893
|
-
if (sensitiveKeys.some((sk)=>key.toLowerCase().includes(sk))) {
|
|
1894
|
-
sanitized[key] = '[REDACTED]';
|
|
1895
|
-
}
|
|
1896
|
-
}
|
|
1897
|
-
return sanitized;
|
|
1898
|
-
}
|
|
1899
|
-
return arg;
|
|
1900
|
-
});
|
|
1901
|
-
}
|
|
1902
1861
|
function getResultType(result) {
|
|
1903
1862
|
if (result === null) return 'null';
|
|
1904
1863
|
if (result === undefined) return 'undefined';
|
|
@@ -1932,9 +1891,9 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
1932
1891
|
|
|
1933
1892
|
|
|
1934
1893
|
},
|
|
1935
|
-
|
|
1936
|
-
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(
|
|
1937
|
-
/* import */ var _constants_message_keys_js__rspack_import_1 = __webpack_require__(
|
|
1894
|
+
5514(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1895
|
+
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
|
|
1896
|
+
/* import */ var _constants_message_keys_js__rspack_import_1 = __webpack_require__(4389);
|
|
1938
1897
|
|
|
1939
1898
|
|
|
1940
1899
|
class BaseAppException extends _nestjs_common__rspack_import_0.HttpException {
|
|
@@ -2055,9 +2014,9 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
2055
2014
|
|
|
2056
2015
|
|
|
2057
2016
|
},
|
|
2058
|
-
|
|
2059
|
-
/* import */ var _base_app_exception_js__rspack_import_0 = __webpack_require__(
|
|
2060
|
-
/* import */ var _permission_exception_js__rspack_import_1 = __webpack_require__(
|
|
2017
|
+
9448(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2018
|
+
/* import */ var _base_app_exception_js__rspack_import_0 = __webpack_require__(5514);
|
|
2019
|
+
/* import */ var _permission_exception_js__rspack_import_1 = __webpack_require__(8374);
|
|
2061
2020
|
|
|
2062
2021
|
|
|
2063
2022
|
|
|
@@ -2077,7 +2036,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
2077
2036
|
|
|
2078
2037
|
|
|
2079
2038
|
},
|
|
2080
|
-
|
|
2039
|
+
3510(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2081
2040
|
|
|
2082
2041
|
// EXPORTS
|
|
2083
2042
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -2087,13 +2046,13 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
2087
2046
|
});
|
|
2088
2047
|
|
|
2089
2048
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/constants/index.ts
|
|
2090
|
-
var constants = __webpack_require__(
|
|
2091
|
-
// EXTERNAL MODULE: ./projects/nestjs-shared/src/middlewares/logger.middleware.ts +
|
|
2092
|
-
var logger_middleware = __webpack_require__(
|
|
2049
|
+
var constants = __webpack_require__(6043);
|
|
2050
|
+
// EXTERNAL MODULE: ./projects/nestjs-shared/src/middlewares/logger.middleware.ts + 1 modules
|
|
2051
|
+
var logger_middleware = __webpack_require__(8244);
|
|
2093
2052
|
// EXTERNAL MODULE: external "@nestjs/common"
|
|
2094
|
-
var common_ = __webpack_require__(
|
|
2053
|
+
var common_ = __webpack_require__(6157);
|
|
2095
2054
|
// EXTERNAL MODULE: external "@nestjs/core"
|
|
2096
|
-
var core_ = __webpack_require__(
|
|
2055
|
+
var core_ = __webpack_require__(3075);
|
|
2097
2056
|
;// CONCATENATED MODULE: external "@nestjs/passport"
|
|
2098
2057
|
|
|
2099
2058
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/guards/jwt-auth.guard.ts
|
|
@@ -2221,9 +2180,9 @@ OptionalJwtGuard = optional_jwt_auth_guard_ts_decorate([
|
|
|
2221
2180
|
], OptionalJwtGuard);
|
|
2222
2181
|
|
|
2223
2182
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/exceptions/permission.exception.ts
|
|
2224
|
-
var permission_exception = __webpack_require__(
|
|
2183
|
+
var permission_exception = __webpack_require__(8374);
|
|
2225
2184
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/modules/shared-permission-cache/shared-permission-cache.service.ts
|
|
2226
|
-
var shared_permission_cache_service = __webpack_require__(
|
|
2185
|
+
var shared_permission_cache_service = __webpack_require__(4657);
|
|
2227
2186
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/utils/permission-match.util.ts
|
|
2228
2187
|
var permission_match_util = __webpack_require__(788);
|
|
2229
2188
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/guards/permission.guard.ts
|
|
@@ -2273,13 +2232,15 @@ class PermissionGuard {
|
|
|
2273
2232
|
context.getHandler(),
|
|
2274
2233
|
context.getClass()
|
|
2275
2234
|
]);
|
|
2276
|
-
if (
|
|
2235
|
+
if (permissionConfig === undefined || permissionConfig === null) return true;
|
|
2277
2236
|
const request = context.switchToHttp().getRequest();
|
|
2278
2237
|
const user = request.user;
|
|
2279
2238
|
if (!user) throw new common_.UnauthorizedException({
|
|
2280
2239
|
message: 'Authentication required',
|
|
2281
2240
|
messageKey: constants/* .AUTH_MESSAGES.TOKEN_REQUIRED */.mK.TOKEN_REQUIRED
|
|
2282
2241
|
});
|
|
2242
|
+
const logicNode = this.normalizeToLogicNode(permissionConfig);
|
|
2243
|
+
if (!logicNode) throw new permission_exception/* .InsufficientPermissionsException */.z8([], 'AND');
|
|
2283
2244
|
if (!this.permissionCacheService?.isCacheConfigured()) {
|
|
2284
2245
|
throw new permission_exception/* .PermissionSystemUnavailableException */.GS();
|
|
2285
2246
|
}
|
|
@@ -2291,8 +2252,6 @@ class PermissionGuard {
|
|
|
2291
2252
|
if (!userPermissions || userPermissions.length === 0) {
|
|
2292
2253
|
throw new permission_exception/* .NoPermissionsFoundException */.d$();
|
|
2293
2254
|
}
|
|
2294
|
-
const logicNode = this.normalizeToLogicNode(permissionConfig);
|
|
2295
|
-
if (!logicNode) return true;
|
|
2296
2255
|
const result = (0,permission_match_util/* .evaluatePermissionLogic */.Ng)(logicNode, userPermissions);
|
|
2297
2256
|
if (!result.passed) {
|
|
2298
2257
|
throw new permission_exception/* .InsufficientPermissionsException */.z8(result.missingPermissions, result.operator);
|
|
@@ -2300,14 +2259,12 @@ class PermissionGuard {
|
|
|
2300
2259
|
return true;
|
|
2301
2260
|
}
|
|
2302
2261
|
normalizeToLogicNode(config) {
|
|
2303
|
-
// string - single permission
|
|
2304
2262
|
if (typeof config === 'string') {
|
|
2305
2263
|
return config ? {
|
|
2306
2264
|
type: 'action',
|
|
2307
2265
|
actionId: config
|
|
2308
2266
|
} : null;
|
|
2309
2267
|
}
|
|
2310
|
-
// string[] - treat as AND of multiple permissions
|
|
2311
2268
|
if (Array.isArray(config)) {
|
|
2312
2269
|
if (config.length === 0) return null;
|
|
2313
2270
|
if (config.length === 1) return {
|
|
@@ -2323,7 +2280,6 @@ class PermissionGuard {
|
|
|
2323
2280
|
}))
|
|
2324
2281
|
};
|
|
2325
2282
|
}
|
|
2326
|
-
// SimplePermissionConfig - { permissions: string[], operator: 'AND'|'OR' }
|
|
2327
2283
|
if ('permissions' in config && Array.isArray(config.permissions)) {
|
|
2328
2284
|
const simple = config;
|
|
2329
2285
|
if (simple.permissions.length === 0) return null;
|
|
@@ -2340,7 +2296,6 @@ class PermissionGuard {
|
|
|
2340
2296
|
}))
|
|
2341
2297
|
};
|
|
2342
2298
|
}
|
|
2343
|
-
// ILogicNode
|
|
2344
2299
|
return config;
|
|
2345
2300
|
}
|
|
2346
2301
|
}
|
|
@@ -2363,7 +2318,7 @@ PermissionGuard = permission_guard_ts_decorate([
|
|
|
2363
2318
|
|
|
2364
2319
|
|
|
2365
2320
|
},
|
|
2366
|
-
|
|
2321
|
+
6863(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2367
2322
|
|
|
2368
2323
|
// EXPORTS
|
|
2369
2324
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -2374,11 +2329,12 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
2374
2329
|
Ul: () => (/* reexport */ SetDeletedByOnBody),
|
|
2375
2330
|
_x: () => (/* reexport */ SetUpdateByOnBody),
|
|
2376
2331
|
Mw: () => (/* reexport */ Slug),
|
|
2332
|
+
NM: () => (/* reexport */ buildIdempotencyCacheKey),
|
|
2377
2333
|
BR: () => (/* reexport */ createSetUserFieldInterceptor)
|
|
2378
2334
|
});
|
|
2379
2335
|
|
|
2380
2336
|
// EXTERNAL MODULE: external "@nestjs/common"
|
|
2381
|
-
var common_ = __webpack_require__(
|
|
2337
|
+
var common_ = __webpack_require__(6157);
|
|
2382
2338
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/interceptors/delete-empty-id-from-body.interceptor.ts
|
|
2383
2339
|
function _ts_decorate(decorators, target, key, desc) {
|
|
2384
2340
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -2397,19 +2353,13 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
2397
2353
|
class DeleteEmptyIdFromBodyInterceptor {
|
|
2398
2354
|
intercept(context, next) {
|
|
2399
2355
|
const request = context.switchToHttp().getRequest();
|
|
2400
|
-
|
|
2401
|
-
request.body
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
});
|
|
2407
|
-
} else if (typeof request.body === 'object' && request.body !== null) {
|
|
2408
|
-
const item = request.body;
|
|
2409
|
-
if (!item?.id || item?.id === '' || item?.id === null) {
|
|
2410
|
-
delete item.id;
|
|
2356
|
+
const items = Array.isArray(request.body) ? request.body : [
|
|
2357
|
+
request.body
|
|
2358
|
+
];
|
|
2359
|
+
for (const item of items){
|
|
2360
|
+
if (typeof item === 'object' && item !== null && !item['id']) {
|
|
2361
|
+
delete item['id'];
|
|
2411
2362
|
}
|
|
2412
|
-
request.body = item;
|
|
2413
2363
|
}
|
|
2414
2364
|
return next.handle();
|
|
2415
2365
|
}
|
|
@@ -2423,9 +2373,11 @@ DeleteEmptyIdFromBodyInterceptor = _ts_decorate([
|
|
|
2423
2373
|
;// CONCATENATED MODULE: external "rxjs/operators"
|
|
2424
2374
|
|
|
2425
2375
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/classes/hybrid-cache.class.ts + 3 modules
|
|
2426
|
-
var hybrid_cache_class = __webpack_require__(
|
|
2376
|
+
var hybrid_cache_class = __webpack_require__(5375);
|
|
2427
2377
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/constants/index.ts
|
|
2428
|
-
var constants = __webpack_require__(
|
|
2378
|
+
var constants = __webpack_require__(6043);
|
|
2379
|
+
// EXTERNAL MODULE: ./projects/nestjs-shared/src/middlewares/logger.middleware.ts + 1 modules
|
|
2380
|
+
var logger_middleware = __webpack_require__(8244);
|
|
2429
2381
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/interceptors/idempotency.interceptor.ts
|
|
2430
2382
|
function idempotency_interceptor_ts_decorate(decorators, target, key, desc) {
|
|
2431
2383
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -2455,47 +2407,54 @@ function _ts_param(paramIndex, decorator) {
|
|
|
2455
2407
|
|
|
2456
2408
|
|
|
2457
2409
|
|
|
2410
|
+
|
|
2411
|
+
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
2412
|
+
/** Bounds how long a crashed instance can hold a key; no request runs this long */ const PROCESSING_TTL_MS = 10 * 60 * 1000;
|
|
2413
|
+
/**
|
|
2414
|
+
* Replays the stored response for a repeated `X-Idempotency-Key`. A key only ever replays for the
|
|
2415
|
+
* same tenant, user and endpoint, and a failed request releases it so the client can retry.
|
|
2416
|
+
*/ function buildIdempotencyCacheKey(request, idempotencyKey) {
|
|
2417
|
+
const tenant = (0,logger_middleware/* .getTenantId */.EO)() ?? '-';
|
|
2418
|
+
const user = request.user?.id ?? 'anonymous';
|
|
2419
|
+
const endpoint = `${request.method ?? ''} ${request.route?.path ?? request.originalUrl ?? request.url ?? ''}`;
|
|
2420
|
+
return `${constants/* .IDEMPOTENCY_CACHE_PREFIX */.mg}:${tenant}:${user}:${endpoint}:${idempotencyKey}`;
|
|
2421
|
+
}
|
|
2458
2422
|
class IdempotencyInterceptor {
|
|
2459
2423
|
cache;
|
|
2460
|
-
CACHE_TTL = 24 * 60 * 60 * 1000;
|
|
2461
|
-
PROCESSING_MARKER = '__PROCESSING__';
|
|
2462
2424
|
constructor(cache){
|
|
2463
2425
|
this.cache = cache;
|
|
2464
2426
|
}
|
|
2465
2427
|
async intercept(context, next) {
|
|
2466
|
-
|
|
2467
|
-
if (!
|
|
2468
|
-
return next.handle();
|
|
2469
|
-
}
|
|
2428
|
+
const cache = this.cache;
|
|
2429
|
+
if (!cache) return next.handle();
|
|
2470
2430
|
const request = context.switchToHttp().getRequest();
|
|
2471
2431
|
const idempotencyKey = request.headers[constants/* .IDEMPOTENCY_KEY_HEADER */.iH];
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2432
|
+
if (!idempotencyKey || typeof idempotencyKey !== 'string') return next.handle();
|
|
2433
|
+
const cacheKey = buildIdempotencyCacheKey(request, idempotencyKey);
|
|
2434
|
+
const stored = await cache.get(cacheKey, {
|
|
2435
|
+
skipMemory: true
|
|
2436
|
+
});
|
|
2437
|
+
if (stored !== undefined) return (0,__rspack_external_rxjs.of)(stored);
|
|
2438
|
+
// Atomic across instances: of two concurrent requests with one key, exactly one runs
|
|
2439
|
+
if (!await cache.claim(cacheKey, PROCESSING_TTL_MS)) {
|
|
2440
|
+
throw new common_.ConflictException({
|
|
2441
|
+
success: false,
|
|
2442
|
+
message: 'Request is already being processed',
|
|
2443
|
+
messageKey: constants/* .SYSTEM_MESSAGES.DUPLICATE_REQUEST */.hg.DUPLICATE_REQUEST
|
|
2444
|
+
});
|
|
2475
2445
|
}
|
|
2476
|
-
const
|
|
2477
|
-
//
|
|
2478
|
-
const
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
message: 'Request is already being processed',
|
|
2485
|
-
messageKey: constants/* .SYSTEM_MESSAGES.DUPLICATE_REQUEST */.hg.DUPLICATE_REQUEST
|
|
2486
|
-
});
|
|
2487
|
-
}
|
|
2488
|
-
// Return cached response
|
|
2489
|
-
return (0,__rspack_external_rxjs.of)(cached);
|
|
2446
|
+
const release = ()=>cache.releaseClaim(cacheKey).catch(()=>undefined);
|
|
2447
|
+
// The first request may have stored its response and released the claim between our read and claim
|
|
2448
|
+
const storedMeanwhile = await cache.get(cacheKey, {
|
|
2449
|
+
skipMemory: true
|
|
2450
|
+
}).catch(()=>undefined);
|
|
2451
|
+
if (storedMeanwhile !== undefined) {
|
|
2452
|
+
await release();
|
|
2453
|
+
return (0,__rspack_external_rxjs.of)(storedMeanwhile);
|
|
2490
2454
|
}
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
// Process request and cache response
|
|
2495
|
-
return next.handle().pipe((0,__rspack_external_rxjs_operators_2eaa0997.tap)(async (response)=>{
|
|
2496
|
-
// Cache the successful response
|
|
2497
|
-
await cache.set(cacheKey, response, this.CACHE_TTL);
|
|
2498
|
-
}));
|
|
2455
|
+
return next.handle().pipe((0,__rspack_external_rxjs_operators_2eaa0997.concatMap)((response)=>(0,__rspack_external_rxjs.from)(cache.set(cacheKey, response, CACHE_TTL_MS, {
|
|
2456
|
+
skipMemory: true
|
|
2457
|
+
}).catch(()=>undefined).then(release).then(()=>response))), (0,__rspack_external_rxjs_operators_2eaa0997.catchError)((error)=>(0,__rspack_external_rxjs.from)(release()).pipe((0,__rspack_external_rxjs_operators_2eaa0997.concatMap)(()=>(0,__rspack_external_rxjs.throwError)(()=>error)))));
|
|
2499
2458
|
}
|
|
2500
2459
|
}
|
|
2501
2460
|
IdempotencyInterceptor = idempotency_interceptor_ts_decorate([
|
|
@@ -2509,7 +2468,7 @@ IdempotencyInterceptor = idempotency_interceptor_ts_decorate([
|
|
|
2509
2468
|
], IdempotencyInterceptor);
|
|
2510
2469
|
|
|
2511
2470
|
// EXTERNAL MODULE: external "crypto"
|
|
2512
|
-
var external_crypto_ = __webpack_require__(
|
|
2471
|
+
var external_crypto_ = __webpack_require__(7823);
|
|
2513
2472
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/interceptors/response-meta.interceptor.ts
|
|
2514
2473
|
function response_meta_interceptor_ts_decorate(decorators, target, key, desc) {
|
|
2515
2474
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -2600,7 +2559,7 @@ const SetUpdateByOnBody = createSetUserFieldInterceptor('updatedById');
|
|
|
2600
2559
|
const SetDeletedByOnBody = createSetUserFieldInterceptor('deletedById');
|
|
2601
2560
|
|
|
2602
2561
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/modules/utils/utils.service.ts
|
|
2603
|
-
var utils_service = __webpack_require__(
|
|
2562
|
+
var utils_service = __webpack_require__(1169);
|
|
2604
2563
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/interceptors/slug.interceptor.ts
|
|
2605
2564
|
function slug_interceptor_ts_decorate(decorators, target, key, desc) {
|
|
2606
2565
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -2634,26 +2593,18 @@ class Slug {
|
|
|
2634
2593
|
}
|
|
2635
2594
|
intercept(context, next) {
|
|
2636
2595
|
const request = context.switchToHttp().getRequest();
|
|
2637
|
-
|
|
2638
|
-
request.body = request.body.map((item)=>{
|
|
2639
|
-
// Only generate slug if not provided and name exists
|
|
2640
|
-
if (!item.slug && item?.name) {
|
|
2641
|
-
return {
|
|
2642
|
-
...item,
|
|
2643
|
-
slug: this.utilsService.transformToSlug(item.name)
|
|
2644
|
-
};
|
|
2645
|
-
}
|
|
2646
|
-
return item;
|
|
2647
|
-
});
|
|
2648
|
-
} else if (!request.body?.slug && request.body?.name) {
|
|
2649
|
-
// Only generate slug if not provided and name exists
|
|
2650
|
-
request.body = {
|
|
2651
|
-
...request.body,
|
|
2652
|
-
slug: this.utilsService.transformToSlug(request.body.name)
|
|
2653
|
-
};
|
|
2654
|
-
}
|
|
2596
|
+
request.body = Array.isArray(request.body) ? request.body.map((item)=>this.withSlug(item)) : this.withSlug(request.body);
|
|
2655
2597
|
return next.handle();
|
|
2656
2598
|
}
|
|
2599
|
+
withSlug(item) {
|
|
2600
|
+
if (typeof item !== 'object' || item === null || Array.isArray(item)) return item;
|
|
2601
|
+
const body = item;
|
|
2602
|
+
if (body['slug'] || typeof body['name'] !== 'string' || !body['name']) return item;
|
|
2603
|
+
return {
|
|
2604
|
+
...body,
|
|
2605
|
+
slug: this.utilsService.transformToSlug(body['name'])
|
|
2606
|
+
};
|
|
2607
|
+
}
|
|
2657
2608
|
}
|
|
2658
2609
|
Slug = slug_interceptor_ts_decorate([
|
|
2659
2610
|
(0,common_.Injectable)(),
|
|
@@ -2673,7 +2624,7 @@ Slug = slug_interceptor_ts_decorate([
|
|
|
2673
2624
|
|
|
2674
2625
|
|
|
2675
2626
|
},
|
|
2676
|
-
|
|
2627
|
+
3928(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2677
2628
|
|
|
2678
2629
|
// EXPORTS
|
|
2679
2630
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -2683,11 +2634,11 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
2683
2634
|
});
|
|
2684
2635
|
|
|
2685
2636
|
// EXTERNAL MODULE: external "@nestjs/common"
|
|
2686
|
-
var common_ = __webpack_require__(
|
|
2637
|
+
var common_ = __webpack_require__(6157);
|
|
2687
2638
|
// EXTERNAL MODULE: external "class-validator"
|
|
2688
|
-
var external_class_validator_ = __webpack_require__(
|
|
2639
|
+
var external_class_validator_ = __webpack_require__(5421);
|
|
2689
2640
|
// EXTERNAL MODULE: ./projects/nestjs-shared/src/constants/message-keys.ts
|
|
2690
|
-
var message_keys = __webpack_require__(
|
|
2641
|
+
var message_keys = __webpack_require__(4389);
|
|
2691
2642
|
;// CONCATENATED MODULE: ./projects/nestjs-shared/src/pipes/dto-body-validation.pipe.ts
|
|
2692
2643
|
|
|
2693
2644
|
|
|
@@ -2782,7 +2733,7 @@ function declaresProperty(dto, key) {
|
|
|
2782
2733
|
|
|
2783
2734
|
|
|
2784
2735
|
},
|
|
2785
|
-
|
|
2736
|
+
8154(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2786
2737
|
/**
|
|
2787
2738
|
* The tenant a cache key belongs to: the provider's current tenant in multi-tenant mode, else
|
|
2788
2739
|
* undefined. A single database never prefixes, so a stray tenant header cannot split its cache.
|