@nest-omni/core 3.1.2-7 → 3.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.
Files changed (138) hide show
  1. package/audit/audit.module.d.ts +10 -0
  2. package/audit/audit.module.js +254 -0
  3. package/audit/controllers/audit.controller.d.ts +20 -0
  4. package/audit/controllers/audit.controller.js +142 -0
  5. package/audit/controllers/index.d.ts +1 -0
  6. package/audit/controllers/index.js +17 -0
  7. package/audit/decorators/audit-controller.decorator.d.ts +5 -0
  8. package/audit/decorators/audit-controller.decorator.js +17 -0
  9. package/audit/decorators/audit-operation.decorator.d.ts +7 -0
  10. package/audit/decorators/audit-operation.decorator.js +25 -0
  11. package/audit/decorators/entity-audit.decorator.d.ts +10 -0
  12. package/audit/decorators/entity-audit.decorator.js +70 -0
  13. package/audit/decorators/index.d.ts +3 -0
  14. package/audit/decorators/index.js +19 -0
  15. package/audit/dto/audit-log-query.dto.d.ts +14 -0
  16. package/audit/dto/audit-log-query.dto.js +95 -0
  17. package/audit/dto/begin-transaction.dto.d.ts +3 -0
  18. package/audit/dto/begin-transaction.dto.js +22 -0
  19. package/audit/dto/compare-entities.dto.d.ts +6 -0
  20. package/audit/dto/compare-entities.dto.js +44 -0
  21. package/audit/dto/index.d.ts +5 -0
  22. package/audit/dto/index.js +21 -0
  23. package/audit/dto/pre-check-restore.dto.d.ts +5 -0
  24. package/audit/dto/pre-check-restore.dto.js +32 -0
  25. package/audit/dto/restore-entity.dto.d.ts +9 -0
  26. package/audit/dto/restore-entity.dto.js +53 -0
  27. package/audit/entities/entity-audit-log.entity.d.ts +23 -0
  28. package/audit/entities/entity-audit-log.entity.js +110 -0
  29. package/audit/entities/entity-transaction.entity.d.ts +21 -0
  30. package/audit/entities/entity-transaction.entity.js +80 -0
  31. package/audit/entities/index.d.ts +4 -0
  32. package/audit/entities/index.js +20 -0
  33. package/audit/entities/manual-operation-log.entity.d.ts +13 -0
  34. package/audit/entities/manual-operation-log.entity.js +65 -0
  35. package/audit/entities/operation-template.entity.d.ts +11 -0
  36. package/audit/entities/operation-template.entity.js +65 -0
  37. package/audit/enums/audit.enums.d.ts +42 -0
  38. package/audit/enums/audit.enums.js +53 -0
  39. package/audit/enums/index.d.ts +1 -0
  40. package/audit/enums/index.js +17 -0
  41. package/audit/index.d.ts +12 -0
  42. package/audit/index.js +48 -0
  43. package/audit/interceptors/audit.interceptor.d.ts +12 -0
  44. package/audit/interceptors/audit.interceptor.js +95 -0
  45. package/audit/interceptors/index.d.ts +1 -0
  46. package/audit/interceptors/index.js +17 -0
  47. package/audit/interfaces/audit.interfaces.d.ts +180 -0
  48. package/audit/interfaces/audit.interfaces.js +2 -0
  49. package/audit/interfaces/index.d.ts +1 -0
  50. package/audit/interfaces/index.js +17 -0
  51. package/audit/services/audit-context.service.d.ts +10 -0
  52. package/audit/services/audit-context.service.js +55 -0
  53. package/audit/services/audit-strategy.service.d.ts +19 -0
  54. package/audit/services/audit-strategy.service.js +89 -0
  55. package/audit/services/entity-audit.service.d.ts +65 -0
  56. package/audit/services/entity-audit.service.js +626 -0
  57. package/audit/services/index.d.ts +6 -0
  58. package/audit/services/index.js +22 -0
  59. package/audit/services/multi-database.service.d.ts +10 -0
  60. package/audit/services/multi-database.service.js +59 -0
  61. package/audit/services/operation-description.service.d.ts +21 -0
  62. package/audit/services/operation-description.service.js +213 -0
  63. package/audit/services/transaction-audit.service.d.ts +22 -0
  64. package/audit/services/transaction-audit.service.js +201 -0
  65. package/audit/subscribers/entity-audit.subscriber.d.ts +14 -0
  66. package/audit/subscribers/entity-audit.subscriber.js +136 -0
  67. package/audit/subscribers/index.d.ts +1 -0
  68. package/audit/subscribers/index.js +17 -0
  69. package/common/utils.d.ts +1 -0
  70. package/common/utils.js +6 -0
  71. package/http-client/config/http-client.config.d.ts +6 -0
  72. package/http-client/config/http-client.config.js +87 -0
  73. package/http-client/config/index.d.ts +1 -0
  74. package/http-client/config/index.js +17 -0
  75. package/http-client/decorators/http-client.decorators.d.ts +72 -0
  76. package/http-client/decorators/http-client.decorators.js +204 -0
  77. package/http-client/decorators/index.d.ts +1 -0
  78. package/http-client/decorators/index.js +17 -0
  79. package/http-client/entities/http-log.entity.d.ts +98 -0
  80. package/http-client/entities/http-log.entity.js +143 -0
  81. package/http-client/entities/index.d.ts +1 -0
  82. package/http-client/entities/index.js +17 -0
  83. package/http-client/errors/http-client.errors.d.ts +56 -0
  84. package/http-client/errors/http-client.errors.js +149 -0
  85. package/http-client/errors/index.d.ts +1 -0
  86. package/http-client/errors/index.js +17 -0
  87. package/http-client/examples/advanced-usage.example.d.ts +23 -0
  88. package/http-client/examples/advanced-usage.example.js +332 -0
  89. package/http-client/examples/auth-with-waiting-lock.example.d.ts +17 -0
  90. package/http-client/examples/auth-with-waiting-lock.example.js +336 -0
  91. package/http-client/examples/basic-usage.example.d.ts +53 -0
  92. package/http-client/examples/basic-usage.example.js +161 -0
  93. package/http-client/examples/index.d.ts +3 -0
  94. package/http-client/examples/index.js +19 -0
  95. package/http-client/examples/multi-api-configuration.example.d.ts +98 -0
  96. package/http-client/examples/multi-api-configuration.example.js +353 -0
  97. package/http-client/http-client.module.d.ts +11 -0
  98. package/http-client/http-client.module.js +257 -0
  99. package/http-client/index.d.ts +10 -0
  100. package/http-client/index.js +27 -0
  101. package/http-client/interfaces/api-client-config.interface.d.ts +152 -0
  102. package/http-client/interfaces/api-client-config.interface.js +12 -0
  103. package/http-client/interfaces/http-client-config.interface.d.ts +123 -0
  104. package/http-client/interfaces/http-client-config.interface.js +2 -0
  105. package/http-client/services/api-client-registry.service.d.ts +41 -0
  106. package/http-client/services/api-client-registry.service.js +412 -0
  107. package/http-client/services/cache.service.d.ts +24 -0
  108. package/http-client/services/cache.service.js +264 -0
  109. package/http-client/services/circuit-breaker.service.d.ts +33 -0
  110. package/http-client/services/circuit-breaker.service.js +180 -0
  111. package/http-client/services/http-client.service.d.ts +60 -0
  112. package/http-client/services/http-client.service.js +504 -0
  113. package/http-client/services/http-log-query.service.d.ts +76 -0
  114. package/http-client/services/http-log-query.service.js +590 -0
  115. package/http-client/services/http-replay.service.d.ts +58 -0
  116. package/http-client/services/http-replay.service.js +266 -0
  117. package/http-client/services/index.d.ts +7 -0
  118. package/http-client/services/index.js +23 -0
  119. package/http-client/services/log-cleanup.service.d.ts +64 -0
  120. package/http-client/services/log-cleanup.service.js +268 -0
  121. package/http-client/services/logging.service.d.ts +36 -0
  122. package/http-client/services/logging.service.js +445 -0
  123. package/http-client/utils/call-stack-extractor.util.d.ts +29 -0
  124. package/http-client/utils/call-stack-extractor.util.js +138 -0
  125. package/http-client/utils/context-extractor.util.d.ts +44 -0
  126. package/http-client/utils/context-extractor.util.js +173 -0
  127. package/http-client/utils/curl-generator.util.d.ts +9 -0
  128. package/http-client/utils/curl-generator.util.js +169 -0
  129. package/http-client/utils/index.d.ts +4 -0
  130. package/http-client/utils/index.js +20 -0
  131. package/http-client/utils/request-id.util.d.ts +4 -0
  132. package/http-client/utils/request-id.util.js +34 -0
  133. package/http-client/utils/retry-recorder.util.d.ts +30 -0
  134. package/http-client/utils/retry-recorder.util.js +143 -0
  135. package/index.d.ts +2 -0
  136. package/index.js +2 -0
  137. package/package.json +1 -1
  138. package/setup/bootstrap.setup.js +5 -1
@@ -0,0 +1,504 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ var HttpClientService_1;
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.HttpClientService = void 0;
23
+ const common_1 = require("@nestjs/common");
24
+ const axios_retry_1 = require("axios-retry");
25
+ const cache_1 = require("../../cache");
26
+ const circuit_breaker_service_1 = require("./circuit-breaker.service");
27
+ const logging_service_1 = require("./logging.service");
28
+ const cache_service_1 = require("./cache.service");
29
+ const decorators_1 = require("../decorators");
30
+ const context_extractor_util_1 = require("../utils/context-extractor.util");
31
+ const curl_generator_util_1 = require("../utils/curl-generator.util");
32
+ const retry_recorder_util_1 = require("../utils/retry-recorder.util");
33
+ const request_id_util_1 = require("../utils/request-id.util");
34
+ const redis_lock_service_1 = require("../../redis-lock/redis-lock.service");
35
+ let HttpClientService = HttpClientService_1 = class HttpClientService {
36
+ constructor(circuitBreakerService, loggingService, cacheService, redisLockService, config = {}) {
37
+ this.circuitBreakerService = circuitBreakerService;
38
+ this.loggingService = loggingService;
39
+ this.cacheService = cacheService;
40
+ this.redisLockService = redisLockService;
41
+ this.logger = new common_1.Logger(HttpClientService_1.name);
42
+ this.requestStats = {
43
+ totalRequests: 0,
44
+ successfulRequests: 0,
45
+ failedRequests: 0,
46
+ totalResponseTime: 0,
47
+ requestsByMethod: {},
48
+ requestsByStatus: {},
49
+ };
50
+ this.defaultConfig = this.mergeWithDefaults(config);
51
+ this.axiosInstance = this.createAxiosInstance();
52
+ }
53
+ request(config, decoratorContext) {
54
+ return __awaiter(this, void 0, void 0, function* () {
55
+ var _a, _b, _c, _d, _e, _f, _g;
56
+ const startTime = Date.now();
57
+ const retryRecorder = retry_recorder_util_1.RetryRecorder.create();
58
+ let requestId;
59
+ let circuitBreakerState;
60
+ let cacheHit = false;
61
+ try {
62
+ const enhancedConfig = this.applyDecoratorConfig(config, decoratorContext);
63
+ const decoratorConfigs = decoratorContext
64
+ ? decorators_1.HttpDecoratorUtils.getAllDecoratorConfigs(decoratorContext.target, decoratorContext.propertyKey)
65
+ : {};
66
+ const loggingOptions = decoratorConfigs.logging || this.defaultConfig.logging;
67
+ if (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.enabled) {
68
+ requestId = this.loggingService.logRequestStart(enhancedConfig, loggingOptions);
69
+ enhancedConfig.metadata = enhancedConfig.metadata || {};
70
+ enhancedConfig.metadata.requestId = requestId;
71
+ }
72
+ const cacheConfig = decoratorConfigs.cache || this.defaultConfig.cache;
73
+ if ((cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.enabled) &&
74
+ this.shouldCacheRequest(enhancedConfig, cacheConfig)) {
75
+ const cachedResponse = yield this.cacheService.get(enhancedConfig, cacheConfig);
76
+ if (cachedResponse) {
77
+ cacheHit = true;
78
+ if (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.enabled) {
79
+ const databaseLogging = (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.databaseLog) ||
80
+ ((_b = (_a = this.defaultConfig.logging) === null || _a === void 0 ? void 0 : _a.databaseLogging) === null || _b === void 0 ? void 0 : _b.enabled);
81
+ this.loggingService.logRequestSuccess(cachedResponse, startTime, requestId, loggingOptions, databaseLogging, undefined, cacheHit, undefined, decoratorContext);
82
+ }
83
+ return cachedResponse.data;
84
+ }
85
+ }
86
+ const timeout = decoratorConfigs.timeout || this.defaultConfig.timeout;
87
+ if (timeout) {
88
+ enhancedConfig.timeout = timeout;
89
+ }
90
+ const proxyConfig = decoratorConfigs.proxy || this.defaultConfig.proxy;
91
+ if (proxyConfig === null || proxyConfig === void 0 ? void 0 : proxyConfig.enabled) {
92
+ enhancedConfig.proxy = {
93
+ host: proxyConfig.host,
94
+ port: proxyConfig.port,
95
+ protocol: proxyConfig.protocol,
96
+ auth: proxyConfig.auth,
97
+ };
98
+ }
99
+ if ((_c = this.defaultConfig.retry) === null || _c === void 0 ? void 0 : _c.enabled) {
100
+ const originalOnRetry = this.defaultConfig.retry.onRetry;
101
+ this.defaultConfig.retry.onRetry = (retryCount, error, requestConfig) => {
102
+ const retryRecord = retry_recorder_util_1.RetryRecorder.recordRetry(retryCount, error, requestConfig, this.calculateRetryDelay(retryCount, this.defaultConfig.retry));
103
+ retryRecorder.addRecord(retryRecord);
104
+ if (originalOnRetry) {
105
+ originalOnRetry(retryCount, error, requestConfig);
106
+ }
107
+ };
108
+ }
109
+ const response = yield this.executeWithFeatures(enhancedConfig, decoratorConfigs, requestId, startTime, retryRecorder, (state) => {
110
+ circuitBreakerState = state;
111
+ });
112
+ if ((cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.enabled) &&
113
+ this.shouldCacheRequest(enhancedConfig, cacheConfig)) {
114
+ yield this.cacheService.set(enhancedConfig, response, cacheConfig);
115
+ }
116
+ if (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.enabled) {
117
+ const databaseLogging = (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.databaseLog) ||
118
+ ((_e = (_d = this.defaultConfig.logging) === null || _d === void 0 ? void 0 : _d.databaseLogging) === null || _e === void 0 ? void 0 : _e.enabled);
119
+ this.loggingService.logRequestSuccess(response, startTime, requestId, loggingOptions, databaseLogging, retryRecorder.getRecords(), cacheHit, circuitBreakerState, decoratorContext);
120
+ }
121
+ return response.data;
122
+ }
123
+ catch (error) {
124
+ const loggingOptions = decoratorContext
125
+ ? decorators_1.HttpDecoratorUtils.getLoggingOptions(decoratorContext.target, decoratorContext.propertyKey)
126
+ : this.defaultConfig.logging;
127
+ if (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.enabled) {
128
+ const databaseLogging = (loggingOptions === null || loggingOptions === void 0 ? void 0 : loggingOptions.databaseLog) ||
129
+ ((_g = (_f = this.defaultConfig.logging) === null || _f === void 0 ? void 0 : _f.databaseLogging) === null || _g === void 0 ? void 0 : _g.enabled);
130
+ this.loggingService.logRequestError(error, startTime, requestId, retryRecorder.getRecords().length || 1, loggingOptions, databaseLogging, retryRecorder.getRecords(), cacheHit, circuitBreakerState, decoratorContext);
131
+ }
132
+ throw error;
133
+ }
134
+ });
135
+ }
136
+ generateCurlCommand(config) {
137
+ return curl_generator_util_1.CurlGenerator.generateSimplifiedCurl(config);
138
+ }
139
+ generateDebugCurlCommand(config, response) {
140
+ return curl_generator_util_1.CurlGenerator.generateDebugCurl(config, response);
141
+ }
142
+ getStats() {
143
+ const avgResponseTime = this.requestStats.totalRequests > 0
144
+ ? this.requestStats.totalResponseTime / this.requestStats.totalRequests
145
+ : 0;
146
+ return Object.assign(Object.assign({}, this.requestStats), { averageResponseTime: avgResponseTime, successRate: this.requestStats.totalRequests > 0
147
+ ? (this.requestStats.successfulRequests /
148
+ this.requestStats.totalRequests) *
149
+ 100
150
+ : 0, circuitBreakerStats: this.circuitBreakerService.getAllStates(), cacheStats: this.cacheService.getStats() });
151
+ }
152
+ resetStats() {
153
+ this.requestStats = {
154
+ totalRequests: 0,
155
+ successfulRequests: 0,
156
+ failedRequests: 0,
157
+ totalResponseTime: 0,
158
+ requestsByMethod: {},
159
+ requestsByStatus: {},
160
+ };
161
+ }
162
+ get(url, config) {
163
+ return __awaiter(this, void 0, void 0, function* () {
164
+ return this.request(Object.assign(Object.assign({}, config), { method: 'GET', url }));
165
+ });
166
+ }
167
+ post(url, data, config) {
168
+ return __awaiter(this, void 0, void 0, function* () {
169
+ return this.request(Object.assign(Object.assign({}, config), { method: 'POST', url, data }));
170
+ });
171
+ }
172
+ put(url, data, config) {
173
+ return __awaiter(this, void 0, void 0, function* () {
174
+ return this.request(Object.assign(Object.assign({}, config), { method: 'PUT', url, data }));
175
+ });
176
+ }
177
+ patch(url, data, config) {
178
+ return __awaiter(this, void 0, void 0, function* () {
179
+ return this.request(Object.assign(Object.assign({}, config), { method: 'PATCH', url, data }));
180
+ });
181
+ }
182
+ delete(url, config) {
183
+ return __awaiter(this, void 0, void 0, function* () {
184
+ return this.request(Object.assign(Object.assign({}, config), { method: 'DELETE', url }));
185
+ });
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
+ }
304
+ createAxiosInstance() {
305
+ var _a, _b;
306
+ const instance = require('axios').create({
307
+ baseURL: this.defaultConfig.baseURL,
308
+ timeout: this.defaultConfig.timeout,
309
+ proxy: ((_a = this.defaultConfig.proxy) === null || _a === void 0 ? void 0 : _a.enabled)
310
+ ? {
311
+ host: this.defaultConfig.proxy.host,
312
+ port: this.defaultConfig.proxy.port,
313
+ protocol: this.defaultConfig.proxy.protocol,
314
+ auth: this.defaultConfig.proxy.auth,
315
+ }
316
+ : undefined,
317
+ });
318
+ if ((_b = this.defaultConfig.retry) === null || _b === void 0 ? void 0 : _b.enabled) {
319
+ (0, axios_retry_1.default)(instance, {
320
+ retries: this.defaultConfig.retry.retries || 3,
321
+ retryDelay: this.defaultConfig.retry.retryDelay ||
322
+ ((retryCount) => Math.pow(2, retryCount) * 1000),
323
+ retryCondition: this.defaultConfig.retry.retryCondition ||
324
+ ((error) => {
325
+ if (!error.response)
326
+ return true;
327
+ const status = error.response.status;
328
+ return status >= 500 || status === 429;
329
+ }),
330
+ shouldResetTimeout: this.defaultConfig.retry.shouldResetTimeout !== false,
331
+ onRetry: this.defaultConfig.retry.onRetry ||
332
+ ((retryCount, error, requestConfig) => {
333
+ var _a;
334
+ this.logger.warn(`Retrying request (attempt ${retryCount}): ${(_a = requestConfig.method) === null || _a === void 0 ? void 0 : _a.toUpperCase()} ${requestConfig.url}`);
335
+ }),
336
+ });
337
+ }
338
+ instance.interceptors.request.use((config) => {
339
+ config.headers = config.headers || {};
340
+ const context = context_extractor_util_1.ContextExtractor.getHttpContext();
341
+ const requestId = context.requestId || (0, request_id_util_1.generateRequestId)();
342
+ config.headers['X-Request-ID'] = requestId;
343
+ if (context.userId) {
344
+ config.headers['X-User-ID'] = context.userId;
345
+ }
346
+ config.metadata = config.metadata || {};
347
+ config.metadata.requestId = requestId;
348
+ return config;
349
+ }, (error) => {
350
+ this.logger.error('Request interceptor error', error);
351
+ return Promise.reject(error);
352
+ });
353
+ instance.interceptors.response.use((response) => {
354
+ this.updateStats(response);
355
+ return response;
356
+ }, (error) => {
357
+ this.updateErrorStats(error);
358
+ return Promise.reject(error);
359
+ });
360
+ return instance;
361
+ }
362
+ executeWithFeatures(config, decoratorConfigs, requestId, startTime, retryRecorder, onCircuitBreakerStateChange) {
363
+ return __awaiter(this, void 0, void 0, function* () {
364
+ const requestFn = () => this.axiosInstance.request(config);
365
+ const circuitBreakerConfig = decoratorConfigs.circuitBreaker || this.defaultConfig.circuitBreaker;
366
+ if (circuitBreakerConfig === null || circuitBreakerConfig === void 0 ? void 0 : circuitBreakerConfig.enabled) {
367
+ const circuitBreakerKey = this.generateCircuitBreakerKey(config);
368
+ return this.circuitBreakerService.executeWithCircuitBreaker(circuitBreakerKey, requestFn, circuitBreakerConfig);
369
+ }
370
+ else {
371
+ return requestFn();
372
+ }
373
+ });
374
+ }
375
+ calculateRetryDelay(retryCount, retryConfig) {
376
+ if (retryConfig.retryDelay) {
377
+ return retryConfig.retryDelay(retryCount);
378
+ }
379
+ return Math.pow(2, retryCount) * 1000;
380
+ }
381
+ applyDecoratorConfig(config, decoratorContext) {
382
+ if (!decoratorContext)
383
+ return Object.assign({}, config);
384
+ const httpClientConfig = decorators_1.HttpDecoratorUtils.getHttpClientOptions(decoratorContext.target);
385
+ return Object.assign(Object.assign({}, config), httpClientConfig);
386
+ }
387
+ shouldCacheRequest(config, cacheConfig) {
388
+ var _a;
389
+ const method = (_a = config.method) === null || _a === void 0 ? void 0 : _a.toLowerCase();
390
+ return cacheConfig.cacheableMethods.includes(method || 'get');
391
+ }
392
+ generateCircuitBreakerKey(config) {
393
+ var _a;
394
+ const method = ((_a = config.method) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || 'UNKNOWN';
395
+ const url = new URL(config.url || '', this.defaultConfig.baseURL || 'http://localhost');
396
+ return `${method}:${url.host}${url.pathname}`;
397
+ }
398
+ updateStats(response) {
399
+ var _a, _b;
400
+ this.requestStats.totalRequests++;
401
+ this.requestStats.successfulRequests++;
402
+ const method = ((_a = response.config.method) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || 'UNKNOWN';
403
+ const status = response.status;
404
+ this.requestStats.requestsByMethod[method] =
405
+ (this.requestStats.requestsByMethod[method] || 0) + 1;
406
+ this.requestStats.requestsByStatus[status] =
407
+ (this.requestStats.requestsByStatus[status] || 0) + 1;
408
+ if ((_b = response.config.metadata) === null || _b === void 0 ? void 0 : _b.startTime) {
409
+ const responseTime = Date.now() -
410
+ response.config.metadata
411
+ .startTime;
412
+ this.requestStats.totalResponseTime += responseTime;
413
+ }
414
+ }
415
+ updateErrorStats(error) {
416
+ var _a;
417
+ this.requestStats.totalRequests++;
418
+ this.requestStats.failedRequests++;
419
+ if (error.config) {
420
+ const method = ((_a = error.config.method) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || 'UNKNOWN';
421
+ this.requestStats.requestsByMethod[method] =
422
+ (this.requestStats.requestsByMethod[method] || 0) + 1;
423
+ if (error.response) {
424
+ const status = error.response.status;
425
+ this.requestStats.requestsByStatus[status] =
426
+ (this.requestStats.requestsByStatus[status] || 0) + 1;
427
+ }
428
+ }
429
+ }
430
+ mergeWithDefaults(config) {
431
+ const defaults = {
432
+ baseURL: process.env.HTTP_CLIENT_BASE_URL,
433
+ timeout: 30000,
434
+ retry: {
435
+ enabled: true,
436
+ retries: 3,
437
+ retryDelay: (retryCount) => Math.pow(2, retryCount) * 1000,
438
+ retryCondition: (error) => {
439
+ if (!error.response)
440
+ return true;
441
+ const status = error.response.status;
442
+ return status >= 500 || status === 429;
443
+ },
444
+ shouldResetTimeout: true,
445
+ },
446
+ circuitBreaker: {
447
+ enabled: true,
448
+ failureThreshold: 5,
449
+ recoveryTimeoutMs: 60000,
450
+ monitoringPeriodMs: 10000,
451
+ minimumThroughputThreshold: 10,
452
+ countHalfOpenCalls: true,
453
+ },
454
+ cache: {
455
+ enabled: true,
456
+ defaultTtl: 300000,
457
+ cacheableMethods: ['get'],
458
+ cacheableStatusCodes: [200, 201, 202, 204, 301, 302, 304],
459
+ options: {
460
+ layers: [cache_1.CacheLayer.MEMORY, cache_1.CacheLayer.REDIS],
461
+ },
462
+ },
463
+ logging: {
464
+ enabled: true,
465
+ logRequests: true,
466
+ logResponses: true,
467
+ logErrors: true,
468
+ logHeaders: true,
469
+ logBody: true,
470
+ maxBodyLength: 1000,
471
+ sanitizeHeaders: ['authorization', 'apikey', 'password', 'token'],
472
+ logLevel: 'info',
473
+ databaseLogging: {
474
+ enabled: false,
475
+ dataSource: 'default',
476
+ tableName: 'http_logs',
477
+ },
478
+ },
479
+ };
480
+ return this.deepMerge(defaults, config);
481
+ }
482
+ deepMerge(target, source) {
483
+ const result = Object.assign({}, target);
484
+ for (const key in source) {
485
+ if (source[key] &&
486
+ typeof source[key] === 'object' &&
487
+ !Array.isArray(source[key])) {
488
+ result[key] = this.deepMerge(result[key] || {}, source[key]);
489
+ }
490
+ else {
491
+ result[key] = source[key];
492
+ }
493
+ }
494
+ return result;
495
+ }
496
+ };
497
+ exports.HttpClientService = HttpClientService;
498
+ exports.HttpClientService = HttpClientService = HttpClientService_1 = __decorate([
499
+ (0, common_1.Injectable)(),
500
+ __metadata("design:paramtypes", [circuit_breaker_service_1.HttpCircuitBreakerService,
501
+ logging_service_1.HttpLoggingService,
502
+ cache_service_1.HttpCacheService,
503
+ redis_lock_service_1.RedisLockService, Object])
504
+ ], HttpClientService);
@@ -0,0 +1,76 @@
1
+ import { DataSource } from 'typeorm';
2
+ import { HttpLogEntity, HttpLogQueryOptions, HttpLogStats } from '../entities/http-log.entity';
3
+ export declare class HttpLogQueryService {
4
+ private readonly dataSource?;
5
+ private readonly logger;
6
+ private logRepository;
7
+ constructor(dataSource?: DataSource);
8
+ findLogs(options?: HttpLogQueryOptions): Promise<{
9
+ logs: HttpLogEntity[];
10
+ total: number;
11
+ page: number;
12
+ limit: number;
13
+ totalPages: number;
14
+ }>;
15
+ findLogById(id: string, includeDetails?: boolean): Promise<HttpLogEntity | null>;
16
+ findLogByRequestId(requestId: string): Promise<HttpLogEntity | null>;
17
+ findErrorLogs(options?: {
18
+ startDate?: Date;
19
+ endDate?: Date;
20
+ errorCode?: string;
21
+ statusCode?: number;
22
+ page?: number;
23
+ limit?: number;
24
+ }): Promise<{
25
+ logs: HttpLogEntity[];
26
+ total: number;
27
+ }>;
28
+ findSlowRequests(minResponseTime?: number, options?: {
29
+ page?: number;
30
+ limit?: number;
31
+ }): Promise<{
32
+ logs: HttpLogEntity[];
33
+ total: number;
34
+ }>;
35
+ findRetryLogs(options?: {
36
+ minRetries?: number;
37
+ page?: number;
38
+ limit?: number;
39
+ }): Promise<{
40
+ logs: HttpLogEntity[];
41
+ total: number;
42
+ }>;
43
+ getStats(options?: {
44
+ startDate?: Date;
45
+ endDate?: Date;
46
+ userId?: string;
47
+ serviceName?: string;
48
+ groupBy?: 'hour' | 'day' | 'week';
49
+ }): Promise<HttpLogStats>;
50
+ deleteOldLogs(daysToKeep?: number): Promise<number>;
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>;
71
+ private initializeRepository;
72
+ private calculatePercentiles;
73
+ private formatStats;
74
+ private buildQuery;
75
+ private sanitizeHeadersForCurl;
76
+ }