@nest-omni/core 4.1.3-1 → 4.1.3-11
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 +39 -1
- package/audit/controllers/audit.controller.d.ts +24 -0
- package/audit/controllers/audit.controller.js +24 -0
- package/audit/decorators/audit-controller.decorator.d.ts +9 -1
- package/audit/decorators/audit-controller.decorator.js +11 -2
- package/audit/decorators/audit-operation.decorator.d.ts +45 -0
- package/audit/decorators/audit-operation.decorator.js +49 -0
- package/audit/decorators/entity-audit.decorator.d.ts +76 -1
- package/audit/decorators/entity-audit.decorator.js +135 -3
- package/audit/decorators/index.d.ts +1 -0
- package/audit/decorators/index.js +1 -0
- package/audit/dto/audit-log-query.dto.d.ts +3 -0
- package/audit/dto/audit-log-query.dto.js +3 -0
- package/audit/dto/begin-transaction.dto.d.ts +3 -0
- package/audit/dto/begin-transaction.dto.js +3 -0
- package/audit/dto/compare-entities.dto.d.ts +3 -0
- package/audit/dto/compare-entities.dto.js +3 -0
- package/audit/dto/pre-check-restore.dto.d.ts +3 -0
- package/audit/dto/pre-check-restore.dto.js +3 -0
- package/audit/dto/restore-entity.dto.d.ts +3 -0
- package/audit/dto/restore-entity.dto.js +3 -0
- package/audit/entities/entity-audit-log.entity.d.ts +8 -0
- package/audit/entities/entity-audit-log.entity.js +33 -1
- package/audit/entities/entity-transaction.entity.d.ts +10 -0
- package/audit/entities/entity-transaction.entity.js +33 -1
- package/audit/entities/index.d.ts +2 -0
- package/audit/entities/index.js +2 -0
- package/audit/entities/manual-operation-log.entity.d.ts +4 -0
- package/audit/entities/manual-operation-log.entity.js +4 -0
- package/audit/entities/operation-template.entity.d.ts +4 -0
- package/audit/entities/operation-template.entity.js +4 -0
- package/audit/enums/audit.enums.d.ts +45 -5
- package/audit/enums/audit.enums.js +47 -4
- package/audit/index.d.ts +3 -1
- package/audit/index.js +30 -1
- package/audit/interceptors/audit.interceptor.d.ts +15 -0
- package/audit/interceptors/audit.interceptor.js +23 -1
- package/audit/interfaces/audit.interfaces.d.ts +182 -2
- package/audit/services/audit-context.service.d.ts +15 -0
- package/audit/services/audit-context.service.js +15 -0
- package/audit/services/audit-strategy.service.d.ts +6 -0
- package/audit/services/audit-strategy.service.js +13 -0
- package/audit/services/entity-audit.service.d.ts +129 -3
- package/audit/services/entity-audit.service.js +301 -6
- package/audit/services/index.d.ts +2 -0
- package/audit/services/index.js +2 -0
- package/audit/services/manual-audit-log.service.d.ts +124 -0
- package/audit/services/manual-audit-log.service.js +138 -0
- package/audit/services/multi-database.service.d.ts +12 -0
- package/audit/services/multi-database.service.js +12 -0
- package/audit/services/operation-description.service.d.ts +59 -0
- package/audit/services/operation-description.service.js +76 -2
- package/audit/services/transaction-audit.service.d.ts +30 -0
- package/audit/services/transaction-audit.service.js +47 -0
- package/audit/subscribers/entity-audit.subscriber.d.ts +15 -0
- package/audit/subscribers/entity-audit.subscriber.js +29 -1
- package/cache/cache-metrics.service.d.ts +67 -0
- package/cache/cache-metrics.service.js +68 -4
- package/cache/cache-serialization.service.d.ts +31 -0
- package/cache/cache-serialization.service.js +25 -0
- package/cache/cache.constants.d.ts +9 -0
- package/cache/cache.constants.js +9 -0
- package/cache/cache.health.d.ts +26 -0
- package/cache/cache.health.js +30 -0
- package/cache/cache.module.d.ts +86 -0
- package/cache/cache.module.js +71 -0
- package/cache/cache.service.d.ts +140 -0
- package/cache/cache.service.js +157 -0
- package/cache/cache.warmup.service.d.ts +39 -0
- package/cache/cache.warmup.service.js +32 -0
- package/cache/decorators/cache-evict.decorator.d.ts +47 -0
- package/cache/decorators/cache-evict.decorator.js +56 -0
- package/cache/decorators/cache-put.decorator.d.ts +34 -0
- package/cache/decorators/cache-put.decorator.js +39 -0
- package/cache/decorators/cacheable.decorator.d.ts +40 -0
- package/cache/decorators/cacheable.decorator.js +55 -0
- package/cache/dependencies/callback.dependency.d.ts +33 -0
- package/cache/dependencies/callback.dependency.js +39 -1
- package/cache/dependencies/chain.dependency.d.ts +28 -0
- package/cache/dependencies/chain.dependency.js +34 -0
- package/cache/dependencies/db.dependency.d.ts +45 -0
- package/cache/dependencies/db.dependency.js +48 -1
- package/cache/dependencies/file.dependency.d.ts +32 -0
- package/cache/dependencies/file.dependency.js +34 -0
- package/cache/dependencies/tag.dependency.d.ts +36 -0
- package/cache/dependencies/tag.dependency.js +36 -0
- package/cache/dependencies/time.dependency.d.ts +43 -0
- package/cache/dependencies/time.dependency.js +43 -0
- package/cache/examples/basic-usage.d.ts +15 -0
- package/cache/examples/basic-usage.js +62 -8
- package/cache/index.js +9 -0
- package/cache/interfaces/cache-dependency.interface.d.ts +53 -0
- package/cache/interfaces/cache-options.interface.d.ts +81 -0
- package/cache/interfaces/cache-options.interface.js +6 -0
- package/cache/interfaces/cache-provider.interface.d.ts +78 -0
- package/cache/providers/base-cache.provider.d.ts +14 -0
- package/cache/providers/base-cache.provider.js +16 -0
- package/cache/providers/cls-cache.provider.d.ts +20 -0
- package/cache/providers/cls-cache.provider.js +28 -0
- package/cache/providers/memory-cache.provider.d.ts +23 -0
- package/cache/providers/memory-cache.provider.js +26 -0
- package/cache/providers/redis-cache.provider.d.ts +26 -0
- package/cache/providers/redis-cache.provider.js +29 -0
- package/cache/utils/dependency-manager.util.d.ts +52 -0
- package/cache/utils/dependency-manager.util.js +59 -0
- package/cache/utils/key-generator.util.d.ts +42 -0
- package/cache/utils/key-generator.util.js +53 -1
- package/common/abstract.entity.d.ts +14 -0
- package/common/abstract.entity.js +14 -0
- package/common/boilerplate.polyfill.d.ts +142 -4
- package/common/boilerplate.polyfill.js +24 -100
- package/common/dto/dto-container.d.ts +16 -0
- package/common/dto/dto-container.js +20 -0
- package/common/dto/dto-decorators.d.ts +18 -0
- package/common/dto/dto-decorators.js +14 -0
- package/common/dto/dto-extensions.d.ts +11 -0
- package/common/dto/dto-extensions.js +9 -0
- package/common/dto/dto-service-accessor.d.ts +17 -0
- package/common/dto/dto-service-accessor.js +18 -0
- package/common/dto/dto-transformer.d.ts +12 -0
- package/common/dto/dto-transformer.js +9 -0
- package/common/dto/index.js +2 -0
- package/common/examples/paginate-and-map.example.d.ts +6 -0
- package/common/examples/paginate-and-map.example.js +26 -0
- package/common/utils.d.ts +15 -0
- package/common/utils.js +15 -0
- package/constants/language-code.js +1 -0
- package/decorators/field.decorators.js +8 -1
- package/decorators/property.decorators.js +1 -0
- package/decorators/public-route.decorator.js +1 -0
- package/decorators/transform.decorators.d.ts +27 -0
- package/decorators/transform.decorators.js +29 -0
- package/decorators/translate.decorator.js +1 -0
- package/decorators/user.decorator.js +1 -0
- package/decorators/validator.decorators.d.ts +8 -18
- package/decorators/validator.decorators.js +22 -190
- package/filters/constraint-errors.js +1 -0
- package/helpers/common.helper.d.ts +13 -0
- package/helpers/common.helper.js +13 -0
- package/http-client/config/http-client.config.d.ts +15 -0
- package/http-client/config/http-client.config.js +25 -9
- package/http-client/decorators/http-client.decorators.d.ts +63 -0
- package/http-client/decorators/http-client.decorators.js +71 -3
- package/http-client/entities/http-log.entity.d.ts +229 -0
- package/http-client/entities/http-log.entity.js +6 -1
- package/http-client/errors/http-client.errors.d.ts +57 -0
- package/http-client/errors/http-client.errors.js +58 -0
- package/http-client/examples/advanced-usage.example.d.ts +41 -0
- package/http-client/examples/advanced-usage.example.js +68 -24
- package/http-client/examples/auth-with-waiting-lock.example.d.ts +31 -0
- package/http-client/examples/auth-with-waiting-lock.example.js +52 -5
- package/http-client/examples/basic-usage.example.d.ts +60 -0
- package/http-client/examples/basic-usage.example.js +60 -0
- package/http-client/examples/multi-api-configuration.example.d.ts +60 -0
- package/http-client/examples/multi-api-configuration.example.js +76 -5
- package/http-client/http-client.module.d.ts +13 -0
- package/http-client/http-client.module.js +20 -5
- package/http-client/index.js +8 -0
- package/http-client/interfaces/api-client-config.interface.d.ts +125 -0
- package/http-client/interfaces/api-client-config.interface.js +3 -0
- package/http-client/interfaces/http-client-config.interface.d.ts +60 -0
- package/http-client/services/api-client-registry.service.d.ts +57 -0
- package/http-client/services/api-client-registry.service.js +84 -1
- package/http-client/services/cache.service.d.ts +52 -0
- package/http-client/services/cache.service.js +72 -3
- package/http-client/services/circuit-breaker.service.d.ts +46 -0
- package/http-client/services/circuit-breaker.service.js +52 -0
- package/http-client/services/http-client.service.d.ts +67 -0
- package/http-client/services/http-client.service.js +105 -4
- package/http-client/services/http-log-query.service.d.ts +83 -0
- package/http-client/services/http-log-query.service.js +122 -1
- package/http-client/services/http-replay.service.d.ts +101 -0
- package/http-client/services/http-replay.service.js +86 -0
- package/http-client/services/log-cleanup.service.d.ts +63 -0
- package/http-client/services/log-cleanup.service.js +54 -2
- package/http-client/services/logging.service.d.ts +40 -0
- package/http-client/services/logging.service.js +53 -0
- package/http-client/utils/call-stack-extractor.util.d.ts +37 -0
- package/http-client/utils/call-stack-extractor.util.js +48 -0
- package/http-client/utils/context-extractor.util.d.ts +49 -0
- package/http-client/utils/context-extractor.util.js +52 -0
- package/http-client/utils/curl-generator.util.d.ts +21 -0
- package/http-client/utils/curl-generator.util.js +44 -3
- package/http-client/utils/request-id.util.d.ts +18 -0
- package/http-client/utils/request-id.util.js +20 -0
- package/http-client/utils/retry-recorder.util.d.ts +42 -0
- package/http-client/utils/retry-recorder.util.js +44 -0
- package/i18n/en_US/validation.json +2 -1
- package/i18n/zh_CN/validation.json +2 -1
- package/index.js +8 -0
- package/interceptors/translation-interceptor.service.js +5 -0
- package/package.json +1 -1
- package/providers/context.provider.js +2 -0
- package/providers/generator.provider.d.ts +4 -0
- package/providers/generator.provider.js +4 -0
- package/redis-lock/comprehensive-lock-cleanup.service.d.ts +94 -0
- package/redis-lock/comprehensive-lock-cleanup.service.js +253 -0
- package/redis-lock/examples/lock-strategy.examples.d.ts +89 -0
- package/redis-lock/examples/lock-strategy.examples.js +130 -15
- package/redis-lock/index.d.ts +2 -0
- package/redis-lock/index.js +8 -1
- package/redis-lock/lock-heartbeat.service.d.ts +78 -0
- package/redis-lock/lock-heartbeat.service.js +222 -0
- package/redis-lock/redis-lock.decorator.d.ts +101 -0
- package/redis-lock/redis-lock.decorator.js +120 -0
- package/redis-lock/redis-lock.module.d.ts +66 -0
- package/redis-lock/redis-lock.module.js +175 -70
- package/redis-lock/redis-lock.service.d.ts +278 -0
- package/redis-lock/redis-lock.service.js +282 -12
- package/setup/bootstrap.setup.js +20 -0
- package/setup/mode.setup.d.ts +44 -0
- package/setup/mode.setup.js +44 -0
- package/setup/schedule.decorator.d.ts +227 -0
- package/setup/schedule.decorator.js +235 -12
- package/setup/worker.decorator.d.ts +86 -0
- package/setup/worker.decorator.js +88 -0
- package/shared/serviceRegistryModule.js +27 -14
- package/shared/services/api-config.service.d.ts +3 -0
- package/shared/services/api-config.service.js +20 -9
- package/validator-json/decorators.d.ts +17 -0
- package/validator-json/decorators.js +17 -2
- package/validator-json/default.d.ts +6 -0
- package/validator-json/default.js +30 -2
- package/validator-json/defaultConverters.js +1 -0
- package/validator-json/options.d.ts +23 -0
- package/validators/common-validators.d.ts +143 -0
- package/validators/common-validators.js +249 -0
- package/validators/custom-validate.examples.d.ts +96 -0
- package/validators/custom-validate.examples.js +400 -0
- package/validators/custom-validate.validator.d.ts +134 -0
- package/validators/custom-validate.validator.js +214 -0
- package/validators/index.d.ts +2 -0
- package/validators/index.js +2 -0
- package/validators/is-exists.validator.d.ts +18 -4
- package/validators/is-exists.validator.js +67 -6
- package/validators/is-unique.validator.d.ts +32 -5
- package/validators/is-unique.validator.js +99 -17
- package/validators/skip-empty.validator.d.ts +5 -0
- package/validators/skip-empty.validator.js +5 -0
- package/vault/interfaces/vault-options.interface.d.ts +9 -0
- package/vault/vault-config.loader.d.ts +30 -0
- package/vault/vault-config.loader.js +48 -1
- package/vault/vault-config.service.d.ts +53 -0
- package/vault/vault-config.service.js +57 -0
- package/vault/vault.module.d.ts +4 -0
- package/vault/vault.module.js +4 -0
- package/decorators/examples/validation-decorators.example.d.ts +0 -69
- package/decorators/examples/validation-decorators.example.js +0 -331
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CurlGenerator = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* HTTP请求curl命令生成器
|
|
6
|
+
*/
|
|
4
7
|
class CurlGenerator {
|
|
8
|
+
/**
|
|
9
|
+
* 生成curl命令
|
|
10
|
+
*/
|
|
5
11
|
static generateCurlCommand(config, response) {
|
|
6
12
|
const parts = ['curl'];
|
|
13
|
+
// 添加方法
|
|
7
14
|
if (config.method && config.method.toLowerCase() !== 'get') {
|
|
8
15
|
parts.push(`-X ${config.method.toUpperCase()}`);
|
|
9
16
|
}
|
|
17
|
+
// 添加URL
|
|
10
18
|
const url = this.buildUrl(config);
|
|
11
19
|
parts.push(`'${url}'`);
|
|
20
|
+
// 添加头信息
|
|
12
21
|
if (config.headers) {
|
|
13
22
|
Object.entries(config.headers).forEach(([key, value]) => {
|
|
14
23
|
if (value !== undefined && value !== null) {
|
|
@@ -16,12 +25,14 @@ class CurlGenerator {
|
|
|
16
25
|
}
|
|
17
26
|
});
|
|
18
27
|
}
|
|
28
|
+
// 添加数据
|
|
19
29
|
if (config.data) {
|
|
20
30
|
const data = typeof config.data === 'string'
|
|
21
31
|
? config.data
|
|
22
32
|
: JSON.stringify(config.data, null, 2);
|
|
23
33
|
parts.push(`-d '${data}'`);
|
|
24
34
|
}
|
|
35
|
+
// 添加表单数据
|
|
25
36
|
if (config.data instanceof FormData) {
|
|
26
37
|
const formDataParts = [];
|
|
27
38
|
config.data.forEach((value, key) => {
|
|
@@ -34,26 +45,35 @@ class CurlGenerator {
|
|
|
34
45
|
});
|
|
35
46
|
parts.push(...formDataParts);
|
|
36
47
|
}
|
|
48
|
+
// 添加查询参数(如果不在URL中)
|
|
37
49
|
if (config.params && !url.includes('?')) {
|
|
38
50
|
const params = new URLSearchParams(config.params).toString();
|
|
39
51
|
if (params) {
|
|
40
52
|
parts[parts.length - 1] = parts[parts.length - 1].replace(/'/, `?${params}'`);
|
|
41
53
|
}
|
|
42
54
|
}
|
|
43
|
-
|
|
44
|
-
parts.push('-
|
|
45
|
-
parts.push('-
|
|
55
|
+
// 添加其他选项
|
|
56
|
+
parts.push('-i'); // 包含头信息
|
|
57
|
+
parts.push('-s'); // 静默模式
|
|
58
|
+
parts.push('-L'); // 跟随重定向
|
|
59
|
+
// 添加响应状态码注释
|
|
46
60
|
if (response) {
|
|
47
61
|
parts.push(`# Response: ${response.status} ${response.statusText}`);
|
|
48
62
|
}
|
|
49
63
|
return parts.join(' \\\n ');
|
|
50
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* 生成简化的curl命令(用于日志记录)
|
|
67
|
+
*/
|
|
51
68
|
static generateSimplifiedCurl(config) {
|
|
52
69
|
const parts = ['curl'];
|
|
70
|
+
// 添加方法
|
|
53
71
|
if (config.method && config.method.toLowerCase() !== 'get') {
|
|
54
72
|
parts.push(`-X ${config.method.toUpperCase()}`);
|
|
55
73
|
}
|
|
74
|
+
// 添加URL
|
|
56
75
|
parts.push(`'${this.buildUrl(config)}'`);
|
|
76
|
+
// 只添加重要的头信息
|
|
57
77
|
const importantHeaders = [
|
|
58
78
|
'content-type',
|
|
59
79
|
'accept',
|
|
@@ -65,11 +85,13 @@ class CurlGenerator {
|
|
|
65
85
|
.filter(([key]) => importantHeaders.includes(key.toLowerCase()))
|
|
66
86
|
.forEach(([key, value]) => {
|
|
67
87
|
if (value !== undefined && value !== null) {
|
|
88
|
+
// 过滤敏感信息
|
|
68
89
|
const sanitizedValue = this.sanitizeHeaderValue(key, String(value));
|
|
69
90
|
parts.push(`-H '${key}: ${sanitizedValue}'`);
|
|
70
91
|
}
|
|
71
92
|
});
|
|
72
93
|
}
|
|
94
|
+
// 添加数据(简化版)
|
|
73
95
|
if (config.data) {
|
|
74
96
|
const data = typeof config.data === 'string'
|
|
75
97
|
? config.data.substring(0, 200) +
|
|
@@ -79,9 +101,13 @@ class CurlGenerator {
|
|
|
79
101
|
}
|
|
80
102
|
return parts.join(' ');
|
|
81
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* 生成用于调试的详细curl命令
|
|
106
|
+
*/
|
|
82
107
|
static generateDebugCurl(config, response) {
|
|
83
108
|
var _a, _b, _c;
|
|
84
109
|
const curl = this.generateCurlCommand(config, response);
|
|
110
|
+
// 添加调试信息注释
|
|
85
111
|
const debugInfo = [
|
|
86
112
|
'# Debug Information:',
|
|
87
113
|
`# Timestamp: ${new Date().toISOString()}`,
|
|
@@ -94,17 +120,23 @@ class CurlGenerator {
|
|
|
94
120
|
}
|
|
95
121
|
return debugInfo.join('\n') + '\n' + curl;
|
|
96
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* 从curl命令解析请求配置
|
|
125
|
+
*/
|
|
97
126
|
static parseCurlCommand(curlCommand) {
|
|
98
127
|
const config = {};
|
|
99
128
|
try {
|
|
129
|
+
// 提取方法
|
|
100
130
|
const methodMatch = curlCommand.match(/-X\s+(\w+)/);
|
|
101
131
|
if (methodMatch) {
|
|
102
132
|
config.method = methodMatch[1].toLowerCase();
|
|
103
133
|
}
|
|
134
|
+
// 提取URL
|
|
104
135
|
const urlMatch = curlCommand.match(/curl[^']*'([^']+)'/);
|
|
105
136
|
if (urlMatch) {
|
|
106
137
|
config.url = urlMatch[1];
|
|
107
138
|
}
|
|
139
|
+
// 提取头信息
|
|
108
140
|
const headerMatches = curlCommand.match(/-H\s+'([^:]+):\s*([^']+)'/g) || [];
|
|
109
141
|
config.headers = {};
|
|
110
142
|
headerMatches.forEach((header) => {
|
|
@@ -113,6 +145,7 @@ class CurlGenerator {
|
|
|
113
145
|
config.headers[headerMatch[1]] = headerMatch[2];
|
|
114
146
|
}
|
|
115
147
|
});
|
|
148
|
+
// 提取数据
|
|
116
149
|
const dataMatch = curlCommand.match(/-d\s+'([^']+)'/);
|
|
117
150
|
if (dataMatch) {
|
|
118
151
|
try {
|
|
@@ -128,11 +161,16 @@ class CurlGenerator {
|
|
|
128
161
|
}
|
|
129
162
|
return config;
|
|
130
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* 构建完整URL
|
|
166
|
+
*/
|
|
131
167
|
static buildUrl(config) {
|
|
132
168
|
let url = config.url || '';
|
|
169
|
+
// 处理相对URL
|
|
133
170
|
if (config.baseURL && !url.startsWith('http')) {
|
|
134
171
|
url = config.baseURL.replace(/\/$/, '') + '/' + url.replace(/^\//, '');
|
|
135
172
|
}
|
|
173
|
+
// 添加查询参数
|
|
136
174
|
if (config.params) {
|
|
137
175
|
const searchParams = new URLSearchParams();
|
|
138
176
|
Object.entries(config.params).forEach(([key, value]) => {
|
|
@@ -147,6 +185,9 @@ class CurlGenerator {
|
|
|
147
185
|
}
|
|
148
186
|
return url;
|
|
149
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* 过滤敏感头信息
|
|
190
|
+
*/
|
|
150
191
|
static sanitizeHeaderValue(key, value) {
|
|
151
192
|
const sensitiveKeys = [
|
|
152
193
|
'authorization',
|
|
@@ -1,4 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 生成请求ID
|
|
3
|
+
* @returns 唯一的请求ID
|
|
4
|
+
*/
|
|
1
5
|
export declare function generateRequestId(): string;
|
|
6
|
+
/**
|
|
7
|
+
* 生成短请求ID(用于日志)
|
|
8
|
+
* @returns 短格的请求ID
|
|
9
|
+
*/
|
|
2
10
|
export declare function generateShortRequestId(): string;
|
|
11
|
+
/**
|
|
12
|
+
* 验证请求ID格式
|
|
13
|
+
* @param requestId 请求ID
|
|
14
|
+
* @returns 是否为有效的请求ID
|
|
15
|
+
*/
|
|
3
16
|
export declare function isValidRequestId(requestId: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* 从请求头中提取请求ID
|
|
19
|
+
* @param headers 请求头
|
|
20
|
+
* @returns 请求ID或null
|
|
21
|
+
*/
|
|
4
22
|
export declare function extractRequestId(headers: Record<string, string>): string | null;
|
|
@@ -5,17 +5,37 @@ exports.generateShortRequestId = generateShortRequestId;
|
|
|
5
5
|
exports.isValidRequestId = isValidRequestId;
|
|
6
6
|
exports.extractRequestId = extractRequestId;
|
|
7
7
|
const crypto_1 = require("crypto");
|
|
8
|
+
/**
|
|
9
|
+
* 生成请求ID
|
|
10
|
+
* @returns 唯一的请求ID
|
|
11
|
+
*/
|
|
8
12
|
function generateRequestId() {
|
|
9
13
|
return (0, crypto_1.randomUUID)();
|
|
10
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* 生成短请求ID(用于日志)
|
|
17
|
+
* @returns 短格的请求ID
|
|
18
|
+
*/
|
|
11
19
|
function generateShortRequestId() {
|
|
12
20
|
return Math.random().toString(36).substring(2, 15);
|
|
13
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* 验证请求ID格式
|
|
24
|
+
* @param requestId 请求ID
|
|
25
|
+
* @returns 是否为有效的请求ID
|
|
26
|
+
*/
|
|
14
27
|
function isValidRequestId(requestId) {
|
|
28
|
+
// UUID格式验证
|
|
15
29
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
16
30
|
return uuidRegex.test(requestId);
|
|
17
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* 从请求头中提取请求ID
|
|
34
|
+
* @param headers 请求头
|
|
35
|
+
* @returns 请求ID或null
|
|
36
|
+
*/
|
|
18
37
|
function extractRequestId(headers) {
|
|
38
|
+
// 常见的请求ID头名称
|
|
19
39
|
const requestIdHeaders = [
|
|
20
40
|
'x-request-id',
|
|
21
41
|
'x-trace-id',
|
|
@@ -1,14 +1,41 @@
|
|
|
1
1
|
import { AxiosError, AxiosRequestConfig } from 'axios';
|
|
2
2
|
import { RetryRecord } from '../entities/http-log.entity';
|
|
3
|
+
/**
|
|
4
|
+
* 请求重试记录器
|
|
5
|
+
*/
|
|
3
6
|
export declare class RetryRecorder {
|
|
4
7
|
private records;
|
|
8
|
+
/**
|
|
9
|
+
* 记录重试尝试
|
|
10
|
+
*/
|
|
5
11
|
static recordRetry(attempt: number, error: AxiosError | any, config: AxiosRequestConfig, delay: number): RetryRecord;
|
|
12
|
+
/**
|
|
13
|
+
* 创建重试记录器实例
|
|
14
|
+
*/
|
|
6
15
|
static create(): RetryRecorder;
|
|
16
|
+
/**
|
|
17
|
+
* 格式化错误信息
|
|
18
|
+
*/
|
|
7
19
|
private static formatError;
|
|
20
|
+
/**
|
|
21
|
+
* 获取重试原因
|
|
22
|
+
*/
|
|
8
23
|
private static getRetryReason;
|
|
24
|
+
/**
|
|
25
|
+
* 过滤敏感头信息
|
|
26
|
+
*/
|
|
9
27
|
private static sanitizeHeaders;
|
|
28
|
+
/**
|
|
29
|
+
* 添加重试记录
|
|
30
|
+
*/
|
|
10
31
|
addRecord(record: RetryRecord): void;
|
|
32
|
+
/**
|
|
33
|
+
* 获取所有重试记录
|
|
34
|
+
*/
|
|
11
35
|
getRecords(): RetryRecord[];
|
|
36
|
+
/**
|
|
37
|
+
* 获取重试统计
|
|
38
|
+
*/
|
|
12
39
|
getStats(): {
|
|
13
40
|
totalRetries: number;
|
|
14
41
|
maxAttempts: number;
|
|
@@ -16,10 +43,25 @@ export declare class RetryRecorder {
|
|
|
16
43
|
averageDelay: number;
|
|
17
44
|
reasons: Record<string, number>;
|
|
18
45
|
};
|
|
46
|
+
/**
|
|
47
|
+
* 重置记录
|
|
48
|
+
*/
|
|
19
49
|
reset(): void;
|
|
50
|
+
/**
|
|
51
|
+
* 获取最后一次重试记录
|
|
52
|
+
*/
|
|
20
53
|
getLastRecord(): RetryRecord | null;
|
|
54
|
+
/**
|
|
55
|
+
* 检查是否有重试记录
|
|
56
|
+
*/
|
|
21
57
|
hasRetries(): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* 获取指定尝试次数的记录
|
|
60
|
+
*/
|
|
22
61
|
getRecordByAttempt(attempt: number): RetryRecord | null;
|
|
62
|
+
/**
|
|
63
|
+
* 获取重试时间线
|
|
64
|
+
*/
|
|
23
65
|
getTimeline(): Array<{
|
|
24
66
|
attempt: number;
|
|
25
67
|
timestamp: Date;
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RetryRecorder = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* 请求重试记录器
|
|
6
|
+
*/
|
|
4
7
|
class RetryRecorder {
|
|
5
8
|
constructor() {
|
|
6
9
|
this.records = [];
|
|
7
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* 记录重试尝试
|
|
13
|
+
*/
|
|
8
14
|
static recordRetry(attempt, error, config, delay) {
|
|
9
15
|
var _a;
|
|
10
16
|
return {
|
|
@@ -20,9 +26,15 @@ class RetryRecorder {
|
|
|
20
26
|
},
|
|
21
27
|
};
|
|
22
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* 创建重试记录器实例
|
|
31
|
+
*/
|
|
23
32
|
static create() {
|
|
24
33
|
return new RetryRecorder();
|
|
25
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* 格式化错误信息
|
|
37
|
+
*/
|
|
26
38
|
static formatError(error) {
|
|
27
39
|
var _a;
|
|
28
40
|
if (!error)
|
|
@@ -38,8 +50,12 @@ class RetryRecorder {
|
|
|
38
50
|
}
|
|
39
51
|
return formatted;
|
|
40
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* 获取重试原因
|
|
55
|
+
*/
|
|
41
56
|
static getRetryReason(error) {
|
|
42
57
|
if (!error.response) {
|
|
58
|
+
// 网络错误
|
|
43
59
|
if (error.code === 'ECONNRESET') {
|
|
44
60
|
return 'Connection reset';
|
|
45
61
|
}
|
|
@@ -54,6 +70,7 @@ class RetryRecorder {
|
|
|
54
70
|
}
|
|
55
71
|
return 'Network error';
|
|
56
72
|
}
|
|
73
|
+
// HTTP错误
|
|
57
74
|
const status = error.response.status;
|
|
58
75
|
if (status >= 500) {
|
|
59
76
|
return `Server error: ${status}`;
|
|
@@ -66,6 +83,9 @@ class RetryRecorder {
|
|
|
66
83
|
}
|
|
67
84
|
return `HTTP error: ${status}`;
|
|
68
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* 过滤敏感头信息
|
|
88
|
+
*/
|
|
69
89
|
static sanitizeHeaders(headers) {
|
|
70
90
|
const sanitized = {};
|
|
71
91
|
const sensitiveKeys = [
|
|
@@ -89,12 +109,21 @@ class RetryRecorder {
|
|
|
89
109
|
});
|
|
90
110
|
return sanitized;
|
|
91
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* 添加重试记录
|
|
114
|
+
*/
|
|
92
115
|
addRecord(record) {
|
|
93
116
|
this.records.push(record);
|
|
94
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* 获取所有重试记录
|
|
120
|
+
*/
|
|
95
121
|
getRecords() {
|
|
96
122
|
return [...this.records];
|
|
97
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* 获取重试统计
|
|
126
|
+
*/
|
|
98
127
|
getStats() {
|
|
99
128
|
const totalRetries = this.records.length;
|
|
100
129
|
const maxAttempts = Math.max(...this.records.map((r) => r.attempt), 0);
|
|
@@ -112,20 +141,35 @@ class RetryRecorder {
|
|
|
112
141
|
reasons,
|
|
113
142
|
};
|
|
114
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* 重置记录
|
|
146
|
+
*/
|
|
115
147
|
reset() {
|
|
116
148
|
this.records = [];
|
|
117
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* 获取最后一次重试记录
|
|
152
|
+
*/
|
|
118
153
|
getLastRecord() {
|
|
119
154
|
return this.records.length > 0
|
|
120
155
|
? this.records[this.records.length - 1]
|
|
121
156
|
: null;
|
|
122
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* 检查是否有重试记录
|
|
160
|
+
*/
|
|
123
161
|
hasRetries() {
|
|
124
162
|
return this.records.length > 0;
|
|
125
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* 获取指定尝试次数的记录
|
|
166
|
+
*/
|
|
126
167
|
getRecordByAttempt(attempt) {
|
|
127
168
|
return this.records.find((r) => r.attempt === attempt) || null;
|
|
128
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* 获取重试时间线
|
|
172
|
+
*/
|
|
129
173
|
getTimeline() {
|
|
130
174
|
let cumulativeDelay = 0;
|
|
131
175
|
return this.records.map((record) => {
|
|
@@ -40,5 +40,6 @@
|
|
|
40
40
|
"IS_LOCALE": "{property} value `{value}` must be a valid locale",
|
|
41
41
|
"AT_LEAST_ONE_FIELD": "At least one of the following fields must be provided: {properties}",
|
|
42
42
|
"CUSTOM_VALIDATION": "Custom validation failed for {property}",
|
|
43
|
-
"CUSTOM_VALIDATION_METHOD": "Validation failed for {property}"
|
|
43
|
+
"CUSTOM_VALIDATION_METHOD": "Validation failed for {property}",
|
|
44
|
+
"CUSTOM_VALIDATE": "Validation failed for {property}"
|
|
44
45
|
}
|
|
@@ -40,5 +40,6 @@
|
|
|
40
40
|
"IS_LOCALE": "{property} 值 `{value}` 必须是有效语言",
|
|
41
41
|
"AT_LEAST_ONE_FIELD": "以下字段中至少必须提供一个:{properties}",
|
|
42
42
|
"CUSTOM_VALIDATION": "{property}自定义验证失败",
|
|
43
|
-
"CUSTOM_VALIDATION_METHOD": "{property}验证失败"
|
|
43
|
+
"CUSTOM_VALIDATION_METHOD": "{property}验证失败",
|
|
44
|
+
"CUSTOM_VALIDATE": "{property}验证失败"
|
|
44
45
|
}
|
package/index.js
CHANGED
|
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Core modules
|
|
17
18
|
__exportStar(require("./constants"), exports);
|
|
18
19
|
__exportStar(require("./decorators"), exports);
|
|
19
20
|
__exportStar(require("./exceptions"), exports);
|
|
@@ -27,10 +28,17 @@ __exportStar(require("./common"), exports);
|
|
|
27
28
|
__exportStar(require("./validator-json"), exports);
|
|
28
29
|
__exportStar(require("./helpers"), exports);
|
|
29
30
|
__exportStar(require("./providers"), exports);
|
|
31
|
+
// Lock module
|
|
30
32
|
__exportStar(require("./redis-lock"), exports);
|
|
33
|
+
// Cache module
|
|
31
34
|
__exportStar(require("./cache"), exports);
|
|
35
|
+
// HTTP Client module
|
|
32
36
|
__exportStar(require("./http-client"), exports);
|
|
37
|
+
// Vault module
|
|
33
38
|
__exportStar(require("./vault"), exports);
|
|
39
|
+
// Setup and bootstrap
|
|
34
40
|
__exportStar(require("./setup"), exports);
|
|
41
|
+
// Health checker
|
|
35
42
|
__exportStar(require("./health-checker"), exports);
|
|
43
|
+
// Audit module
|
|
36
44
|
__exportStar(require("./audit"), exports);
|
|
@@ -9,12 +9,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
exports.TranslationInterceptor = void 0;
|
|
10
10
|
const common_1 = require("@nestjs/common");
|
|
11
11
|
const operators_1 = require("rxjs/operators");
|
|
12
|
+
// import { TranslationService } from '../shared/services/translation.service';
|
|
13
|
+
// FIXME: add implementation
|
|
12
14
|
let TranslationInterceptor = class TranslationInterceptor {
|
|
15
|
+
// constructor(private readonly translationService: TranslationService) {}
|
|
13
16
|
intercept(context, next) {
|
|
14
17
|
const ctx = context.switchToHttp();
|
|
15
18
|
const req = ctx.getRequest();
|
|
16
19
|
const res = ctx.getResponse();
|
|
17
20
|
return next.handle().pipe((0, operators_1.map)((data) => {
|
|
21
|
+
// const newData = this.translationService.translateNecessaryKeys(data);
|
|
22
|
+
// status 201 => 200
|
|
18
23
|
if (res.statusCode === common_1.HttpStatus.CREATED) {
|
|
19
24
|
res.status(common_1.HttpStatus.OK);
|
|
20
25
|
}
|
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@ class ContextProvider {
|
|
|
8
8
|
const store = nestjs_cls_1.ClsServiceManager.getClsService();
|
|
9
9
|
return store.get(ContextProvider.getKeyWithNamespace(key));
|
|
10
10
|
}
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
12
|
static set(key, value) {
|
|
12
13
|
const store = nestjs_cls_1.ClsServiceManager.getClsService();
|
|
13
14
|
store.set(ContextProvider.getKeyWithNamespace(key), value);
|
|
@@ -24,6 +25,7 @@ class ContextProvider {
|
|
|
24
25
|
static getRouter() {
|
|
25
26
|
const value = ContextProvider.get(ContextProvider.routerKey);
|
|
26
27
|
if (value) {
|
|
28
|
+
// @ts-ignore
|
|
27
29
|
return value;
|
|
28
30
|
}
|
|
29
31
|
return {
|
|
@@ -5,5 +5,9 @@ export declare class GeneratorProvider {
|
|
|
5
5
|
static getS3Key(publicUrl: string): string;
|
|
6
6
|
static generateVerificationCode(): string;
|
|
7
7
|
static generatePassword(): string;
|
|
8
|
+
/**
|
|
9
|
+
* generate random string
|
|
10
|
+
* @param length
|
|
11
|
+
*/
|
|
8
12
|
static generateRandomString(length: number): string;
|
|
9
13
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { OnModuleInit, OnApplicationShutdown } from '@nestjs/common';
|
|
2
|
+
import { RedisLockService } from './redis-lock.service';
|
|
3
|
+
import { LockHeartbeatService } from './lock-heartbeat.service';
|
|
4
|
+
/**
|
|
5
|
+
* Comprehensive lock cleanup service
|
|
6
|
+
*
|
|
7
|
+
* Provides safe and comprehensive lock cleanup mechanism for distributed environments.
|
|
8
|
+
* Combines instance-based precise cleanup with heartbeat-based dead instance detection.
|
|
9
|
+
*
|
|
10
|
+
* **Cleanup Strategy:**
|
|
11
|
+
* 1. **Immediate Precise Cleanup (0s):**
|
|
12
|
+
* - Only cleans locks from the current instance
|
|
13
|
+
* - Safe during rolling updates - won't affect other running instances
|
|
14
|
+
*
|
|
15
|
+
* 2. **Delayed Conservative Cleanup (60s):**
|
|
16
|
+
* - Checks heartbeat of other instances
|
|
17
|
+
* - Only cleans locks from dead instances (no heartbeat)
|
|
18
|
+
* - Gives enough time for rolling updates to complete
|
|
19
|
+
*
|
|
20
|
+
* 3. **Graceful Shutdown Cleanup:**
|
|
21
|
+
* - On SIGTERM/SIGINT, immediately cleans own locks
|
|
22
|
+
* - Ensures locks are released before process exits
|
|
23
|
+
* - Works with PM2 reload and Kubernetes rolling updates
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* // In your module
|
|
28
|
+
* @Module({
|
|
29
|
+
* providers: [
|
|
30
|
+
* RedisLockService,
|
|
31
|
+
* LockHeartbeatService,
|
|
32
|
+
* ComprehensiveLockCleanupService,
|
|
33
|
+
* ],
|
|
34
|
+
* })
|
|
35
|
+
* export class AppModule {}
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare class ComprehensiveLockCleanupService implements OnModuleInit, OnApplicationShutdown {
|
|
39
|
+
private readonly lockService;
|
|
40
|
+
private readonly heartbeatService;
|
|
41
|
+
private readonly logger;
|
|
42
|
+
private readonly instanceId;
|
|
43
|
+
/**
|
|
44
|
+
* Grace period before cleaning other instances' locks (milliseconds)
|
|
45
|
+
* @default 60000 (60 seconds)
|
|
46
|
+
*/
|
|
47
|
+
private readonly gracePeriod;
|
|
48
|
+
constructor(lockService: RedisLockService, heartbeatService: LockHeartbeatService);
|
|
49
|
+
onModuleInit(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Clean up locks from the current instance
|
|
52
|
+
* Safe to run immediately - only affects locks created by this instance
|
|
53
|
+
*/
|
|
54
|
+
private cleanupOwnLocks;
|
|
55
|
+
/**
|
|
56
|
+
* Clean up locks from dead instances
|
|
57
|
+
* Only runs after grace period to avoid cleaning locks during rolling updates
|
|
58
|
+
*/
|
|
59
|
+
private cleanupDeadInstanceLocks;
|
|
60
|
+
/**
|
|
61
|
+
* Check if a lock belongs to the current instance
|
|
62
|
+
*
|
|
63
|
+
* @param lockValue - Lock value to check
|
|
64
|
+
* @returns True if lock belongs to current instance
|
|
65
|
+
*/
|
|
66
|
+
private isOwnLock;
|
|
67
|
+
/**
|
|
68
|
+
* Extract instance ID from lock value
|
|
69
|
+
* Lock value format: instanceId:timestamp:random:pid
|
|
70
|
+
*
|
|
71
|
+
* @param lockValue - Lock value
|
|
72
|
+
* @returns Instance ID or null if cannot be extracted
|
|
73
|
+
*/
|
|
74
|
+
private extractInstanceId;
|
|
75
|
+
/**
|
|
76
|
+
* Get instance identifier
|
|
77
|
+
*/
|
|
78
|
+
private getInstanceId;
|
|
79
|
+
/**
|
|
80
|
+
* Manually trigger cleanup of all stale locks
|
|
81
|
+
* Use with caution - this will clean both own and dead instance locks
|
|
82
|
+
*/
|
|
83
|
+
manualCleanup(): Promise<{
|
|
84
|
+
ownLocks: number;
|
|
85
|
+
deadLocks: number;
|
|
86
|
+
}>;
|
|
87
|
+
private cleanupOwnLocksCount;
|
|
88
|
+
private cleanupDeadInstanceLocksCount;
|
|
89
|
+
/**
|
|
90
|
+
* Cleanup own locks on application shutdown
|
|
91
|
+
* Called when receiving SIGTERM/SIGINT (graceful shutdown)
|
|
92
|
+
*/
|
|
93
|
+
onApplicationShutdown(signal?: string): Promise<void>;
|
|
94
|
+
}
|