@nest-omni/core 4.1.3-1 → 4.1.3-10

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 (242) 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 -4
  105. package/common/boilerplate.polyfill.js +24 -100
  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/i18n/en_US/validation.json +2 -1
  183. package/i18n/zh_CN/validation.json +2 -1
  184. package/index.js +8 -0
  185. package/interceptors/translation-interceptor.service.js +5 -0
  186. package/package.json +1 -1
  187. package/providers/context.provider.js +2 -0
  188. package/providers/generator.provider.d.ts +4 -0
  189. package/providers/generator.provider.js +4 -0
  190. package/redis-lock/comprehensive-lock-cleanup.service.d.ts +94 -0
  191. package/redis-lock/comprehensive-lock-cleanup.service.js +253 -0
  192. package/redis-lock/examples/lock-strategy.examples.d.ts +89 -0
  193. package/redis-lock/examples/lock-strategy.examples.js +130 -15
  194. package/redis-lock/index.d.ts +2 -0
  195. package/redis-lock/index.js +8 -1
  196. package/redis-lock/lock-heartbeat.service.d.ts +78 -0
  197. package/redis-lock/lock-heartbeat.service.js +222 -0
  198. package/redis-lock/redis-lock.decorator.d.ts +101 -0
  199. package/redis-lock/redis-lock.decorator.js +120 -0
  200. package/redis-lock/redis-lock.module.d.ts +66 -0
  201. package/redis-lock/redis-lock.module.js +175 -70
  202. package/redis-lock/redis-lock.service.d.ts +260 -0
  203. package/redis-lock/redis-lock.service.js +244 -4
  204. package/setup/bootstrap.setup.js +20 -0
  205. package/setup/mode.setup.d.ts +44 -0
  206. package/setup/mode.setup.js +44 -0
  207. package/setup/schedule.decorator.d.ts +227 -0
  208. package/setup/schedule.decorator.js +219 -6
  209. package/setup/worker.decorator.d.ts +86 -0
  210. package/setup/worker.decorator.js +88 -0
  211. package/shared/serviceRegistryModule.js +9 -1
  212. package/shared/services/api-config.service.d.ts +3 -0
  213. package/shared/services/api-config.service.js +20 -9
  214. package/validator-json/decorators.d.ts +17 -0
  215. package/validator-json/decorators.js +17 -2
  216. package/validator-json/default.d.ts +6 -0
  217. package/validator-json/default.js +30 -2
  218. package/validator-json/defaultConverters.js +1 -0
  219. package/validator-json/options.d.ts +23 -0
  220. package/validators/common-validators.d.ts +143 -0
  221. package/validators/common-validators.js +249 -0
  222. package/validators/custom-validate.examples.d.ts +96 -0
  223. package/validators/custom-validate.examples.js +400 -0
  224. package/validators/custom-validate.validator.d.ts +134 -0
  225. package/validators/custom-validate.validator.js +214 -0
  226. package/validators/index.d.ts +2 -0
  227. package/validators/index.js +2 -0
  228. package/validators/is-exists.validator.d.ts +18 -4
  229. package/validators/is-exists.validator.js +67 -6
  230. package/validators/is-unique.validator.d.ts +32 -5
  231. package/validators/is-unique.validator.js +99 -17
  232. package/validators/skip-empty.validator.d.ts +5 -0
  233. package/validators/skip-empty.validator.js +5 -0
  234. package/vault/interfaces/vault-options.interface.d.ts +9 -0
  235. package/vault/vault-config.loader.d.ts +30 -0
  236. package/vault/vault-config.loader.js +48 -1
  237. package/vault/vault-config.service.d.ts +53 -0
  238. package/vault/vault-config.service.js +57 -0
  239. package/vault/vault.module.d.ts +4 -0
  240. package/vault/vault.module.js +4 -0
  241. package/decorators/examples/validation-decorators.example.d.ts +0 -69
  242. package/decorators/examples/validation-decorators.example.js +0 -331
@@ -21,39 +21,93 @@ var RedisLockService_1;
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
22
  exports.RedisLockService = exports.LockStrategy = void 0;
23
23
  const common_1 = require("@nestjs/common");
24
+ /**
25
+ * Lock acquisition strategy
26
+ */
24
27
  var LockStrategy;
25
28
  (function (LockStrategy) {
29
+ /**
30
+ * Skip execution if lock cannot be acquired immediately
31
+ * This is the default behavior for backward compatibility
32
+ */
26
33
  LockStrategy["SKIP"] = "SKIP";
34
+ /**
35
+ * Throw an error if lock cannot be acquired
36
+ * Useful for critical operations that must have exclusive access
37
+ */
27
38
  LockStrategy["THROW"] = "THROW";
39
+ /**
40
+ * Wait/block until the lock can be acquired
41
+ * Will retry indefinitely with the specified retry delay
42
+ */
28
43
  LockStrategy["WAIT"] = "WAIT";
29
44
  })(LockStrategy || (exports.LockStrategy = LockStrategy = {}));
45
+ /**
46
+ * Redis-based distributed lock service
47
+ *
48
+ * Provides thread-safe, distributed locking mechanism using Redis.
49
+ * Supports automatic lock expiration, retries, proper lock release,
50
+ * and automatic lock extension.
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * constructor(private lockService: RedisLockService) {}
55
+ *
56
+ * async processTask() {
57
+ * const result = await this.lockService.acquireLock('task:process', { ttl: 60000 });
58
+ *
59
+ * if (result.acquired) {
60
+ * try {
61
+ * // Do work
62
+ * } finally {
63
+ * await this.lockService.releaseLock('task:process', result.lockValue);
64
+ * }
65
+ * }
66
+ * }
67
+ * ```
68
+ */
30
69
  let RedisLockService = RedisLockService_1 = class RedisLockService {
31
70
  constructor() {
32
71
  this.logger = new common_1.Logger(RedisLockService_1.name);
33
72
  this.redis = null;
34
73
  this.defaultOptions = {
35
- ttl: 300000,
74
+ ttl: 300000, // 5 minutes
36
75
  retryCount: 0,
37
76
  retryDelay: 100,
38
77
  keyPrefix: 'lock',
39
78
  throwOnFailure: false,
40
79
  strategy: LockStrategy.SKIP,
41
80
  waitTimeout: undefined,
42
- autoExtend: 0,
81
+ autoExtend: 0, // No auto-extension by default
43
82
  };
83
+ // Set global instance when created
44
84
  if (!RedisLockService_1.globalInstance) {
45
85
  RedisLockService_1.globalInstance = this;
46
86
  }
87
+ // Initialize instance ID
88
+ this.instanceId = this.getInstanceId();
47
89
  }
90
+ /**
91
+ * Get the global singleton instance
92
+ * This allows decorators to access the service without dependency injection
93
+ */
48
94
  static getGlobalInstance() {
49
95
  return RedisLockService_1.globalInstance;
50
96
  }
97
+ /**
98
+ * Get or create the global singleton instance
99
+ * If no instance exists, it will create one
100
+ */
51
101
  static getOrCreateGlobalInstance() {
52
102
  if (!RedisLockService_1.globalInstance) {
53
103
  RedisLockService_1.globalInstance = new RedisLockService_1();
54
104
  }
55
105
  return RedisLockService_1.globalInstance;
56
106
  }
107
+ /**
108
+ * Set the global singleton instance
109
+ * Useful for testing or manual setup
110
+ */
57
111
  static setGlobalInstance(instance) {
58
112
  RedisLockService_1.globalInstance = instance;
59
113
  }
@@ -69,37 +123,64 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
69
123
  }
70
124
  onModuleDestroy() {
71
125
  return __awaiter(this, void 0, void 0, function* () {
126
+ // We don't manage the Redis connection lifecycle anymore
127
+ // The injected Redis client is managed by the Redis module
72
128
  this.logger.log('RedisLockService destroyed');
73
129
  });
74
130
  }
131
+ /**
132
+ * Set Redis client (required for dependency injection)
133
+ * This service requires an external Redis client to function
134
+ */
75
135
  setRedisClient(redis) {
76
136
  this.redis = redis;
77
137
  this.logger.log('Redis client set for RedisLockService');
78
138
  }
139
+ /**
140
+ * Set default TTL for locks
141
+ */
79
142
  setDefaultTtl(ttl) {
80
143
  this.defaultOptions.ttl = ttl;
81
144
  }
145
+ /**
146
+ * Set default key prefix for locks
147
+ */
82
148
  setDefaultKeyPrefix(prefix) {
83
149
  this.defaultOptions.keyPrefix = prefix;
84
150
  }
151
+ /**
152
+ * Set default retry count for lock acquisition
153
+ */
85
154
  setDefaultRetryCount(count) {
86
155
  this.defaultOptions.retryCount = count;
87
156
  }
157
+ /**
158
+ * Set default retry delay for lock acquisition
159
+ */
88
160
  setDefaultRetryDelay(delay) {
89
161
  this.defaultOptions.retryDelay = delay;
90
162
  }
163
+ /**
164
+ * Acquire a distributed lock
165
+ *
166
+ * @param key - Lock key (will be prefixed with 'lock:')
167
+ * @param options - Lock options
168
+ * @returns Lock acquisition result
169
+ */
91
170
  acquireLock(key_1) {
92
171
  return __awaiter(this, arguments, void 0, function* (key, options = {}) {
93
172
  const redis = yield this.getRedis();
94
173
  const opts = Object.assign(Object.assign({}, this.defaultOptions), options);
174
+ // Handle backward compatibility: if throwOnFailure is true, use THROW strategy
95
175
  if (opts.throwOnFailure && !options.strategy) {
96
176
  opts.strategy = LockStrategy.THROW;
97
177
  }
98
178
  const lockKey = this.buildLockKey(key, opts.keyPrefix);
99
179
  const lockValue = this.generateLockValue();
180
+ // Determine max attempts based on strategy
100
181
  let maxAttempts;
101
182
  if (opts.strategy === LockStrategy.WAIT) {
102
- maxAttempts = Number.MAX_SAFE_INTEGER;
183
+ maxAttempts = Number.MAX_SAFE_INTEGER; // Infinite retries for WAIT strategy
103
184
  }
104
185
  else {
105
186
  maxAttempts = opts.retryCount + 1;
@@ -107,6 +188,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
107
188
  let attempts = 0;
108
189
  const startTime = Date.now();
109
190
  while (attempts < maxAttempts) {
191
+ // Check timeout for WAIT strategy
110
192
  if (opts.strategy === LockStrategy.WAIT && opts.waitTimeout) {
111
193
  const elapsed = Date.now() - startTime;
112
194
  if (elapsed >= opts.waitTimeout) {
@@ -116,9 +198,11 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
116
198
  }
117
199
  }
118
200
  try {
201
+ // Use SET with NX (Not eXists) and PX (expiration in milliseconds)
119
202
  const result = yield redis.set(lockKey, lockValue, 'PX', opts.ttl, 'NX');
120
203
  if (result === 'OK') {
121
204
  this.logger.debug(`Lock acquired: ${lockKey} (value: ${lockValue}, ttl: ${opts.ttl}ms, attempts: ${attempts + 1})`);
205
+ // Set up auto-extension if enabled
122
206
  let autoExtendTimer;
123
207
  if (opts.autoExtend && opts.autoExtend > 0) {
124
208
  autoExtendTimer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
@@ -132,7 +216,9 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
132
216
  }
133
217
  return { acquired: true, lockValue, autoExtendTimer };
134
218
  }
219
+ // Lock acquisition failed
135
220
  attempts++;
221
+ // For WAIT strategy, log less frequently to avoid spam
136
222
  if (opts.strategy === LockStrategy.WAIT) {
137
223
  if (attempts === 1 || attempts % 10 === 0) {
138
224
  this.logger.debug(`Waiting for lock ${lockKey}... (attempt ${attempts})`);
@@ -141,6 +227,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
141
227
  else if (attempts < maxAttempts) {
142
228
  this.logger.debug(`Lock acquisition failed for ${lockKey}, retrying... (${attempts}/${opts.retryCount})`);
143
229
  }
230
+ // Wait before next attempt (except for last attempt)
144
231
  if (attempts < maxAttempts) {
145
232
  yield this.sleep(opts.retryDelay);
146
233
  }
@@ -154,6 +241,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
154
241
  return { acquired: false, error: errorMessage };
155
242
  }
156
243
  }
244
+ // Max attempts reached
157
245
  const failureMessage = `Failed to acquire lock for ${lockKey} after ${attempts} attempts`;
158
246
  this.logger.warn(failureMessage);
159
247
  if (opts.strategy === LockStrategy.THROW) {
@@ -162,11 +250,23 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
162
250
  return { acquired: false, error: failureMessage };
163
251
  });
164
252
  }
253
+ /**
254
+ * Release a distributed lock
255
+ *
256
+ * Uses Lua script to ensure atomic check-and-delete operation
257
+ * Only releases the lock if the value matches (prevents releasing someone else's lock)
258
+ *
259
+ * @param key - Lock key
260
+ * @param lockValue - Lock value obtained during acquisition
261
+ * @param keyPrefix - Key prefix (must match acquisition)
262
+ * @returns True if lock was released, false otherwise
263
+ */
165
264
  releaseLock(key_1, lockValue_1) {
166
265
  return __awaiter(this, arguments, void 0, function* (key, lockValue, keyPrefix = 'lock') {
167
266
  const redis = yield this.getRedis();
168
267
  const lockKey = this.buildLockKey(key, keyPrefix);
169
268
  try {
269
+ // Lua script to atomically check and delete the lock
170
270
  const script = `
171
271
  if redis.call("get", KEYS[1]) == ARGV[1] then
172
272
  return redis.call("del", KEYS[1])
@@ -190,11 +290,21 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
190
290
  }
191
291
  });
192
292
  }
293
+ /**
294
+ * Extend the expiration time of an existing lock
295
+ *
296
+ * @param key - Lock key
297
+ * @param lockValue - Lock value obtained during acquisition
298
+ * @param ttl - New TTL in milliseconds
299
+ * @param keyPrefix - Key prefix (must match acquisition)
300
+ * @returns True if lock was extended, false otherwise
301
+ */
193
302
  extendLock(key_1, lockValue_1, ttl_1) {
194
303
  return __awaiter(this, arguments, void 0, function* (key, lockValue, ttl, keyPrefix = 'lock') {
195
304
  const redis = yield this.getRedis();
196
305
  const lockKey = this.buildLockKey(key, keyPrefix);
197
306
  try {
307
+ // Lua script to atomically check value and extend TTL
198
308
  const script = `
199
309
  if redis.call("get", KEYS[1]) == ARGV[1] then
200
310
  return redis.call("pexpire", KEYS[1], ARGV[2])
@@ -218,6 +328,13 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
218
328
  }
219
329
  });
220
330
  }
331
+ /**
332
+ * Check if a lock exists
333
+ *
334
+ * @param key - Lock key
335
+ * @param keyPrefix - Key prefix
336
+ * @returns True if lock exists, false otherwise
337
+ */
221
338
  isLocked(key_1) {
222
339
  return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
223
340
  const redis = yield this.getRedis();
@@ -232,6 +349,14 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
232
349
  }
233
350
  });
234
351
  }
352
+ /**
353
+ * Execute a function with automatic lock acquisition and release
354
+ *
355
+ * @param key - Lock key
356
+ * @param fn - Function to execute while holding the lock
357
+ * @param options - Lock options
358
+ * @returns Result of the function execution, or null if lock couldn't be acquired
359
+ */
235
360
  withLock(key_1, fn_1) {
236
361
  return __awaiter(this, arguments, void 0, function* (key, fn, options = {}) {
237
362
  const lockResult = yield this.acquireLock(key, options);
@@ -247,6 +372,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
247
372
  throw error;
248
373
  }
249
374
  finally {
375
+ // Clear auto-extension timer if it exists
250
376
  if (lockResult.autoExtendTimer) {
251
377
  clearInterval(lockResult.autoExtendTimer);
252
378
  }
@@ -254,6 +380,13 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
254
380
  }
255
381
  });
256
382
  }
383
+ /**
384
+ * Get lock information from Redis
385
+ *
386
+ * @param key - Lock key
387
+ * @param keyPrefix - Key prefix
388
+ * @returns Lock information including TTL and value
389
+ */
257
390
  getLockInfo(key_1) {
258
391
  return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
259
392
  const redis = yield this.getRedis();
@@ -274,6 +407,13 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
274
407
  }
275
408
  });
276
409
  }
410
+ /**
411
+ * Force release a lock (use with caution)
412
+ *
413
+ * @param key - Lock key
414
+ * @param keyPrefix - Key prefix
415
+ * @returns True if lock was released, false otherwise
416
+ */
277
417
  forceRelease(key_1) {
278
418
  return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
279
419
  const redis = yield this.getRedis();
@@ -295,6 +435,25 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
295
435
  }
296
436
  });
297
437
  }
438
+ /**
439
+ * Clean up locks by pattern
440
+ * Useful for cleaning up locks after process restart or for specific services
441
+ *
442
+ * WARNING: Use with caution in production! This will forcefully delete locks.
443
+ *
444
+ * @param pattern - Lock pattern (e.g., 'MyService:*' or '*:migration:*')
445
+ * @param keyPrefix - Key prefix (default: 'lock')
446
+ * @returns Number of locks deleted
447
+ *
448
+ * @example
449
+ * ```typescript
450
+ * // Clean up all locks for MyService
451
+ * await lockService.cleanupLocksByPattern('MyService:*');
452
+ *
453
+ * // Clean up all migration locks
454
+ * await lockService.cleanupLocksByPattern('*:migration:*');
455
+ * ```
456
+ */
298
457
  cleanupLocksByPattern(pattern_1) {
299
458
  return __awaiter(this, arguments, void 0, function* (pattern, keyPrefix = 'lock') {
300
459
  const redis = yield this.getRedis();
@@ -315,6 +474,28 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
315
474
  }
316
475
  });
317
476
  }
477
+ /**
478
+ * Clean up locks on startup
479
+ * This method is useful for cleaning up stale locks from previous process instances
480
+ *
481
+ * WARNING: Only use this if you're sure the locks are from previous process instances!
482
+ *
483
+ * @param patterns - Array of lock patterns to clean up
484
+ * @param keyPrefix - Key prefix (default: 'lock')
485
+ * @returns Total number of locks deleted
486
+ *
487
+ * @example
488
+ * ```typescript
489
+ * // In your module's onModuleInit
490
+ * async onModuleInit() {
491
+ * // Clean up locks from this service that might be left from previous restart
492
+ * await this.lockService.cleanupOnStartup([
493
+ * 'MyService:*',
494
+ * 'AnotherService:*'
495
+ * ]);
496
+ * }
497
+ * ```
498
+ */
318
499
  cleanupOnStartup(patterns_1) {
319
500
  return __awaiter(this, arguments, void 0, function* (patterns, keyPrefix = 'lock') {
320
501
  this.logger.log(`Starting lock cleanup for ${patterns.length} pattern(s) on startup...`);
@@ -327,10 +508,17 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
327
508
  return totalDeleted;
328
509
  });
329
510
  }
511
+ /**
512
+ * Health check for Redis connection
513
+ * Returns information about Redis connectivity and lock service status
514
+ *
515
+ * @returns Health check result
516
+ */
330
517
  healthCheck() {
331
518
  return __awaiter(this, void 0, void 0, function* () {
332
519
  try {
333
520
  const redis = yield this.getRedis();
521
+ // Try to ping Redis
334
522
  const pong = yield redis.ping();
335
523
  if (pong === 'PONG') {
336
524
  return {
@@ -356,6 +544,14 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
356
544
  }
357
545
  });
358
546
  }
547
+ /**
548
+ * Get all active locks with optional pattern filtering
549
+ * Useful for monitoring and debugging
550
+ *
551
+ * @param pattern - Optional pattern to filter locks (e.g., 'MyService:*')
552
+ * @param keyPrefix - Key prefix (default: 'lock')
553
+ * @returns Array of active lock information
554
+ */
359
555
  getActiveLocks() {
360
556
  return __awaiter(this, arguments, void 0, function* (pattern = '*', keyPrefix = 'lock') {
361
557
  const redis = yield this.getRedis();
@@ -370,6 +566,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
370
566
  redis.get(key),
371
567
  redis.pttl(key),
372
568
  ]);
569
+ // Remove the key prefix for cleaner output
373
570
  const cleanKey = key.startsWith(`${keyPrefix}:`)
374
571
  ? key.substring(`${keyPrefix}:`.length)
375
572
  : key;
@@ -387,6 +584,10 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
387
584
  }
388
585
  });
389
586
  }
587
+ /**
588
+ * Get Redis connection
589
+ * Requires external Redis client to be set
590
+ */
390
591
  getRedis() {
391
592
  return __awaiter(this, void 0, void 0, function* () {
392
593
  if (!this.redis) {
@@ -395,12 +596,51 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
395
596
  return this.redis;
396
597
  });
397
598
  }
599
+ /**
600
+ * Generate a unique lock value
601
+ * Format: instanceId:timestamp:random:pid
602
+ *
603
+ * @returns Unique lock identifier
604
+ */
398
605
  generateLockValue() {
399
- return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}-${process.pid}`;
606
+ const timestamp = Date.now();
607
+ const random = Math.random().toString(36).substring(2, 15);
608
+ const pid = process.pid;
609
+ return `${this.instanceId}:${timestamp}:${random}:${pid}`;
400
610
  }
611
+ /**
612
+ * Get instance identifier
613
+ * Used to distinguish different process instances in distributed environments
614
+ *
615
+ * @returns Instance identifier
616
+ */
617
+ getInstanceId() {
618
+ // 1. Kubernetes Pod name
619
+ if (process.env.HOSTNAME) {
620
+ return process.env.HOSTNAME;
621
+ }
622
+ // 2. Custom instance ID
623
+ if (process.env.INSTANCE_ID) {
624
+ return process.env.INSTANCE_ID;
625
+ }
626
+ // 3. Generate unique ID
627
+ return `instance-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
628
+ }
629
+ /**
630
+ * Build the full Redis key for a lock
631
+ *
632
+ * @param key - Lock key
633
+ * @param prefix - Key prefix
634
+ * @returns Full Redis key
635
+ */
401
636
  buildLockKey(key, prefix = 'lock') {
402
637
  return `${prefix}:${key}`;
403
638
  }
639
+ /**
640
+ * Sleep for a specified duration
641
+ *
642
+ * @param ms - Milliseconds to sleep
643
+ */
404
644
  sleep(ms) {
405
645
  return new Promise((resolve) => setTimeout(resolve, ms));
406
646
  }
@@ -19,12 +19,15 @@ const process = require("process");
19
19
  const mode_setup_1 = require("./mode.setup");
20
20
  function findValidRootPath() {
21
21
  const getAppRootPath = () => {
22
+ // 优先使用 require.main.filename(应用入口文件)
22
23
  if (require.main && require.main.filename) {
23
24
  return (0, path_1.dirname)(require.main.filename);
24
25
  }
26
+ // fallback 到 process.argv[1]
25
27
  if (process.argv[1]) {
26
28
  return (0, path_1.dirname)(process.argv[1]);
27
29
  }
30
+ // 最后 fallback 到当前工作目录
28
31
  return process.cwd();
29
32
  };
30
33
  const possibleRootPaths = [getAppRootPath(), process.cwd(), __dirname];
@@ -56,6 +59,8 @@ function findValidRootPath() {
56
59
  throw new Error(`No valid .env file: ${envFilePath}`);
57
60
  }
58
61
  const { envFilePath, rootPath, baseEnvFilePath } = findValidRootPath();
62
+ // 配置加载顺序: base.env < 环境.env < Vault
63
+ // 1. 先加载本地配置文件 (base.env 和 环境.env)
59
64
  dotenv.config({ path: [envFilePath, baseEnvFilePath] });
60
65
  process.env.ROOT_PATH = rootPath;
61
66
  process.env.ENV_FILE_PATH = envFilePath;
@@ -121,34 +126,47 @@ const vault_1 = require("../vault");
121
126
  const dto_1 = require("../common/dto");
122
127
  function bootstrapSetup(AppModule, SetupSwagger) {
123
128
  return __awaiter(this, void 0, void 0, function* () {
129
+ // 2. 加载 Vault 配置(会覆盖 .env 中的配置)
124
130
  yield vault_1.VaultConfigLoader.loadVaultConfig();
131
+ // 获取应用模式
125
132
  const shouldStartHttp = (0, mode_setup_1.shouldStartHttpServer)();
133
+ // 创建应用实例
126
134
  const app = yield core_1.NestFactory.create(AppModule, {
127
135
  bufferLogs: true,
128
136
  autoFlushLogs: true,
129
137
  });
138
+ // 设置容器 - 类似class-validator的useContainer
130
139
  const appModuleRef = app.select(AppModule);
131
140
  (0, class_validator_1.useContainer)(appModuleRef, { fallbackOnErrors: true });
141
+ // 初始化DTO容器
132
142
  dto_1.DtoContainer.useContainer(appModuleRef);
143
+ // 获取核心服务
133
144
  const configService = app.select(__1.ServiceRegistryModule).get(__1.ApiConfigService);
134
145
  const logger = app.get(nestjs_pino_1.Logger);
135
146
  app.useLogger(logger);
136
147
  app.flushLogs();
148
+ // 记录应用模式
137
149
  logger.log(`Application Mode: ${(0, mode_setup_1.getModeDescription)()}`);
138
150
  logger.log(`Environment: ${process.env.NODE_ENV || 'unknown'}`);
139
151
  app.enableShutdownHooks();
152
+ // 基础配置
140
153
  app.enableVersioning();
141
154
  app.enable('trust proxy');
142
155
  app.set('query parser', 'extended');
156
+ // 中间件配置
143
157
  app.use(bodyParse.urlencoded({
144
158
  extended: true,
145
159
  parameterLimit: 1000,
146
160
  }), bodyParse.json({ limit: '50mb' }), new nestjs_cls_1.ClsMiddleware({
147
161
  saveReq: true,
162
+ // 启用请求保存,解决CLS相关的上下文问题
148
163
  }).use, (0, __1.RequestIdMiddleware)(), (0, __1.PowerByMiddleware)(), (0, __1.OmniAuthMiddleware)(), compression());
164
+ // 全局过滤器
149
165
  const reflector = app.get(core_1.Reflector);
150
166
  app.useGlobalFilters(new setup_1.SentryGlobalFilter(), new __1.HttpExceptionFilter(), new __1.QueryFailedFilter(reflector));
167
+ // 全局拦截器
151
168
  app.useGlobalInterceptors(new __1.LanguageInterceptor(), new __1.TranslationInterceptor(), new nestjs_pino_1.LoggerErrorInterceptor());
169
+ // 全局管道
152
170
  app.useGlobalPipes(new nestjs_i18n_1.I18nValidationPipe({
153
171
  whitelist: true,
154
172
  errorHttpStatusCode: common_1.HttpStatus.UNPROCESSABLE_ENTITY,
@@ -156,6 +174,7 @@ function bootstrapSetup(AppModule, SetupSwagger) {
156
174
  stopAtFirstError: true,
157
175
  validationError: { target: false, value: false },
158
176
  }));
177
+ // 可选功能模块 - 仅在 HTTP 或 Hybrid 模式下启用
159
178
  if (shouldStartHttp) {
160
179
  if (configService.documentationEnabled && SetupSwagger) {
161
180
  SetupSwagger(app, configService.documentationPath);
@@ -181,6 +200,7 @@ function bootstrapSetup(AppModule, SetupSwagger) {
181
200
  else {
182
201
  logger.log('Running in Worker-only mode - HTTP server not started');
183
202
  logger.log('Application is ready to process background tasks');
203
+ // 在 Worker 模式下,应用会持续运行但不监听 HTTP 请求
184
204
  yield app.init();
185
205
  }
186
206
  return app;
@@ -1,12 +1,56 @@
1
+ /**
2
+ * Application Mode Detection and Management System
3
+ *
4
+ * This module provides utilities for detecting and managing different application modes:
5
+ * - HTTP: Only HTTP server (no workers/schedulers)
6
+ * - WORKER: Only background workers and schedulers (no HTTP server)
7
+ * - HYBRID: Both HTTP server and workers (default)
8
+ */
1
9
  export declare enum ApplicationMode {
2
10
  HTTP = "http",
3
11
  WORKER = "worker",
4
12
  HYBRID = "hybrid"
5
13
  }
14
+ /**
15
+ * Get the current application mode from environment variables
16
+ * Supports both APP_MODE and MODE environment variables
17
+ *
18
+ * @returns The current application mode
19
+ */
6
20
  export declare function getApplicationMode(): ApplicationMode;
21
+ /**
22
+ * Check if the current mode should process queues and scheduled tasks
23
+ *
24
+ * @returns True if workers should be registered
25
+ */
7
26
  export declare function shouldProcessQueues(): boolean;
27
+ /**
28
+ * Check if the current mode should start HTTP server
29
+ *
30
+ * @returns True if HTTP server should be started
31
+ */
8
32
  export declare function shouldStartHttpServer(): boolean;
33
+ /**
34
+ * Check if running in HTTP-only mode
35
+ *
36
+ * @returns True if running in HTTP-only mode
37
+ */
9
38
  export declare function isHttpMode(): boolean;
39
+ /**
40
+ * Check if running in Worker-only mode
41
+ *
42
+ * @returns True if running in Worker-only mode
43
+ */
10
44
  export declare function isWorkerMode(): boolean;
45
+ /**
46
+ * Check if running in Hybrid mode
47
+ *
48
+ * @returns True if running in Hybrid mode
49
+ */
11
50
  export declare function isHybridMode(): boolean;
51
+ /**
52
+ * Get a human-readable description of the current mode
53
+ *
54
+ * @returns Description of the current mode
55
+ */
12
56
  export declare function getModeDescription(): string;
@@ -1,4 +1,12 @@
1
1
  "use strict";
2
+ /**
3
+ * Application Mode Detection and Management System
4
+ *
5
+ * This module provides utilities for detecting and managing different application modes:
6
+ * - HTTP: Only HTTP server (no workers/schedulers)
7
+ * - WORKER: Only background workers and schedulers (no HTTP server)
8
+ * - HYBRID: Both HTTP server and workers (default)
9
+ */
2
10
  Object.defineProperty(exports, "__esModule", { value: true });
3
11
  exports.ApplicationMode = void 0;
4
12
  exports.getApplicationMode = getApplicationMode;
@@ -14,6 +22,12 @@ var ApplicationMode;
14
22
  ApplicationMode["WORKER"] = "worker";
15
23
  ApplicationMode["HYBRID"] = "hybrid";
16
24
  })(ApplicationMode || (exports.ApplicationMode = ApplicationMode = {}));
25
+ /**
26
+ * Get the current application mode from environment variables
27
+ * Supports both APP_MODE and MODE environment variables
28
+ *
29
+ * @returns The current application mode
30
+ */
17
31
  function getApplicationMode() {
18
32
  const mode = (process.env.APP_MODE || process.env.MODE || 'hybrid')
19
33
  .toLowerCase()
@@ -28,23 +42,53 @@ function getApplicationMode() {
28
42
  return ApplicationMode.HYBRID;
29
43
  }
30
44
  }
45
+ /**
46
+ * Check if the current mode should process queues and scheduled tasks
47
+ *
48
+ * @returns True if workers should be registered
49
+ */
31
50
  function shouldProcessQueues() {
32
51
  const mode = getApplicationMode();
33
52
  return mode === ApplicationMode.WORKER || mode === ApplicationMode.HYBRID;
34
53
  }
54
+ /**
55
+ * Check if the current mode should start HTTP server
56
+ *
57
+ * @returns True if HTTP server should be started
58
+ */
35
59
  function shouldStartHttpServer() {
36
60
  const mode = getApplicationMode();
37
61
  return mode === ApplicationMode.HTTP || mode === ApplicationMode.HYBRID;
38
62
  }
63
+ /**
64
+ * Check if running in HTTP-only mode
65
+ *
66
+ * @returns True if running in HTTP-only mode
67
+ */
39
68
  function isHttpMode() {
40
69
  return getApplicationMode() === ApplicationMode.HTTP;
41
70
  }
71
+ /**
72
+ * Check if running in Worker-only mode
73
+ *
74
+ * @returns True if running in Worker-only mode
75
+ */
42
76
  function isWorkerMode() {
43
77
  return getApplicationMode() === ApplicationMode.WORKER;
44
78
  }
79
+ /**
80
+ * Check if running in Hybrid mode
81
+ *
82
+ * @returns True if running in Hybrid mode
83
+ */
45
84
  function isHybridMode() {
46
85
  return getApplicationMode() === ApplicationMode.HYBRID;
47
86
  }
87
+ /**
88
+ * Get a human-readable description of the current mode
89
+ *
90
+ * @returns Description of the current mode
91
+ */
48
92
  function getModeDescription() {
49
93
  const mode = getApplicationMode();
50
94
  switch (mode) {