@nest-omni/core 4.1.3-2 → 4.1.3-4
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 +15 -0
- 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 +8 -0
- package/audit/decorators/audit-controller.decorator.js +9 -0
- 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 +8 -0
- package/audit/decorators/entity-audit.decorator.js +9 -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 +3 -0
- package/audit/entities/entity-audit-log.entity.js +3 -0
- package/audit/entities/entity-transaction.entity.d.ts +3 -0
- package/audit/entities/entity-transaction.entity.js +3 -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 +17 -2
- package/audit/enums/audit.enums.js +15 -0
- package/audit/index.js +10 -0
- package/audit/interceptors/audit.interceptor.d.ts +15 -0
- package/audit/interceptors/audit.interceptor.js +23 -1
- package/audit/interfaces/audit.interfaces.d.ts +42 -0
- 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 +57 -0
- package/audit/services/entity-audit.service.js +91 -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 -0
- package/common/boilerplate.polyfill.js +17 -0
- 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 +19 -0
- 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/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/examples/lock-strategy.examples.d.ts +89 -0
- package/redis-lock/examples/lock-strategy.examples.js +130 -15
- package/redis-lock/index.js +3 -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 +60 -0
- package/redis-lock/redis-lock.module.js +46 -0
- package/redis-lock/redis-lock.service.d.ts +251 -0
- package/redis-lock/redis-lock.service.js +219 -3
- 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 +226 -0
- package/setup/schedule.decorator.js +214 -1
- package/setup/worker.decorator.d.ts +86 -0
- package/setup/worker.decorator.js +88 -0
- package/shared/serviceRegistryModule.js +5 -1
- 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 +23 -0
- package/validators/custom-validate.examples.js +78 -6
- package/validators/custom-validate.validator.d.ts +107 -0
- package/validators/custom-validate.validator.js +84 -0
- package/validators/index.d.ts +1 -0
- package/validators/index.js +1 -0
- package/validators/is-exists.validator.d.ts +11 -0
- package/validators/is-exists.validator.js +22 -0
- package/validators/is-unique.validator.d.ts +11 -0
- package/validators/is-unique.validator.js +31 -3
- 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
|
@@ -28,6 +28,9 @@ let CustomValidateValidator = class CustomValidateValidator {
|
|
|
28
28
|
constructor(moduleRef) {
|
|
29
29
|
this.moduleRef = moduleRef;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* 验证入口
|
|
33
|
+
*/
|
|
31
34
|
validate(value, args) {
|
|
32
35
|
return __awaiter(this, void 0, void 0, function* () {
|
|
33
36
|
const [constraint, ...extraArgs] = args.constraints;
|
|
@@ -40,12 +43,15 @@ let CustomValidateValidator = class CustomValidateValidator {
|
|
|
40
43
|
args,
|
|
41
44
|
};
|
|
42
45
|
try {
|
|
46
|
+
// 1. 如果是函数,直接调用
|
|
43
47
|
if (typeof constraint === 'function') {
|
|
44
48
|
return yield this.callFunction(constraint, value, context, extraArgs);
|
|
45
49
|
}
|
|
50
|
+
// 2. 如果是字符串,调用 Entity 方法
|
|
46
51
|
if (typeof constraint === 'string') {
|
|
47
52
|
return yield this.callEntityMethod(args.object, constraint, value, context, extraArgs);
|
|
48
53
|
}
|
|
54
|
+
// 3. 如果是数组,调用 Service 方法
|
|
49
55
|
if (Array.isArray(constraint)) {
|
|
50
56
|
return yield this.callServiceMethod(constraint, value, context);
|
|
51
57
|
}
|
|
@@ -53,17 +59,24 @@ let CustomValidateValidator = class CustomValidateValidator {
|
|
|
53
59
|
`Expected: function, string, or array. Got: ${typeof constraint}`);
|
|
54
60
|
}
|
|
55
61
|
catch (error) {
|
|
62
|
+
// 验证函数执行出错,记录详细错误信息
|
|
56
63
|
console.error(`[@CustomValidate] Validation error for property "${args.property}":`, error);
|
|
57
64
|
throw error;
|
|
58
65
|
}
|
|
59
66
|
});
|
|
60
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* 调用内联函数
|
|
70
|
+
*/
|
|
61
71
|
callFunction(fn, value, context, extraArgs) {
|
|
62
72
|
return __awaiter(this, void 0, void 0, function* () {
|
|
63
73
|
const result = fn(value, context, ...extraArgs);
|
|
64
74
|
return result instanceof Promise ? yield result : result;
|
|
65
75
|
});
|
|
66
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* 调用 Entity 方法
|
|
79
|
+
*/
|
|
67
80
|
callEntityMethod(entity, methodName, value, context, extraArgs) {
|
|
68
81
|
return __awaiter(this, void 0, void 0, function* () {
|
|
69
82
|
if (!entity || typeof entity[methodName] !== 'function') {
|
|
@@ -74,13 +87,18 @@ let CustomValidateValidator = class CustomValidateValidator {
|
|
|
74
87
|
return result instanceof Promise ? yield result : result;
|
|
75
88
|
});
|
|
76
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* 调用 Service 方法
|
|
92
|
+
*/
|
|
77
93
|
callServiceMethod(constraint, value, context) {
|
|
78
94
|
return __awaiter(this, void 0, void 0, function* () {
|
|
79
95
|
let [serviceClass, methodName, ...extraArgs] = constraint;
|
|
96
|
+
// 验证参数
|
|
80
97
|
if (!serviceClass || !methodName) {
|
|
81
98
|
throw new Error(`[@CustomValidate] Invalid service constraint format. ` +
|
|
82
99
|
`Expected: [ServiceClass, 'methodName'] or [() => ServiceClass, 'methodName']`);
|
|
83
100
|
}
|
|
101
|
+
// 解析延迟引用(解决循环依赖)
|
|
84
102
|
if (typeof serviceClass === 'function' && !serviceClass.prototype) {
|
|
85
103
|
serviceClass = serviceClass();
|
|
86
104
|
}
|
|
@@ -89,6 +107,7 @@ let CustomValidateValidator = class CustomValidateValidator {
|
|
|
89
107
|
`This may be caused by circular dependencies. ` +
|
|
90
108
|
`Consider using lazy reference: [() => ServiceClass, 'methodName']`);
|
|
91
109
|
}
|
|
110
|
+
// 通过依赖注入获取 service 实例
|
|
92
111
|
let service;
|
|
93
112
|
try {
|
|
94
113
|
service = this.moduleRef.get(serviceClass, { strict: false });
|
|
@@ -106,7 +125,11 @@ let CustomValidateValidator = class CustomValidateValidator {
|
|
|
106
125
|
return result instanceof Promise ? yield result : result;
|
|
107
126
|
});
|
|
108
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* 默认错误消息
|
|
130
|
+
*/
|
|
109
131
|
defaultMessage(args) {
|
|
132
|
+
// 优先使用 i18n
|
|
110
133
|
return (0, nestjs_i18n_1.i18nValidationMessage)('validation.CUSTOM_VALIDATE')(args);
|
|
111
134
|
}
|
|
112
135
|
};
|
|
@@ -116,6 +139,67 @@ exports.CustomValidateValidator = CustomValidateValidator = __decorate([
|
|
|
116
139
|
(0, class_validator_1.ValidatorConstraint)({ name: 'customValidate', async: true }),
|
|
117
140
|
__metadata("design:paramtypes", [core_1.ModuleRef])
|
|
118
141
|
], CustomValidateValidator);
|
|
142
|
+
/**
|
|
143
|
+
* @CustomValidate 装饰器
|
|
144
|
+
*
|
|
145
|
+
* 支持多种验证方式的灵活验证装饰器
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* // 1. 内联函数(同步)
|
|
149
|
+
* @CustomValidate(
|
|
150
|
+
* (value) => value > 0,
|
|
151
|
+
* { message: '价格必须大于0' }
|
|
152
|
+
* )
|
|
153
|
+
* price: number;
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* // 2. 内联函数(异步)
|
|
157
|
+
* @CustomValidate(
|
|
158
|
+
* async (value, context) => {
|
|
159
|
+
* const response = await fetch(`/api/check/${value}`);
|
|
160
|
+
* return response.ok;
|
|
161
|
+
* }
|
|
162
|
+
* )
|
|
163
|
+
* username: string;
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* // 3. Entity 方法
|
|
167
|
+
* @CustomValidate('validateVersion')
|
|
168
|
+
* version: string;
|
|
169
|
+
*
|
|
170
|
+
* validateVersion(value: string): boolean {
|
|
171
|
+
* return /^\d+\.\d+\.\d+$/.test(value);
|
|
172
|
+
* }
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* // 4. Service 方法
|
|
176
|
+
* @CustomValidate([UserValidationService, 'checkUsername'])
|
|
177
|
+
* username: string;
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* // 5. 延迟引用(解决循环依赖)
|
|
181
|
+
* @CustomValidate([() => UserValidationService, 'checkUsername'])
|
|
182
|
+
* username: string;
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* // 6. 带额外参数
|
|
186
|
+
* @CustomValidate(
|
|
187
|
+
* [ValidationService, 'checkRange', 0, 100],
|
|
188
|
+
* { message: '价格必须在 0-100 之间' }
|
|
189
|
+
* )
|
|
190
|
+
* price: number;
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* // 7. 使用 i18n
|
|
194
|
+
* @CustomValidate(
|
|
195
|
+
* (value) => value.length >= 6,
|
|
196
|
+
* { message: 'validation.PASSWORD_TOO_SHORT' }
|
|
197
|
+
* )
|
|
198
|
+
* password: string;
|
|
199
|
+
*
|
|
200
|
+
* @param constraint 验证约束(函数、方法名、或 [Service, 方法名])
|
|
201
|
+
* @param validationOptions 验证选项
|
|
202
|
+
*/
|
|
119
203
|
function CustomValidate(constraint, validationOptions) {
|
|
120
204
|
return (object, propertyName) => {
|
|
121
205
|
(0, class_validator_1.registerDecorator)({
|
package/validators/index.d.ts
CHANGED
package/validators/index.js
CHANGED
|
@@ -21,3 +21,4 @@ __exportStar(require("./is-exists.validator"), exports);
|
|
|
21
21
|
__exportStar(require("./is-unique.validator"), exports);
|
|
22
22
|
__exportStar(require("./same-as.validator"), exports);
|
|
23
23
|
__exportStar(require("./custom-validate.validator"), exports);
|
|
24
|
+
__exportStar(require("./common-validators"), exports);
|
|
@@ -5,7 +5,18 @@ import { TransactionalAdapterTypeOrm } from '@nestjs-cls/transactional-adapter-t
|
|
|
5
5
|
export declare class IsExistsValidator implements ValidatorConstraintInterface {
|
|
6
6
|
private readonly transactionHost;
|
|
7
7
|
constructor(transactionHost: TransactionHost<TransactionalAdapterTypeOrm>);
|
|
8
|
+
/**
|
|
9
|
+
* 解析 Entity 引用,支持多种形式:
|
|
10
|
+
* 1. Entity 类直接引用
|
|
11
|
+
* 2. 延迟函数 () => Entity
|
|
12
|
+
* 3. 字符串名称 "EntityName"
|
|
13
|
+
* 4. undefined (从属性名自动推断)
|
|
14
|
+
*/
|
|
8
15
|
private resolveEntity;
|
|
16
|
+
/**
|
|
17
|
+
* 从属性名推断 Entity 名称
|
|
18
|
+
* 例如:appId -> App, userId -> User
|
|
19
|
+
*/
|
|
9
20
|
private inferEntityNameFromProperty;
|
|
10
21
|
validate<E>(value: string, args: IExistsValidationArguments<E>): Promise<boolean>;
|
|
11
22
|
defaultMessage(args: ValidationArguments): string;
|
|
@@ -28,26 +28,41 @@ let IsExistsValidator = class IsExistsValidator {
|
|
|
28
28
|
constructor(transactionHost) {
|
|
29
29
|
this.transactionHost = transactionHost;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* 解析 Entity 引用,支持多种形式:
|
|
33
|
+
* 1. Entity 类直接引用
|
|
34
|
+
* 2. 延迟函数 () => Entity
|
|
35
|
+
* 3. 字符串名称 "EntityName"
|
|
36
|
+
* 4. undefined (从属性名自动推断)
|
|
37
|
+
*/
|
|
31
38
|
resolveEntity(entityRef, propertyName, object) {
|
|
39
|
+
// 1. 如果是字符串,直接返回(TypeORM 支持字符串)
|
|
32
40
|
if (typeof entityRef === 'string') {
|
|
33
41
|
return entityRef;
|
|
34
42
|
}
|
|
43
|
+
// 2. 如果是函数,需要区分延迟函数和 Entity 类
|
|
35
44
|
if (typeof entityRef === 'function') {
|
|
45
|
+
// 2.1 箭头函数没有 prototype,是延迟函数
|
|
36
46
|
if (!entityRef.prototype) {
|
|
37
47
|
const resolved = entityRef();
|
|
38
48
|
if (resolved)
|
|
39
49
|
return resolved;
|
|
40
50
|
}
|
|
41
51
|
else {
|
|
52
|
+
// 2.2 有 prototype,是 Entity 类或普通构造函数
|
|
53
|
+
// 直接返回
|
|
42
54
|
return entityRef;
|
|
43
55
|
}
|
|
44
56
|
}
|
|
57
|
+
// 3. 如果是 undefined,尝试从属性名推断 Entity
|
|
58
|
+
// 例如:appId -> AppEntity, userId -> UserEntity
|
|
45
59
|
if (!entityRef) {
|
|
46
60
|
const inferredEntityName = this.inferEntityNameFromProperty(propertyName);
|
|
47
61
|
if (inferredEntityName) {
|
|
48
62
|
console.warn(`[IsExists] Entity reference is undefined for property "${propertyName}". ` +
|
|
49
63
|
`This may be caused by circular dependencies. ` +
|
|
50
64
|
`Consider using lazy reference: () => ${inferredEntityName}`);
|
|
65
|
+
// 返回字符串形式的 Entity 名称
|
|
51
66
|
return inferredEntityName;
|
|
52
67
|
}
|
|
53
68
|
}
|
|
@@ -58,16 +73,23 @@ let IsExistsValidator = class IsExistsValidator {
|
|
|
58
73
|
`2. String reference: @IsExists(["EntityName", ...])\n` +
|
|
59
74
|
`3. Break the circular dependency`);
|
|
60
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* 从属性名推断 Entity 名称
|
|
78
|
+
* 例如:appId -> App, userId -> User
|
|
79
|
+
*/
|
|
61
80
|
inferEntityNameFromProperty(propertyName) {
|
|
81
|
+
// 移除常见后缀:Id, Ids, Key, Code
|
|
62
82
|
const name = propertyName.replace(/(Id|Ids|Key|Code)$/, '');
|
|
63
83
|
if (!name)
|
|
64
84
|
return null;
|
|
85
|
+
// 转换为 PascalCase 并添加 Entity 后缀
|
|
65
86
|
const entityName = name.charAt(0).toUpperCase() + name.slice(1) + 'Entity';
|
|
66
87
|
return entityName;
|
|
67
88
|
}
|
|
68
89
|
validate(value, args) {
|
|
69
90
|
return __awaiter(this, void 0, void 0, function* () {
|
|
70
91
|
const [entityRef, findCondition] = args.constraints;
|
|
92
|
+
// 解析 Entity 引用
|
|
71
93
|
const entityClass = this.resolveEntity(entityRef, args.property, args.object);
|
|
72
94
|
const repository = this.transactionHost.tx.getRepository(entityClass);
|
|
73
95
|
args.value = value;
|
|
@@ -5,7 +5,18 @@ import { TransactionalAdapterTypeOrm } from '@nestjs-cls/transactional-adapter-t
|
|
|
5
5
|
export declare class IsUniqueValidator implements ValidatorConstraintInterface {
|
|
6
6
|
private readonly transactionHost;
|
|
7
7
|
constructor(transactionHost: TransactionHost<TransactionalAdapterTypeOrm>);
|
|
8
|
+
/**
|
|
9
|
+
* 解析 Entity 引用,支持多种形式:
|
|
10
|
+
* 1. Entity 类直接引用
|
|
11
|
+
* 2. 延迟函数 () => Entity
|
|
12
|
+
* 3. 字符串名称 "EntityName"
|
|
13
|
+
* 4. undefined (从属性名自动推断)
|
|
14
|
+
*/
|
|
8
15
|
private resolveEntity;
|
|
16
|
+
/**
|
|
17
|
+
* 从属性名推断 Entity 名称
|
|
18
|
+
* 例如:appId -> App, userId -> User
|
|
19
|
+
*/
|
|
9
20
|
private inferEntityNameFromProperty;
|
|
10
21
|
validate<E>(value: string, args: IUniqueValidationArguments<E>): Promise<boolean>;
|
|
11
22
|
defaultMessage(args: ValidationArguments): string;
|
|
@@ -28,20 +28,33 @@ let IsUniqueValidator = class IsUniqueValidator {
|
|
|
28
28
|
constructor(transactionHost) {
|
|
29
29
|
this.transactionHost = transactionHost;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* 解析 Entity 引用,支持多种形式:
|
|
33
|
+
* 1. Entity 类直接引用
|
|
34
|
+
* 2. 延迟函数 () => Entity
|
|
35
|
+
* 3. 字符串名称 "EntityName"
|
|
36
|
+
* 4. undefined (从属性名自动推断)
|
|
37
|
+
*/
|
|
31
38
|
resolveEntity(entityRef, propertyName, object) {
|
|
39
|
+
// 1. 如果是字符串,直接返回(TypeORM 支持字符串)
|
|
32
40
|
if (typeof entityRef === 'string') {
|
|
33
41
|
return entityRef;
|
|
34
42
|
}
|
|
43
|
+
// 2. 如果是函数,需要区分延迟函数和 Entity 类
|
|
35
44
|
if (typeof entityRef === 'function') {
|
|
45
|
+
// 2.1 箭头函数没有 prototype,是延迟函数
|
|
36
46
|
if (!entityRef.prototype) {
|
|
37
47
|
const resolved = entityRef();
|
|
38
48
|
if (resolved)
|
|
39
49
|
return resolved;
|
|
40
50
|
}
|
|
41
51
|
else {
|
|
52
|
+
// 2.2 有 prototype,是 Entity 类或普通构造函数
|
|
53
|
+
// 直接返回
|
|
42
54
|
return entityRef;
|
|
43
55
|
}
|
|
44
56
|
}
|
|
57
|
+
// 3. 如果是 undefined,尝试从属性名推断 Entity
|
|
45
58
|
if (!entityRef) {
|
|
46
59
|
const inferredEntityName = this.inferEntityNameFromProperty(propertyName);
|
|
47
60
|
if (inferredEntityName) {
|
|
@@ -58,6 +71,10 @@ let IsUniqueValidator = class IsUniqueValidator {
|
|
|
58
71
|
`2. String reference: @IsUnique(["EntityName", ...])\n` +
|
|
59
72
|
`3. Break the circular dependency`);
|
|
60
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* 从属性名推断 Entity 名称
|
|
76
|
+
* 例如:appId -> App, userId -> User
|
|
77
|
+
*/
|
|
61
78
|
inferEntityNameFromProperty(propertyName) {
|
|
62
79
|
const name = propertyName.replace(/(Id|Ids|Key|Code)$/, '');
|
|
63
80
|
if (!name)
|
|
@@ -68,6 +85,7 @@ let IsUniqueValidator = class IsUniqueValidator {
|
|
|
68
85
|
validate(value, args) {
|
|
69
86
|
return __awaiter(this, void 0, void 0, function* () {
|
|
70
87
|
const [entityRef, findCondition] = args.constraints;
|
|
88
|
+
// 解析 Entity 引用
|
|
71
89
|
const entityClass = this.resolveEntity(entityRef, args.property, args.object);
|
|
72
90
|
const repository = this.transactionHost.tx.getRepository(entityClass);
|
|
73
91
|
args.value = value;
|
|
@@ -75,13 +93,20 @@ let IsUniqueValidator = class IsUniqueValidator {
|
|
|
75
93
|
const defCon = findCondition(args);
|
|
76
94
|
const pkCols = repository.metadata
|
|
77
95
|
.primaryColumns.map((column) => column.propertyName);
|
|
78
|
-
|
|
79
|
-
|
|
96
|
+
// 修复:检查是否为新建记录
|
|
97
|
+
// 如果所有主键都没有值(null/undefined),则为新建
|
|
98
|
+
const isNew = !pkCols.some((pk) => {
|
|
99
|
+
const pkValue = args.object[pk];
|
|
100
|
+
return pkValue !== null && pkValue !== undefined && pkValue !== '';
|
|
101
|
+
});
|
|
102
|
+
if (isNew) {
|
|
103
|
+
// 新建场景:简单检查是否存在相同值的记录
|
|
80
104
|
exists =
|
|
81
105
|
(yield repository
|
|
82
106
|
.count({ where: defCon })) < 1;
|
|
83
107
|
}
|
|
84
108
|
else {
|
|
109
|
+
// 更新场景:需要排除当前记录(通过主键对比)
|
|
85
110
|
const entities = yield repository
|
|
86
111
|
.createQueryBuilder()
|
|
87
112
|
.where(defCon)
|
|
@@ -90,16 +115,19 @@ let IsUniqueValidator = class IsUniqueValidator {
|
|
|
90
115
|
.execute();
|
|
91
116
|
const entityCount = entities.length;
|
|
92
117
|
if (entityCount === 1) {
|
|
118
|
+
// 只有一条记录,检查是否是当前记录本身
|
|
93
119
|
const entity = entities[0];
|
|
94
120
|
const oldPk = {};
|
|
95
121
|
const newPk = {};
|
|
96
|
-
pkCols.
|
|
122
|
+
pkCols.forEach((pk) => {
|
|
97
123
|
oldPk[pk] = entity[pk];
|
|
98
124
|
newPk[pk] = args.object[pk];
|
|
99
125
|
});
|
|
126
|
+
// 如果主键相同,说明是自己,允许(唯一)
|
|
100
127
|
exists = JSON.stringify(oldPk) === JSON.stringify(newPk);
|
|
101
128
|
}
|
|
102
129
|
else {
|
|
130
|
+
// 0条或多条记录
|
|
103
131
|
exists = entityCount < 1;
|
|
104
132
|
}
|
|
105
133
|
}
|
|
@@ -1 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When the value is emtpy, validation is skipped
|
|
3
|
+
* @param field
|
|
4
|
+
* @constructor
|
|
5
|
+
*/
|
|
1
6
|
export declare function SkipEmpty(field?: string): <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
|
|
@@ -5,6 +5,11 @@ const common_1 = require("@nestjs/common");
|
|
|
5
5
|
const swagger_1 = require("@nestjs/swagger");
|
|
6
6
|
const class_validator_1 = require("class-validator");
|
|
7
7
|
const lodash_1 = require("lodash");
|
|
8
|
+
/**
|
|
9
|
+
* When the value is emtpy, validation is skipped
|
|
10
|
+
* @param field
|
|
11
|
+
* @constructor
|
|
12
|
+
*/
|
|
8
13
|
function SkipEmpty(field) {
|
|
9
14
|
return (0, common_1.applyDecorators)((0, swagger_1.ApiProperty)({ required: false }), (0, class_validator_1.ValidateIf)((obj, value) => {
|
|
10
15
|
if (field) {
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault 认证选项
|
|
3
|
+
*/
|
|
1
4
|
export interface VaultAuthOptions {
|
|
2
5
|
token?: string;
|
|
3
6
|
roleId?: string;
|
|
@@ -5,6 +8,9 @@ export interface VaultAuthOptions {
|
|
|
5
8
|
k8sRole?: string;
|
|
6
9
|
k8sServiceAccountToken?: string;
|
|
7
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Vault 配置选项
|
|
13
|
+
*/
|
|
8
14
|
export interface VaultOptions {
|
|
9
15
|
endpoint: string;
|
|
10
16
|
auth: VaultAuthOptions;
|
|
@@ -16,6 +22,9 @@ export interface VaultOptions {
|
|
|
16
22
|
hotReloadInterval?: number;
|
|
17
23
|
failOnError?: boolean;
|
|
18
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Vault 配置
|
|
27
|
+
*/
|
|
19
28
|
export interface VaultConfig {
|
|
20
29
|
enabled: boolean;
|
|
21
30
|
options?: VaultOptions;
|
|
@@ -1,13 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault 配置加载器
|
|
3
|
+
* 负责在应用启动时从 Vault 加载配置并注入到 process.env
|
|
4
|
+
* 配置优先级: base.env < 环境.env < Vault
|
|
5
|
+
*/
|
|
1
6
|
export declare class VaultConfigLoader {
|
|
2
7
|
private static readonly logger;
|
|
3
8
|
private static vaultClient;
|
|
4
9
|
private static hotReloadTimer;
|
|
10
|
+
/**
|
|
11
|
+
* 从环境变量构建 Vault 配置
|
|
12
|
+
*/
|
|
5
13
|
private static buildVaultOptions;
|
|
14
|
+
/**
|
|
15
|
+
* 初始化 Vault 客户端并进行认证
|
|
16
|
+
*/
|
|
6
17
|
private static initializeVaultClient;
|
|
18
|
+
/**
|
|
19
|
+
* 从 Vault 读取指定路径的配置
|
|
20
|
+
*/
|
|
7
21
|
private static readSecrets;
|
|
22
|
+
/**
|
|
23
|
+
* 加载 Vault 配置并注入到 process.env
|
|
24
|
+
* 配置优先级: base.env < 环境.env < Vault(Vault 会覆盖之前的配置)
|
|
25
|
+
*/
|
|
8
26
|
static loadVaultConfig(): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* 启动配置热更新
|
|
29
|
+
*/
|
|
9
30
|
private static startHotReload;
|
|
31
|
+
/**
|
|
32
|
+
* 停止热更新
|
|
33
|
+
*/
|
|
10
34
|
static stopHotReload(): void;
|
|
35
|
+
/**
|
|
36
|
+
* 获取 Vault 客户端(用于运行时动态读取)
|
|
37
|
+
*/
|
|
11
38
|
static getVaultClient(): any;
|
|
39
|
+
/**
|
|
40
|
+
* 检查 Vault 是否已连接
|
|
41
|
+
*/
|
|
12
42
|
static isConnected(): boolean;
|
|
13
43
|
}
|
|
@@ -11,7 +11,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.VaultConfigLoader = void 0;
|
|
13
13
|
const common_1 = require("@nestjs/common");
|
|
14
|
+
/**
|
|
15
|
+
* Vault 配置加载器
|
|
16
|
+
* 负责在应用启动时从 Vault 加载配置并注入到 process.env
|
|
17
|
+
* 配置优先级: base.env < 环境.env < Vault
|
|
18
|
+
*/
|
|
14
19
|
class VaultConfigLoader {
|
|
20
|
+
/**
|
|
21
|
+
* 从环境变量构建 Vault 配置
|
|
22
|
+
*/
|
|
15
23
|
static buildVaultOptions() {
|
|
16
24
|
var _a;
|
|
17
25
|
const enabled = process.env.VAULT_ENABLED === 'true';
|
|
@@ -29,6 +37,7 @@ class VaultConfigLoader {
|
|
|
29
37
|
this.logger.warn('Vault enabled but VAULT_SECRET_PATHS is empty');
|
|
30
38
|
return null;
|
|
31
39
|
}
|
|
40
|
+
// 构建认证配置
|
|
32
41
|
const auth = {};
|
|
33
42
|
if (process.env.VAULT_TOKEN) {
|
|
34
43
|
auth.token = process.env.VAULT_TOKEN;
|
|
@@ -57,13 +66,17 @@ class VaultConfigLoader {
|
|
|
57
66
|
timeout: parseInt(process.env.VAULT_TIMEOUT || '5000', 10),
|
|
58
67
|
enableHotReload: process.env.VAULT_HOT_RELOAD === 'true',
|
|
59
68
|
hotReloadInterval: parseInt(process.env.VAULT_HOT_RELOAD_INTERVAL || '300', 10),
|
|
60
|
-
failOnError: process.env.VAULT_FAIL_ON_ERROR !== 'false',
|
|
69
|
+
failOnError: process.env.VAULT_FAIL_ON_ERROR !== 'false', // 默认失败时终止
|
|
61
70
|
};
|
|
62
71
|
this.logger.log(`Vault configuration loaded: ${secretPaths.length} secret path(s)`);
|
|
63
72
|
return options;
|
|
64
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* 初始化 Vault 客户端并进行认证
|
|
76
|
+
*/
|
|
65
77
|
static initializeVaultClient(options) {
|
|
66
78
|
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
// 动态导入 node-vault
|
|
67
80
|
let vault;
|
|
68
81
|
try {
|
|
69
82
|
vault = yield Promise.resolve().then(() => require('node-vault'));
|
|
@@ -79,12 +92,15 @@ class VaultConfigLoader {
|
|
|
79
92
|
timeout: options.timeout,
|
|
80
93
|
},
|
|
81
94
|
});
|
|
95
|
+
// 根据认证方式进行认证
|
|
82
96
|
try {
|
|
83
97
|
if (options.auth.token) {
|
|
98
|
+
// Token 认证
|
|
84
99
|
client.token = options.auth.token;
|
|
85
100
|
this.logger.log('Vault Token authentication configured');
|
|
86
101
|
}
|
|
87
102
|
else if (options.auth.roleId && options.auth.secretId) {
|
|
103
|
+
// AppRole 认证
|
|
88
104
|
const result = yield client.approleLogin({
|
|
89
105
|
role_id: options.auth.roleId,
|
|
90
106
|
secret_id: options.auth.secretId,
|
|
@@ -93,7 +109,9 @@ class VaultConfigLoader {
|
|
|
93
109
|
this.logger.log('Vault AppRole authentication successful');
|
|
94
110
|
}
|
|
95
111
|
else if (options.auth.k8sRole) {
|
|
112
|
+
// Kubernetes 认证
|
|
96
113
|
let jwt = options.auth.k8sServiceAccountToken;
|
|
114
|
+
// 如果没有提供 token,从默认路径读取
|
|
97
115
|
if (!jwt) {
|
|
98
116
|
const fs = yield Promise.resolve().then(() => require('fs'));
|
|
99
117
|
const K8S_SA_TOKEN_PATH = '/var/run/secrets/kubernetes.io/serviceaccount/token';
|
|
@@ -114,6 +132,7 @@ class VaultConfigLoader {
|
|
|
114
132
|
else {
|
|
115
133
|
throw new Error('No valid Vault authentication method configured');
|
|
116
134
|
}
|
|
135
|
+
// 验证 token 是否有效
|
|
117
136
|
yield client.tokenLookupSelf();
|
|
118
137
|
this.logger.log('Vault authentication verified');
|
|
119
138
|
return client;
|
|
@@ -124,6 +143,9 @@ class VaultConfigLoader {
|
|
|
124
143
|
}
|
|
125
144
|
});
|
|
126
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* 从 Vault 读取指定路径的配置
|
|
148
|
+
*/
|
|
127
149
|
static readSecrets(client, secretPath, apiVersion) {
|
|
128
150
|
return __awaiter(this, void 0, void 0, function* () {
|
|
129
151
|
try {
|
|
@@ -133,6 +155,8 @@ class VaultConfigLoader {
|
|
|
133
155
|
this.logger.warn(`No data found at path: ${secretPath}`);
|
|
134
156
|
return {};
|
|
135
157
|
}
|
|
158
|
+
// KV v2 引擎的数据在 data.data 中
|
|
159
|
+
// KV v1 引擎的数据在 data 中
|
|
136
160
|
const secrets = apiVersion === 'v2' ? result.data.data : result.data;
|
|
137
161
|
if (!secrets || typeof secrets !== 'object') {
|
|
138
162
|
this.logger.warn(`Invalid secret format at path: ${secretPath}`);
|
|
@@ -148,6 +172,10 @@ class VaultConfigLoader {
|
|
|
148
172
|
}
|
|
149
173
|
});
|
|
150
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* 加载 Vault 配置并注入到 process.env
|
|
177
|
+
* 配置优先级: base.env < 环境.env < Vault(Vault 会覆盖之前的配置)
|
|
178
|
+
*/
|
|
151
179
|
static loadVaultConfig() {
|
|
152
180
|
return __awaiter(this, void 0, void 0, function* () {
|
|
153
181
|
const options = this.buildVaultOptions();
|
|
@@ -158,11 +186,14 @@ class VaultConfigLoader {
|
|
|
158
186
|
try {
|
|
159
187
|
this.logger.log(`Connecting to Vault at ${options.endpoint}`);
|
|
160
188
|
this.vaultClient = yield this.initializeVaultClient(options);
|
|
189
|
+
// 从所有配置路径读取配置(后面的路径会覆盖前面的)
|
|
161
190
|
const allSecrets = {};
|
|
162
191
|
for (const secretPath of options.secretPaths) {
|
|
163
192
|
const secrets = yield this.readSecrets(this.vaultClient, secretPath, options.apiVersion);
|
|
193
|
+
// 合并配置(后面的路径会覆盖前面的)
|
|
164
194
|
Object.assign(allSecrets, secrets);
|
|
165
195
|
}
|
|
196
|
+
// 注入到 process.env(覆盖所有已有的环境变量)
|
|
166
197
|
let injectedCount = 0;
|
|
167
198
|
let overriddenCount = 0;
|
|
168
199
|
for (const [key, value] of Object.entries(allSecrets)) {
|
|
@@ -177,12 +208,14 @@ class VaultConfigLoader {
|
|
|
177
208
|
}
|
|
178
209
|
}
|
|
179
210
|
this.logger.log(`Vault configuration loaded: ${injectedCount} new, ${overriddenCount} overridden`);
|
|
211
|
+
// 启动热更新(如果启用)
|
|
180
212
|
if (options.enableHotReload) {
|
|
181
213
|
this.startHotReload(options);
|
|
182
214
|
}
|
|
183
215
|
}
|
|
184
216
|
catch (error) {
|
|
185
217
|
this.logger.error('Failed to load Vault configuration', error.message);
|
|
218
|
+
// 根据配置决定是否在 Vault 失败时继续启动
|
|
186
219
|
if (options.failOnError) {
|
|
187
220
|
this.logger.error('Application startup failed due to Vault error');
|
|
188
221
|
throw error;
|
|
@@ -193,8 +226,12 @@ class VaultConfigLoader {
|
|
|
193
226
|
}
|
|
194
227
|
});
|
|
195
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* 启动配置热更新
|
|
231
|
+
*/
|
|
196
232
|
static startHotReload(options) {
|
|
197
233
|
this.logger.log(`Starting Vault hot reload with interval: ${options.hotReloadInterval}s`);
|
|
234
|
+
// 清除之前的定时器
|
|
198
235
|
if (this.hotReloadTimer) {
|
|
199
236
|
clearInterval(this.hotReloadTimer);
|
|
200
237
|
}
|
|
@@ -206,6 +243,7 @@ class VaultConfigLoader {
|
|
|
206
243
|
const secrets = yield this.readSecrets(this.vaultClient, secretPath, options.apiVersion);
|
|
207
244
|
Object.assign(allSecrets, secrets);
|
|
208
245
|
}
|
|
246
|
+
// 更新 process.env
|
|
209
247
|
let changedCount = 0;
|
|
210
248
|
for (const [key, value] of Object.entries(allSecrets)) {
|
|
211
249
|
const newValue = String(value);
|
|
@@ -227,6 +265,9 @@ class VaultConfigLoader {
|
|
|
227
265
|
}
|
|
228
266
|
}), options.hotReloadInterval * 1000);
|
|
229
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* 停止热更新
|
|
270
|
+
*/
|
|
230
271
|
static stopHotReload() {
|
|
231
272
|
if (this.hotReloadTimer) {
|
|
232
273
|
clearInterval(this.hotReloadTimer);
|
|
@@ -234,9 +275,15 @@ class VaultConfigLoader {
|
|
|
234
275
|
this.logger.log('Vault hot reload stopped');
|
|
235
276
|
}
|
|
236
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* 获取 Vault 客户端(用于运行时动态读取)
|
|
280
|
+
*/
|
|
237
281
|
static getVaultClient() {
|
|
238
282
|
return this.vaultClient;
|
|
239
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* 检查 Vault 是否已连接
|
|
286
|
+
*/
|
|
240
287
|
static isConnected() {
|
|
241
288
|
return this.vaultClient !== null && this.vaultClient !== undefined;
|
|
242
289
|
}
|