@nest-omni/core 3.1.2-8 → 4.1.2-9
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/audit/audit.module.d.ts +10 -0
- package/audit/audit.module.js +231 -0
- package/audit/controllers/audit.controller.d.ts +20 -0
- package/audit/controllers/audit.controller.js +142 -0
- package/audit/controllers/index.d.ts +1 -0
- package/audit/controllers/index.js +17 -0
- package/audit/decorators/audit-controller.decorator.d.ts +5 -0
- package/audit/decorators/audit-controller.decorator.js +17 -0
- package/audit/decorators/audit-operation.decorator.d.ts +5 -0
- package/audit/decorators/audit-operation.decorator.js +23 -0
- package/audit/decorators/entity-audit.decorator.d.ts +5 -0
- package/audit/decorators/entity-audit.decorator.js +19 -0
- package/audit/decorators/index.d.ts +2 -0
- package/audit/decorators/index.js +18 -0
- package/audit/dto/audit-log-query.dto.d.ts +14 -0
- package/audit/dto/audit-log-query.dto.js +95 -0
- package/audit/dto/begin-transaction.dto.d.ts +3 -0
- package/audit/dto/begin-transaction.dto.js +22 -0
- package/audit/dto/compare-entities.dto.d.ts +6 -0
- package/audit/dto/compare-entities.dto.js +44 -0
- package/audit/dto/index.d.ts +5 -0
- package/audit/dto/index.js +21 -0
- package/audit/dto/pre-check-restore.dto.d.ts +5 -0
- package/audit/dto/pre-check-restore.dto.js +32 -0
- package/audit/dto/restore-entity.dto.d.ts +9 -0
- package/audit/dto/restore-entity.dto.js +53 -0
- package/audit/entities/entity-audit-log.entity.d.ts +18 -0
- package/audit/entities/entity-audit-log.entity.js +81 -0
- package/audit/entities/entity-transaction.entity.d.ts +14 -0
- package/audit/entities/entity-transaction.entity.js +51 -0
- package/audit/entities/index.d.ts +2 -0
- package/audit/entities/index.js +18 -0
- package/audit/entities/manual-operation-log.entity.d.ts +15 -0
- package/audit/entities/manual-operation-log.entity.js +82 -0
- package/audit/entities/operation-template.entity.d.ts +11 -0
- package/audit/entities/operation-template.entity.js +65 -0
- package/audit/enums/audit.enums.d.ts +27 -0
- package/audit/enums/audit.enums.js +35 -0
- package/audit/enums/index.d.ts +1 -0
- package/audit/enums/index.js +17 -0
- package/audit/index.d.ts +10 -0
- package/audit/index.js +26 -0
- package/audit/interceptors/audit.interceptor.d.ts +12 -0
- package/audit/interceptors/audit.interceptor.js +95 -0
- package/audit/interceptors/index.d.ts +1 -0
- package/audit/interceptors/index.js +17 -0
- package/audit/interfaces/audit.interfaces.d.ts +119 -0
- package/audit/interfaces/audit.interfaces.js +2 -0
- package/audit/interfaces/index.d.ts +1 -0
- package/audit/interfaces/index.js +17 -0
- package/audit/services/audit-context.service.d.ts +10 -0
- package/audit/services/audit-context.service.js +55 -0
- package/audit/services/audit-strategy.service.d.ts +19 -0
- package/audit/services/audit-strategy.service.js +89 -0
- package/audit/services/entity-audit.service.d.ts +37 -0
- package/audit/services/entity-audit.service.js +484 -0
- package/audit/services/index.d.ts +5 -0
- package/audit/services/index.js +21 -0
- package/audit/services/manual-audit-log.service.d.ts +29 -0
- package/audit/services/manual-audit-log.service.js +184 -0
- package/audit/services/multi-database.service.d.ts +10 -0
- package/audit/services/multi-database.service.js +59 -0
- package/audit/services/operation-description.service.d.ts +21 -0
- package/audit/services/operation-description.service.js +213 -0
- package/audit/services/transaction-audit.service.d.ts +22 -0
- package/audit/services/transaction-audit.service.js +201 -0
- package/audit/subscribers/entity-audit.subscriber.d.ts +14 -0
- package/audit/subscribers/entity-audit.subscriber.js +136 -0
- package/audit/subscribers/index.d.ts +1 -0
- package/audit/subscribers/index.js +17 -0
- package/common/abstract.entity.js +1 -1
- package/http-client/examples/advanced-usage.example.js +14 -1
- package/http-client/examples/auth-with-waiting-lock.example.d.ts +17 -0
- package/http-client/examples/auth-with-waiting-lock.example.js +336 -0
- package/http-client/examples/basic-usage.example.d.ts +1 -9
- package/http-client/examples/basic-usage.example.js +4 -14
- package/http-client/examples/multi-api-configuration.example.js +4 -4
- package/http-client/http-client.module.js +7 -4
- package/http-client/services/api-client-registry.service.d.ts +2 -1
- package/http-client/services/api-client-registry.service.js +2 -1
- package/http-client/services/http-client.service.d.ts +18 -1
- package/http-client/services/http-client.service.js +123 -3
- package/http-client/services/http-log-query.service.d.ts +20 -0
- package/http-client/services/http-log-query.service.js +176 -0
- package/http-client/services/http-replay.service.d.ts +58 -0
- package/http-client/services/http-replay.service.js +266 -0
- package/http-client/services/log-cleanup.service.js +2 -2
- package/http-client/services/logging.service.js +1 -1
- package/http-client/utils/request-id.util.d.ts +4 -0
- package/http-client/utils/request-id.util.js +34 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +1 -1
- package/setup/bootstrap.setup.js +5 -1
|
@@ -30,12 +30,14 @@ const decorators_1 = require("../decorators");
|
|
|
30
30
|
const context_extractor_util_1 = require("../utils/context-extractor.util");
|
|
31
31
|
const curl_generator_util_1 = require("../utils/curl-generator.util");
|
|
32
32
|
const retry_recorder_util_1 = require("../utils/retry-recorder.util");
|
|
33
|
-
const request_id_util_1 = require("
|
|
33
|
+
const request_id_util_1 = require("../utils/request-id.util");
|
|
34
|
+
const redis_lock_service_1 = require("../../redis-lock/redis-lock.service");
|
|
34
35
|
let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
35
|
-
constructor(circuitBreakerService, loggingService, cacheService, config = {}) {
|
|
36
|
+
constructor(circuitBreakerService, loggingService, cacheService, redisLockService, config = {}) {
|
|
36
37
|
this.circuitBreakerService = circuitBreakerService;
|
|
37
38
|
this.loggingService = loggingService;
|
|
38
39
|
this.cacheService = cacheService;
|
|
40
|
+
this.redisLockService = redisLockService;
|
|
39
41
|
this.logger = new common_1.Logger(HttpClientService_1.name);
|
|
40
42
|
this.requestStats = {
|
|
41
43
|
totalRequests: 0,
|
|
@@ -182,6 +184,123 @@ let HttpClientService = HttpClientService_1 = class HttpClientService {
|
|
|
182
184
|
return this.request(Object.assign(Object.assign({}, config), { method: 'DELETE', url }));
|
|
183
185
|
});
|
|
184
186
|
}
|
|
187
|
+
authRequest(config, tokenProvider, options) {
|
|
188
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
189
|
+
if (!this.redisLockService) {
|
|
190
|
+
this.logger.warn('RedisLockService not available, proceeding without lock');
|
|
191
|
+
return this.request(config);
|
|
192
|
+
}
|
|
193
|
+
const { lockKey = `auth-request:${(0, request_id_util_1.generateRequestId)()}`, lockTimeout = 30000, waitTimeout = 60000, enableRetry = true, } = options || {};
|
|
194
|
+
try {
|
|
195
|
+
const result = yield this.redisLockService.withLock(lockKey, () => __awaiter(this, void 0, void 0, function* () {
|
|
196
|
+
const token = yield tokenProvider();
|
|
197
|
+
const authConfig = Object.assign(Object.assign({}, config), { headers: Object.assign(Object.assign({}, config.headers), { Authorization: `Bearer ${token}` }) });
|
|
198
|
+
return this.request(authConfig);
|
|
199
|
+
}), {
|
|
200
|
+
ttl: lockTimeout,
|
|
201
|
+
retryCount: enableRetry ? 3 : 0,
|
|
202
|
+
retryDelay: 1000,
|
|
203
|
+
strategy: 'SKIP',
|
|
204
|
+
});
|
|
205
|
+
if (result === null) {
|
|
206
|
+
throw new Error(`Failed to acquire lock for auth request: ${lockKey}`);
|
|
207
|
+
}
|
|
208
|
+
return result;
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
this.logger.error(`Auth request failed with lock ${lockKey}`, error);
|
|
212
|
+
if (enableRetry && error.message.includes('Failed to acquire lock')) {
|
|
213
|
+
this.logger.warn('Retrying auth request without lock');
|
|
214
|
+
const token = yield tokenProvider();
|
|
215
|
+
const authConfig = Object.assign(Object.assign({}, config), { headers: Object.assign(Object.assign({}, config.headers), { Authorization: `Bearer ${token}` }) });
|
|
216
|
+
return this.request(authConfig);
|
|
217
|
+
}
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
authBatchRequest(requests, tokenProvider, options) {
|
|
223
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
224
|
+
if (!this.redisLockService) {
|
|
225
|
+
this.logger.warn('RedisLockService not available, proceeding batch auth requests without lock');
|
|
226
|
+
const token = yield tokenProvider();
|
|
227
|
+
const promises = requests.map((request) => __awaiter(this, void 0, void 0, function* () {
|
|
228
|
+
try {
|
|
229
|
+
const authConfig = Object.assign(Object.assign({}, request.config), { headers: Object.assign(Object.assign({}, request.config.headers), { Authorization: `Bearer ${token}` }) });
|
|
230
|
+
return yield this.request(authConfig);
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
this.logger.error(`Batch auth request failed for key: ${request.key}`, error);
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
}));
|
|
237
|
+
return Promise.all(promises);
|
|
238
|
+
}
|
|
239
|
+
const { lockKey = `batch-auth-request:${(0, request_id_util_1.generateRequestId)()}`, lockTimeout = 60000, waitTimeout = 120000, maxConcurrency = 5, } = options || {};
|
|
240
|
+
try {
|
|
241
|
+
const results = yield this.redisLockService.withLock(lockKey, () => __awaiter(this, void 0, void 0, function* () {
|
|
242
|
+
const token = yield tokenProvider();
|
|
243
|
+
const semaphore = new Array(maxConcurrency).fill(null);
|
|
244
|
+
const results = new Array(requests.length);
|
|
245
|
+
const executing = new Set();
|
|
246
|
+
const executeRequest = (requestConfig, key, index) => __awaiter(this, void 0, void 0, function* () {
|
|
247
|
+
try {
|
|
248
|
+
const authConfig = Object.assign(Object.assign({}, requestConfig), { headers: Object.assign(Object.assign({}, requestConfig.headers), { Authorization: `Bearer ${token}` }) });
|
|
249
|
+
const result = yield this.request(authConfig);
|
|
250
|
+
results[index] = result;
|
|
251
|
+
return result;
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
this.logger.error(`Batch auth request failed for key: ${key}`, error);
|
|
255
|
+
results[index] = null;
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
finally {
|
|
259
|
+
executing.delete(key);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
const promises = requests.map((request, index) => __awaiter(this, void 0, void 0, function* () {
|
|
263
|
+
return new Promise((resolve, reject) => {
|
|
264
|
+
const checkSlot = () => {
|
|
265
|
+
const slotIndex = semaphore.findIndex((slot) => slot === null);
|
|
266
|
+
if (slotIndex !== -1) {
|
|
267
|
+
semaphore[slotIndex] = { resolve, reject };
|
|
268
|
+
executeRequest(request.config, request.key, index)
|
|
269
|
+
.then(() => {
|
|
270
|
+
semaphore[slotIndex] = null;
|
|
271
|
+
resolve();
|
|
272
|
+
})
|
|
273
|
+
.catch((error) => {
|
|
274
|
+
semaphore[slotIndex] = null;
|
|
275
|
+
reject(error);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
setTimeout(checkSlot, 10);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
checkSlot();
|
|
283
|
+
});
|
|
284
|
+
}));
|
|
285
|
+
yield Promise.all(promises);
|
|
286
|
+
return results;
|
|
287
|
+
}), {
|
|
288
|
+
ttl: lockTimeout,
|
|
289
|
+
retryCount: 2,
|
|
290
|
+
retryDelay: 2000,
|
|
291
|
+
strategy: 'SKIP',
|
|
292
|
+
});
|
|
293
|
+
if (results === null) {
|
|
294
|
+
throw new Error(`Failed to acquire lock for batch auth request: ${lockKey}`);
|
|
295
|
+
}
|
|
296
|
+
return results;
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
this.logger.error(`Batch auth request failed with lock ${lockKey}`, error);
|
|
300
|
+
throw error;
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
185
304
|
createAxiosInstance() {
|
|
186
305
|
var _a, _b;
|
|
187
306
|
const instance = require('axios').create({
|
|
@@ -380,5 +499,6 @@ exports.HttpClientService = HttpClientService = HttpClientService_1 = __decorate
|
|
|
380
499
|
(0, common_1.Injectable)(),
|
|
381
500
|
__metadata("design:paramtypes", [circuit_breaker_service_1.HttpCircuitBreakerService,
|
|
382
501
|
logging_service_1.HttpLoggingService,
|
|
383
|
-
cache_service_1.HttpCacheService,
|
|
502
|
+
cache_service_1.HttpCacheService,
|
|
503
|
+
redis_lock_service_1.RedisLockService, Object])
|
|
384
504
|
], HttpClientService);
|
|
@@ -49,8 +49,28 @@ export declare class HttpLogQueryService {
|
|
|
49
49
|
}): Promise<HttpLogStats>;
|
|
50
50
|
deleteOldLogs(daysToKeep?: number): Promise<number>;
|
|
51
51
|
clearAllLogs(): Promise<number>;
|
|
52
|
+
generateCurlFromLog(logId: string): Promise<string | null>;
|
|
53
|
+
generateCurlFromRequestId(requestId: string): Promise<string | null>;
|
|
54
|
+
generateReplayConfigFromLog(logId: string): Promise<any | null>;
|
|
55
|
+
generateReplayConfigFromRequestId(requestId: string): Promise<any | null>;
|
|
56
|
+
generateBatchCurlCommands(options?: HttpLogQueryOptions): Promise<Array<{
|
|
57
|
+
logId: string;
|
|
58
|
+
requestId?: string;
|
|
59
|
+
curlCommand: string;
|
|
60
|
+
}>>;
|
|
61
|
+
getLogReplayInfo(logId: string): Promise<{
|
|
62
|
+
log: HttpLogEntity;
|
|
63
|
+
curlCommand: string | null;
|
|
64
|
+
replayConfig: any | null;
|
|
65
|
+
} | null>;
|
|
66
|
+
getLogReplayInfoByRequestId(requestId: string): Promise<{
|
|
67
|
+
log: HttpLogEntity;
|
|
68
|
+
curlCommand: string | null;
|
|
69
|
+
replayConfig: any | null;
|
|
70
|
+
} | null>;
|
|
52
71
|
private initializeRepository;
|
|
53
72
|
private calculatePercentiles;
|
|
54
73
|
private formatStats;
|
|
55
74
|
private buildQuery;
|
|
75
|
+
private sanitizeHeadersForCurl;
|
|
56
76
|
}
|
|
@@ -23,6 +23,7 @@ exports.HttpLogQueryService = void 0;
|
|
|
23
23
|
const common_1 = require("@nestjs/common");
|
|
24
24
|
const typeorm_1 = require("typeorm");
|
|
25
25
|
const http_log_entity_1 = require("../entities/http-log.entity");
|
|
26
|
+
const curl_generator_util_1 = require("../utils/curl-generator.util");
|
|
26
27
|
let HttpLogQueryService = HttpLogQueryService_1 = class HttpLogQueryService {
|
|
27
28
|
constructor(dataSource) {
|
|
28
29
|
this.dataSource = dataSource;
|
|
@@ -255,6 +256,164 @@ let HttpLogQueryService = HttpLogQueryService_1 = class HttpLogQueryService {
|
|
|
255
256
|
return 0;
|
|
256
257
|
});
|
|
257
258
|
}
|
|
259
|
+
generateCurlFromLog(logId) {
|
|
260
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
261
|
+
if (!this.logRepository) {
|
|
262
|
+
throw new Error('HTTP log repository not available');
|
|
263
|
+
}
|
|
264
|
+
const log = yield this.logRepository.findOne({
|
|
265
|
+
where: { id: logId },
|
|
266
|
+
});
|
|
267
|
+
if (!log) {
|
|
268
|
+
this.logger.warn(`Log with ID ${logId} not found`);
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
const sanitizedHeaders = this.sanitizeHeadersForCurl(log.headers || {});
|
|
273
|
+
const requestConfig = {
|
|
274
|
+
method: log.method,
|
|
275
|
+
url: log.url,
|
|
276
|
+
headers: sanitizedHeaders,
|
|
277
|
+
data: log.body,
|
|
278
|
+
params: log.params,
|
|
279
|
+
};
|
|
280
|
+
const curlCommand = curl_generator_util_1.CurlGenerator.generateCurlCommand(requestConfig);
|
|
281
|
+
this.logger.log(`Generated curl command for log ${logId}`);
|
|
282
|
+
return curlCommand;
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
this.logger.error(`Failed to generate curl command for log ${logId}`, error);
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
generateCurlFromRequestId(requestId) {
|
|
291
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
292
|
+
if (!this.logRepository) {
|
|
293
|
+
throw new Error('HTTP log repository not available');
|
|
294
|
+
}
|
|
295
|
+
const log = yield this.logRepository.findOne({
|
|
296
|
+
where: { requestId },
|
|
297
|
+
order: { createdAt: 'DESC' },
|
|
298
|
+
});
|
|
299
|
+
if (!log) {
|
|
300
|
+
this.logger.warn(`Log with requestId ${requestId} not found`);
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
return this.generateCurlFromLog(log.id);
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
generateReplayConfigFromLog(logId) {
|
|
307
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
308
|
+
if (!this.logRepository) {
|
|
309
|
+
throw new Error('HTTP log repository not available');
|
|
310
|
+
}
|
|
311
|
+
const log = yield this.logRepository.findOne({
|
|
312
|
+
where: { id: logId },
|
|
313
|
+
});
|
|
314
|
+
if (!log) {
|
|
315
|
+
this.logger.warn(`Log with ID ${logId} not found`);
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
const replayConfig = {
|
|
320
|
+
method: log.method,
|
|
321
|
+
url: log.url,
|
|
322
|
+
headers: log.headers || {},
|
|
323
|
+
data: log.body
|
|
324
|
+
? typeof log.body === 'string'
|
|
325
|
+
? JSON.parse(log.body)
|
|
326
|
+
: log.body
|
|
327
|
+
: undefined,
|
|
328
|
+
params: log.params || {},
|
|
329
|
+
metadata: {
|
|
330
|
+
originalLogId: log.id,
|
|
331
|
+
originalRequestId: log.requestId,
|
|
332
|
+
replayTimestamp: new Date().toISOString(),
|
|
333
|
+
replayedBy: 'http-log-query-service',
|
|
334
|
+
},
|
|
335
|
+
};
|
|
336
|
+
this.logger.log(`Generated replay config for log ${logId}`);
|
|
337
|
+
return replayConfig;
|
|
338
|
+
}
|
|
339
|
+
catch (error) {
|
|
340
|
+
this.logger.error(`Failed to generate replay config for log ${logId}`, error);
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
generateReplayConfigFromRequestId(requestId) {
|
|
346
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
347
|
+
if (!this.logRepository) {
|
|
348
|
+
throw new Error('HTTP log repository not available');
|
|
349
|
+
}
|
|
350
|
+
const log = yield this.logRepository.findOne({
|
|
351
|
+
where: { requestId },
|
|
352
|
+
order: { createdAt: 'DESC' },
|
|
353
|
+
});
|
|
354
|
+
if (!log) {
|
|
355
|
+
this.logger.warn(`Log with requestId ${requestId} not found`);
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
return this.generateReplayConfigFromLog(log.id);
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
generateBatchCurlCommands() {
|
|
362
|
+
return __awaiter(this, arguments, void 0, function* (options = {}) {
|
|
363
|
+
if (!this.logRepository) {
|
|
364
|
+
throw new Error('HTTP log repository not available');
|
|
365
|
+
}
|
|
366
|
+
const limitedOptions = Object.assign(Object.assign({}, options), { limit: Math.min(options.limit || 10, 50) });
|
|
367
|
+
const result = yield this.findLogs(limitedOptions);
|
|
368
|
+
const curlCommands = [];
|
|
369
|
+
for (const log of result.logs) {
|
|
370
|
+
try {
|
|
371
|
+
const curlCommand = yield this.generateCurlFromLog(log.id);
|
|
372
|
+
if (curlCommand) {
|
|
373
|
+
curlCommands.push({
|
|
374
|
+
logId: log.id,
|
|
375
|
+
requestId: log.requestId,
|
|
376
|
+
curlCommand,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
this.logger.warn(`Failed to generate curl for log ${log.id}`, error);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
this.logger.log(`Generated ${curlCommands.length} curl commands`);
|
|
385
|
+
return curlCommands;
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
getLogReplayInfo(logId) {
|
|
389
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
390
|
+
if (!this.logRepository) {
|
|
391
|
+
throw new Error('HTTP log repository not available');
|
|
392
|
+
}
|
|
393
|
+
const log = yield this.findLogById(logId, true);
|
|
394
|
+
if (!log) {
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
const [curlCommand, replayConfig] = yield Promise.all([
|
|
398
|
+
this.generateCurlFromLog(logId),
|
|
399
|
+
this.generateReplayConfigFromLog(logId),
|
|
400
|
+
]);
|
|
401
|
+
return {
|
|
402
|
+
log,
|
|
403
|
+
curlCommand,
|
|
404
|
+
replayConfig,
|
|
405
|
+
};
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
getLogReplayInfoByRequestId(requestId) {
|
|
409
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
410
|
+
const log = yield this.findLogByRequestId(requestId);
|
|
411
|
+
if (!log) {
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
return this.getLogReplayInfo(log.id);
|
|
415
|
+
});
|
|
416
|
+
}
|
|
258
417
|
initializeRepository() {
|
|
259
418
|
if (this.dataSource) {
|
|
260
419
|
try {
|
|
@@ -406,6 +565,23 @@ let HttpLogQueryService = HttpLogQueryService_1 = class HttpLogQueryService {
|
|
|
406
565
|
}
|
|
407
566
|
return queryBuilder;
|
|
408
567
|
}
|
|
568
|
+
sanitizeHeadersForCurl(headers) {
|
|
569
|
+
const sensitiveHeaders = [
|
|
570
|
+
'authorization',
|
|
571
|
+
'apikey',
|
|
572
|
+
'x-api-key',
|
|
573
|
+
'x-auth-token',
|
|
574
|
+
'cookie',
|
|
575
|
+
'set-cookie',
|
|
576
|
+
];
|
|
577
|
+
const sanitized = Object.assign({}, headers);
|
|
578
|
+
for (const header of sensitiveHeaders) {
|
|
579
|
+
if (sanitized[header]) {
|
|
580
|
+
sanitized[header] = '***REDACTED***';
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
return sanitized;
|
|
584
|
+
}
|
|
409
585
|
};
|
|
410
586
|
exports.HttpLogQueryService = HttpLogQueryService;
|
|
411
587
|
exports.HttpLogQueryService = HttpLogQueryService = HttpLogQueryService_1 = __decorate([
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { AxiosRequestConfig } from 'axios';
|
|
2
|
+
import { HttpClientService } from './http-client.service';
|
|
3
|
+
import { HttpLogQueryService } from './http-log-query.service';
|
|
4
|
+
import { HttpLogEntity } from '../entities/http-log.entity';
|
|
5
|
+
export interface HttpReplayOptions {
|
|
6
|
+
overrideHeaders?: boolean;
|
|
7
|
+
overrideBody?: boolean;
|
|
8
|
+
overrideParams?: boolean;
|
|
9
|
+
additionalHeaders?: Record<string, string>;
|
|
10
|
+
metadata?: Record<string, any>;
|
|
11
|
+
logReplay?: boolean;
|
|
12
|
+
timeout?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface HttpReplayResult {
|
|
15
|
+
originalLog: HttpLogEntity;
|
|
16
|
+
requestConfig: AxiosRequestConfig;
|
|
17
|
+
response: any;
|
|
18
|
+
responseTime: number;
|
|
19
|
+
success: boolean;
|
|
20
|
+
error?: string;
|
|
21
|
+
replayTimestamp: string;
|
|
22
|
+
replayId: string;
|
|
23
|
+
}
|
|
24
|
+
export interface BatchReplayResult {
|
|
25
|
+
totalRequests: number;
|
|
26
|
+
successfulRequests: number;
|
|
27
|
+
failedRequests: number;
|
|
28
|
+
successRate: number;
|
|
29
|
+
totalResponseTime: number;
|
|
30
|
+
averageResponseTime: number;
|
|
31
|
+
results: HttpReplayResult[];
|
|
32
|
+
}
|
|
33
|
+
export declare class HttpReplayService {
|
|
34
|
+
private readonly httpClient;
|
|
35
|
+
private readonly logQueryService;
|
|
36
|
+
private readonly logger;
|
|
37
|
+
constructor(httpClient: HttpClientService, logQueryService: HttpLogQueryService);
|
|
38
|
+
replayByLogId(logId: string, options?: HttpReplayOptions): Promise<HttpReplayResult>;
|
|
39
|
+
replayByRequestId(requestId: string, options?: HttpReplayOptions): Promise<HttpReplayResult>;
|
|
40
|
+
batchReplay(logIds: string[], options?: HttpReplayOptions, concurrency?: number): Promise<BatchReplayResult>;
|
|
41
|
+
batchReplayByQuery(queryOptions?: any, replayOptions?: HttpReplayOptions, concurrency?: number): Promise<BatchReplayResult>;
|
|
42
|
+
replayAndCompare(logId: string, options?: HttpReplayOptions): Promise<{
|
|
43
|
+
original: HttpLogEntity;
|
|
44
|
+
replay: HttpReplayResult;
|
|
45
|
+
comparison: {
|
|
46
|
+
statusMatch: boolean;
|
|
47
|
+
responseTimeDifference: number;
|
|
48
|
+
headersMatch: boolean;
|
|
49
|
+
bodyMatch: boolean;
|
|
50
|
+
};
|
|
51
|
+
}>;
|
|
52
|
+
private buildReplayConfig;
|
|
53
|
+
private executeReplayRequest;
|
|
54
|
+
private generateReplayId;
|
|
55
|
+
private chunkArray;
|
|
56
|
+
private compareHeaders;
|
|
57
|
+
private compareBodies;
|
|
58
|
+
}
|