@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.
Files changed (235) hide show
  1. package/audit/audit.module.d.ts +10 -0
  2. package/audit/audit.module.js +15 -0
  3. package/audit/controllers/audit.controller.d.ts +24 -0
  4. package/audit/controllers/audit.controller.js +24 -0
  5. package/audit/decorators/audit-controller.decorator.d.ts +8 -0
  6. package/audit/decorators/audit-controller.decorator.js +9 -0
  7. package/audit/decorators/audit-operation.decorator.d.ts +45 -0
  8. package/audit/decorators/audit-operation.decorator.js +49 -0
  9. package/audit/decorators/entity-audit.decorator.d.ts +8 -0
  10. package/audit/decorators/entity-audit.decorator.js +9 -0
  11. package/audit/dto/audit-log-query.dto.d.ts +3 -0
  12. package/audit/dto/audit-log-query.dto.js +3 -0
  13. package/audit/dto/begin-transaction.dto.d.ts +3 -0
  14. package/audit/dto/begin-transaction.dto.js +3 -0
  15. package/audit/dto/compare-entities.dto.d.ts +3 -0
  16. package/audit/dto/compare-entities.dto.js +3 -0
  17. package/audit/dto/pre-check-restore.dto.d.ts +3 -0
  18. package/audit/dto/pre-check-restore.dto.js +3 -0
  19. package/audit/dto/restore-entity.dto.d.ts +3 -0
  20. package/audit/dto/restore-entity.dto.js +3 -0
  21. package/audit/entities/entity-audit-log.entity.d.ts +3 -0
  22. package/audit/entities/entity-audit-log.entity.js +3 -0
  23. package/audit/entities/entity-transaction.entity.d.ts +3 -0
  24. package/audit/entities/entity-transaction.entity.js +3 -0
  25. package/audit/entities/manual-operation-log.entity.d.ts +4 -0
  26. package/audit/entities/manual-operation-log.entity.js +4 -0
  27. package/audit/entities/operation-template.entity.d.ts +4 -0
  28. package/audit/entities/operation-template.entity.js +4 -0
  29. package/audit/enums/audit.enums.d.ts +17 -2
  30. package/audit/enums/audit.enums.js +15 -0
  31. package/audit/index.js +10 -0
  32. package/audit/interceptors/audit.interceptor.d.ts +15 -0
  33. package/audit/interceptors/audit.interceptor.js +23 -1
  34. package/audit/interfaces/audit.interfaces.d.ts +42 -0
  35. package/audit/services/audit-context.service.d.ts +15 -0
  36. package/audit/services/audit-context.service.js +15 -0
  37. package/audit/services/audit-strategy.service.d.ts +6 -0
  38. package/audit/services/audit-strategy.service.js +13 -0
  39. package/audit/services/entity-audit.service.d.ts +57 -0
  40. package/audit/services/entity-audit.service.js +91 -0
  41. package/audit/services/manual-audit-log.service.d.ts +124 -0
  42. package/audit/services/manual-audit-log.service.js +138 -0
  43. package/audit/services/multi-database.service.d.ts +12 -0
  44. package/audit/services/multi-database.service.js +12 -0
  45. package/audit/services/operation-description.service.d.ts +59 -0
  46. package/audit/services/operation-description.service.js +76 -2
  47. package/audit/services/transaction-audit.service.d.ts +30 -0
  48. package/audit/services/transaction-audit.service.js +47 -0
  49. package/audit/subscribers/entity-audit.subscriber.d.ts +15 -0
  50. package/audit/subscribers/entity-audit.subscriber.js +29 -1
  51. package/cache/cache-metrics.service.d.ts +67 -0
  52. package/cache/cache-metrics.service.js +68 -4
  53. package/cache/cache-serialization.service.d.ts +31 -0
  54. package/cache/cache-serialization.service.js +25 -0
  55. package/cache/cache.constants.d.ts +9 -0
  56. package/cache/cache.constants.js +9 -0
  57. package/cache/cache.health.d.ts +26 -0
  58. package/cache/cache.health.js +30 -0
  59. package/cache/cache.module.d.ts +86 -0
  60. package/cache/cache.module.js +71 -0
  61. package/cache/cache.service.d.ts +140 -0
  62. package/cache/cache.service.js +157 -0
  63. package/cache/cache.warmup.service.d.ts +39 -0
  64. package/cache/cache.warmup.service.js +32 -0
  65. package/cache/decorators/cache-evict.decorator.d.ts +47 -0
  66. package/cache/decorators/cache-evict.decorator.js +56 -0
  67. package/cache/decorators/cache-put.decorator.d.ts +34 -0
  68. package/cache/decorators/cache-put.decorator.js +39 -0
  69. package/cache/decorators/cacheable.decorator.d.ts +40 -0
  70. package/cache/decorators/cacheable.decorator.js +55 -0
  71. package/cache/dependencies/callback.dependency.d.ts +33 -0
  72. package/cache/dependencies/callback.dependency.js +39 -1
  73. package/cache/dependencies/chain.dependency.d.ts +28 -0
  74. package/cache/dependencies/chain.dependency.js +34 -0
  75. package/cache/dependencies/db.dependency.d.ts +45 -0
  76. package/cache/dependencies/db.dependency.js +48 -1
  77. package/cache/dependencies/file.dependency.d.ts +32 -0
  78. package/cache/dependencies/file.dependency.js +34 -0
  79. package/cache/dependencies/tag.dependency.d.ts +36 -0
  80. package/cache/dependencies/tag.dependency.js +36 -0
  81. package/cache/dependencies/time.dependency.d.ts +43 -0
  82. package/cache/dependencies/time.dependency.js +43 -0
  83. package/cache/examples/basic-usage.d.ts +15 -0
  84. package/cache/examples/basic-usage.js +62 -8
  85. package/cache/index.js +9 -0
  86. package/cache/interfaces/cache-dependency.interface.d.ts +53 -0
  87. package/cache/interfaces/cache-options.interface.d.ts +81 -0
  88. package/cache/interfaces/cache-options.interface.js +6 -0
  89. package/cache/interfaces/cache-provider.interface.d.ts +78 -0
  90. package/cache/providers/base-cache.provider.d.ts +14 -0
  91. package/cache/providers/base-cache.provider.js +16 -0
  92. package/cache/providers/cls-cache.provider.d.ts +20 -0
  93. package/cache/providers/cls-cache.provider.js +28 -0
  94. package/cache/providers/memory-cache.provider.d.ts +23 -0
  95. package/cache/providers/memory-cache.provider.js +26 -0
  96. package/cache/providers/redis-cache.provider.d.ts +26 -0
  97. package/cache/providers/redis-cache.provider.js +29 -0
  98. package/cache/utils/dependency-manager.util.d.ts +52 -0
  99. package/cache/utils/dependency-manager.util.js +59 -0
  100. package/cache/utils/key-generator.util.d.ts +42 -0
  101. package/cache/utils/key-generator.util.js +53 -1
  102. package/common/abstract.entity.d.ts +14 -0
  103. package/common/abstract.entity.js +14 -0
  104. package/common/boilerplate.polyfill.d.ts +142 -0
  105. package/common/boilerplate.polyfill.js +17 -0
  106. package/common/dto/dto-container.d.ts +16 -0
  107. package/common/dto/dto-container.js +20 -0
  108. package/common/dto/dto-decorators.d.ts +18 -0
  109. package/common/dto/dto-decorators.js +14 -0
  110. package/common/dto/dto-extensions.d.ts +11 -0
  111. package/common/dto/dto-extensions.js +9 -0
  112. package/common/dto/dto-service-accessor.d.ts +17 -0
  113. package/common/dto/dto-service-accessor.js +18 -0
  114. package/common/dto/dto-transformer.d.ts +12 -0
  115. package/common/dto/dto-transformer.js +9 -0
  116. package/common/dto/index.js +2 -0
  117. package/common/examples/paginate-and-map.example.d.ts +6 -0
  118. package/common/examples/paginate-and-map.example.js +26 -0
  119. package/common/utils.d.ts +15 -0
  120. package/common/utils.js +15 -0
  121. package/constants/language-code.js +1 -0
  122. package/decorators/field.decorators.js +8 -1
  123. package/decorators/property.decorators.js +1 -0
  124. package/decorators/public-route.decorator.js +1 -0
  125. package/decorators/transform.decorators.d.ts +27 -0
  126. package/decorators/transform.decorators.js +29 -0
  127. package/decorators/translate.decorator.js +1 -0
  128. package/decorators/user.decorator.js +1 -0
  129. package/decorators/validator.decorators.d.ts +8 -18
  130. package/decorators/validator.decorators.js +22 -190
  131. package/filters/constraint-errors.js +1 -0
  132. package/helpers/common.helper.d.ts +13 -0
  133. package/helpers/common.helper.js +13 -0
  134. package/http-client/config/http-client.config.d.ts +15 -0
  135. package/http-client/config/http-client.config.js +25 -9
  136. package/http-client/decorators/http-client.decorators.d.ts +63 -0
  137. package/http-client/decorators/http-client.decorators.js +71 -3
  138. package/http-client/entities/http-log.entity.d.ts +229 -0
  139. package/http-client/entities/http-log.entity.js +6 -1
  140. package/http-client/errors/http-client.errors.d.ts +57 -0
  141. package/http-client/errors/http-client.errors.js +58 -0
  142. package/http-client/examples/advanced-usage.example.d.ts +41 -0
  143. package/http-client/examples/advanced-usage.example.js +68 -24
  144. package/http-client/examples/auth-with-waiting-lock.example.d.ts +31 -0
  145. package/http-client/examples/auth-with-waiting-lock.example.js +52 -5
  146. package/http-client/examples/basic-usage.example.d.ts +60 -0
  147. package/http-client/examples/basic-usage.example.js +60 -0
  148. package/http-client/examples/multi-api-configuration.example.d.ts +60 -0
  149. package/http-client/examples/multi-api-configuration.example.js +76 -5
  150. package/http-client/http-client.module.d.ts +13 -0
  151. package/http-client/http-client.module.js +19 -0
  152. package/http-client/index.js +8 -0
  153. package/http-client/interfaces/api-client-config.interface.d.ts +125 -0
  154. package/http-client/interfaces/api-client-config.interface.js +3 -0
  155. package/http-client/interfaces/http-client-config.interface.d.ts +60 -0
  156. package/http-client/services/api-client-registry.service.d.ts +57 -0
  157. package/http-client/services/api-client-registry.service.js +84 -1
  158. package/http-client/services/cache.service.d.ts +52 -0
  159. package/http-client/services/cache.service.js +72 -3
  160. package/http-client/services/circuit-breaker.service.d.ts +46 -0
  161. package/http-client/services/circuit-breaker.service.js +52 -0
  162. package/http-client/services/http-client.service.d.ts +67 -0
  163. package/http-client/services/http-client.service.js +105 -4
  164. package/http-client/services/http-log-query.service.d.ts +83 -0
  165. package/http-client/services/http-log-query.service.js +122 -1
  166. package/http-client/services/http-replay.service.d.ts +101 -0
  167. package/http-client/services/http-replay.service.js +86 -0
  168. package/http-client/services/log-cleanup.service.d.ts +63 -0
  169. package/http-client/services/log-cleanup.service.js +54 -2
  170. package/http-client/services/logging.service.d.ts +40 -0
  171. package/http-client/services/logging.service.js +53 -0
  172. package/http-client/utils/call-stack-extractor.util.d.ts +37 -0
  173. package/http-client/utils/call-stack-extractor.util.js +48 -0
  174. package/http-client/utils/context-extractor.util.d.ts +49 -0
  175. package/http-client/utils/context-extractor.util.js +52 -0
  176. package/http-client/utils/curl-generator.util.d.ts +21 -0
  177. package/http-client/utils/curl-generator.util.js +44 -3
  178. package/http-client/utils/request-id.util.d.ts +18 -0
  179. package/http-client/utils/request-id.util.js +20 -0
  180. package/http-client/utils/retry-recorder.util.d.ts +42 -0
  181. package/http-client/utils/retry-recorder.util.js +44 -0
  182. package/index.js +8 -0
  183. package/interceptors/translation-interceptor.service.js +5 -0
  184. package/package.json +1 -1
  185. package/providers/context.provider.js +2 -0
  186. package/providers/generator.provider.d.ts +4 -0
  187. package/providers/generator.provider.js +4 -0
  188. package/redis-lock/examples/lock-strategy.examples.d.ts +89 -0
  189. package/redis-lock/examples/lock-strategy.examples.js +130 -15
  190. package/redis-lock/index.js +3 -0
  191. package/redis-lock/redis-lock.decorator.d.ts +101 -0
  192. package/redis-lock/redis-lock.decorator.js +120 -0
  193. package/redis-lock/redis-lock.module.d.ts +60 -0
  194. package/redis-lock/redis-lock.module.js +46 -0
  195. package/redis-lock/redis-lock.service.d.ts +251 -0
  196. package/redis-lock/redis-lock.service.js +219 -3
  197. package/setup/bootstrap.setup.js +20 -0
  198. package/setup/mode.setup.d.ts +44 -0
  199. package/setup/mode.setup.js +44 -0
  200. package/setup/schedule.decorator.d.ts +226 -0
  201. package/setup/schedule.decorator.js +214 -1
  202. package/setup/worker.decorator.d.ts +86 -0
  203. package/setup/worker.decorator.js +88 -0
  204. package/shared/serviceRegistryModule.js +5 -1
  205. package/shared/services/api-config.service.d.ts +3 -0
  206. package/shared/services/api-config.service.js +20 -9
  207. package/validator-json/decorators.d.ts +17 -0
  208. package/validator-json/decorators.js +17 -2
  209. package/validator-json/default.d.ts +6 -0
  210. package/validator-json/default.js +30 -2
  211. package/validator-json/defaultConverters.js +1 -0
  212. package/validator-json/options.d.ts +23 -0
  213. package/validators/common-validators.d.ts +143 -0
  214. package/validators/common-validators.js +249 -0
  215. package/validators/custom-validate.examples.d.ts +23 -0
  216. package/validators/custom-validate.examples.js +78 -6
  217. package/validators/custom-validate.validator.d.ts +107 -0
  218. package/validators/custom-validate.validator.js +84 -0
  219. package/validators/index.d.ts +1 -0
  220. package/validators/index.js +1 -0
  221. package/validators/is-exists.validator.d.ts +11 -0
  222. package/validators/is-exists.validator.js +22 -0
  223. package/validators/is-unique.validator.d.ts +11 -0
  224. package/validators/is-unique.validator.js +31 -3
  225. package/validators/skip-empty.validator.d.ts +5 -0
  226. package/validators/skip-empty.validator.js +5 -0
  227. package/vault/interfaces/vault-options.interface.d.ts +9 -0
  228. package/vault/vault-config.loader.d.ts +30 -0
  229. package/vault/vault-config.loader.js +48 -1
  230. package/vault/vault-config.service.d.ts +53 -0
  231. package/vault/vault-config.service.js +57 -0
  232. package/vault/vault.module.d.ts +4 -0
  233. package/vault/vault.module.js +4 -0
  234. package/decorators/examples/validation-decorators.example.d.ts +0 -69
  235. 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)({
@@ -5,3 +5,4 @@ export * from './is-exists.validator';
5
5
  export * from './is-unique.validator';
6
6
  export * from './same-as.validator';
7
7
  export * from './custom-validate.validator';
8
+ export * from './common-validators';
@@ -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
- const isNew = pkCols.some((pk) => args.object[pk]);
79
- if (!isNew) {
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.map((pk) => {
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
  }