@nest-omni/core 4.1.3-2 → 4.1.3-3

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 +18 -0
  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
@@ -21,39 +21,91 @@ 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
  }
47
87
  }
88
+ /**
89
+ * Get the global singleton instance
90
+ * This allows decorators to access the service without dependency injection
91
+ */
48
92
  static getGlobalInstance() {
49
93
  return RedisLockService_1.globalInstance;
50
94
  }
95
+ /**
96
+ * Get or create the global singleton instance
97
+ * If no instance exists, it will create one
98
+ */
51
99
  static getOrCreateGlobalInstance() {
52
100
  if (!RedisLockService_1.globalInstance) {
53
101
  RedisLockService_1.globalInstance = new RedisLockService_1();
54
102
  }
55
103
  return RedisLockService_1.globalInstance;
56
104
  }
105
+ /**
106
+ * Set the global singleton instance
107
+ * Useful for testing or manual setup
108
+ */
57
109
  static setGlobalInstance(instance) {
58
110
  RedisLockService_1.globalInstance = instance;
59
111
  }
@@ -69,37 +121,64 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
69
121
  }
70
122
  onModuleDestroy() {
71
123
  return __awaiter(this, void 0, void 0, function* () {
124
+ // We don't manage the Redis connection lifecycle anymore
125
+ // The injected Redis client is managed by the Redis module
72
126
  this.logger.log('RedisLockService destroyed');
73
127
  });
74
128
  }
129
+ /**
130
+ * Set Redis client (required for dependency injection)
131
+ * This service requires an external Redis client to function
132
+ */
75
133
  setRedisClient(redis) {
76
134
  this.redis = redis;
77
135
  this.logger.log('Redis client set for RedisLockService');
78
136
  }
137
+ /**
138
+ * Set default TTL for locks
139
+ */
79
140
  setDefaultTtl(ttl) {
80
141
  this.defaultOptions.ttl = ttl;
81
142
  }
143
+ /**
144
+ * Set default key prefix for locks
145
+ */
82
146
  setDefaultKeyPrefix(prefix) {
83
147
  this.defaultOptions.keyPrefix = prefix;
84
148
  }
149
+ /**
150
+ * Set default retry count for lock acquisition
151
+ */
85
152
  setDefaultRetryCount(count) {
86
153
  this.defaultOptions.retryCount = count;
87
154
  }
155
+ /**
156
+ * Set default retry delay for lock acquisition
157
+ */
88
158
  setDefaultRetryDelay(delay) {
89
159
  this.defaultOptions.retryDelay = delay;
90
160
  }
161
+ /**
162
+ * Acquire a distributed lock
163
+ *
164
+ * @param key - Lock key (will be prefixed with 'lock:')
165
+ * @param options - Lock options
166
+ * @returns Lock acquisition result
167
+ */
91
168
  acquireLock(key_1) {
92
169
  return __awaiter(this, arguments, void 0, function* (key, options = {}) {
93
170
  const redis = yield this.getRedis();
94
171
  const opts = Object.assign(Object.assign({}, this.defaultOptions), options);
172
+ // Handle backward compatibility: if throwOnFailure is true, use THROW strategy
95
173
  if (opts.throwOnFailure && !options.strategy) {
96
174
  opts.strategy = LockStrategy.THROW;
97
175
  }
98
176
  const lockKey = this.buildLockKey(key, opts.keyPrefix);
99
177
  const lockValue = this.generateLockValue();
178
+ // Determine max attempts based on strategy
100
179
  let maxAttempts;
101
180
  if (opts.strategy === LockStrategy.WAIT) {
102
- maxAttempts = Number.MAX_SAFE_INTEGER;
181
+ maxAttempts = Number.MAX_SAFE_INTEGER; // Infinite retries for WAIT strategy
103
182
  }
104
183
  else {
105
184
  maxAttempts = opts.retryCount + 1;
@@ -107,6 +186,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
107
186
  let attempts = 0;
108
187
  const startTime = Date.now();
109
188
  while (attempts < maxAttempts) {
189
+ // Check timeout for WAIT strategy
110
190
  if (opts.strategy === LockStrategy.WAIT && opts.waitTimeout) {
111
191
  const elapsed = Date.now() - startTime;
112
192
  if (elapsed >= opts.waitTimeout) {
@@ -116,9 +196,11 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
116
196
  }
117
197
  }
118
198
  try {
199
+ // Use SET with NX (Not eXists) and PX (expiration in milliseconds)
119
200
  const result = yield redis.set(lockKey, lockValue, 'PX', opts.ttl, 'NX');
120
201
  if (result === 'OK') {
121
202
  this.logger.debug(`Lock acquired: ${lockKey} (value: ${lockValue}, ttl: ${opts.ttl}ms, attempts: ${attempts + 1})`);
203
+ // Set up auto-extension if enabled
122
204
  let autoExtendTimer;
123
205
  if (opts.autoExtend && opts.autoExtend > 0) {
124
206
  autoExtendTimer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
@@ -132,7 +214,9 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
132
214
  }
133
215
  return { acquired: true, lockValue, autoExtendTimer };
134
216
  }
217
+ // Lock acquisition failed
135
218
  attempts++;
219
+ // For WAIT strategy, log less frequently to avoid spam
136
220
  if (opts.strategy === LockStrategy.WAIT) {
137
221
  if (attempts === 1 || attempts % 10 === 0) {
138
222
  this.logger.debug(`Waiting for lock ${lockKey}... (attempt ${attempts})`);
@@ -141,6 +225,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
141
225
  else if (attempts < maxAttempts) {
142
226
  this.logger.debug(`Lock acquisition failed for ${lockKey}, retrying... (${attempts}/${opts.retryCount})`);
143
227
  }
228
+ // Wait before next attempt (except for last attempt)
144
229
  if (attempts < maxAttempts) {
145
230
  yield this.sleep(opts.retryDelay);
146
231
  }
@@ -154,6 +239,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
154
239
  return { acquired: false, error: errorMessage };
155
240
  }
156
241
  }
242
+ // Max attempts reached
157
243
  const failureMessage = `Failed to acquire lock for ${lockKey} after ${attempts} attempts`;
158
244
  this.logger.warn(failureMessage);
159
245
  if (opts.strategy === LockStrategy.THROW) {
@@ -162,11 +248,23 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
162
248
  return { acquired: false, error: failureMessage };
163
249
  });
164
250
  }
251
+ /**
252
+ * Release a distributed lock
253
+ *
254
+ * Uses Lua script to ensure atomic check-and-delete operation
255
+ * Only releases the lock if the value matches (prevents releasing someone else's lock)
256
+ *
257
+ * @param key - Lock key
258
+ * @param lockValue - Lock value obtained during acquisition
259
+ * @param keyPrefix - Key prefix (must match acquisition)
260
+ * @returns True if lock was released, false otherwise
261
+ */
165
262
  releaseLock(key_1, lockValue_1) {
166
263
  return __awaiter(this, arguments, void 0, function* (key, lockValue, keyPrefix = 'lock') {
167
264
  const redis = yield this.getRedis();
168
265
  const lockKey = this.buildLockKey(key, keyPrefix);
169
266
  try {
267
+ // Lua script to atomically check and delete the lock
170
268
  const script = `
171
269
  if redis.call("get", KEYS[1]) == ARGV[1] then
172
270
  return redis.call("del", KEYS[1])
@@ -190,11 +288,21 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
190
288
  }
191
289
  });
192
290
  }
291
+ /**
292
+ * Extend the expiration time of an existing lock
293
+ *
294
+ * @param key - Lock key
295
+ * @param lockValue - Lock value obtained during acquisition
296
+ * @param ttl - New TTL in milliseconds
297
+ * @param keyPrefix - Key prefix (must match acquisition)
298
+ * @returns True if lock was extended, false otherwise
299
+ */
193
300
  extendLock(key_1, lockValue_1, ttl_1) {
194
301
  return __awaiter(this, arguments, void 0, function* (key, lockValue, ttl, keyPrefix = 'lock') {
195
302
  const redis = yield this.getRedis();
196
303
  const lockKey = this.buildLockKey(key, keyPrefix);
197
304
  try {
305
+ // Lua script to atomically check value and extend TTL
198
306
  const script = `
199
307
  if redis.call("get", KEYS[1]) == ARGV[1] then
200
308
  return redis.call("pexpire", KEYS[1], ARGV[2])
@@ -218,6 +326,13 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
218
326
  }
219
327
  });
220
328
  }
329
+ /**
330
+ * Check if a lock exists
331
+ *
332
+ * @param key - Lock key
333
+ * @param keyPrefix - Key prefix
334
+ * @returns True if lock exists, false otherwise
335
+ */
221
336
  isLocked(key_1) {
222
337
  return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
223
338
  const redis = yield this.getRedis();
@@ -232,6 +347,14 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
232
347
  }
233
348
  });
234
349
  }
350
+ /**
351
+ * Execute a function with automatic lock acquisition and release
352
+ *
353
+ * @param key - Lock key
354
+ * @param fn - Function to execute while holding the lock
355
+ * @param options - Lock options
356
+ * @returns Result of the function execution, or null if lock couldn't be acquired
357
+ */
235
358
  withLock(key_1, fn_1) {
236
359
  return __awaiter(this, arguments, void 0, function* (key, fn, options = {}) {
237
360
  const lockResult = yield this.acquireLock(key, options);
@@ -247,6 +370,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
247
370
  throw error;
248
371
  }
249
372
  finally {
373
+ // Clear auto-extension timer if it exists
250
374
  if (lockResult.autoExtendTimer) {
251
375
  clearInterval(lockResult.autoExtendTimer);
252
376
  }
@@ -254,6 +378,13 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
254
378
  }
255
379
  });
256
380
  }
381
+ /**
382
+ * Get lock information from Redis
383
+ *
384
+ * @param key - Lock key
385
+ * @param keyPrefix - Key prefix
386
+ * @returns Lock information including TTL and value
387
+ */
257
388
  getLockInfo(key_1) {
258
389
  return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
259
390
  const redis = yield this.getRedis();
@@ -274,6 +405,13 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
274
405
  }
275
406
  });
276
407
  }
408
+ /**
409
+ * Force release a lock (use with caution)
410
+ *
411
+ * @param key - Lock key
412
+ * @param keyPrefix - Key prefix
413
+ * @returns True if lock was released, false otherwise
414
+ */
277
415
  forceRelease(key_1) {
278
416
  return __awaiter(this, arguments, void 0, function* (key, keyPrefix = 'lock') {
279
417
  const redis = yield this.getRedis();
@@ -295,6 +433,25 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
295
433
  }
296
434
  });
297
435
  }
436
+ /**
437
+ * Clean up locks by pattern
438
+ * Useful for cleaning up locks after process restart or for specific services
439
+ *
440
+ * WARNING: Use with caution in production! This will forcefully delete locks.
441
+ *
442
+ * @param pattern - Lock pattern (e.g., 'MyService:*' or '*:migration:*')
443
+ * @param keyPrefix - Key prefix (default: 'lock')
444
+ * @returns Number of locks deleted
445
+ *
446
+ * @example
447
+ * ```typescript
448
+ * // Clean up all locks for MyService
449
+ * await lockService.cleanupLocksByPattern('MyService:*');
450
+ *
451
+ * // Clean up all migration locks
452
+ * await lockService.cleanupLocksByPattern('*:migration:*');
453
+ * ```
454
+ */
298
455
  cleanupLocksByPattern(pattern_1) {
299
456
  return __awaiter(this, arguments, void 0, function* (pattern, keyPrefix = 'lock') {
300
457
  const redis = yield this.getRedis();
@@ -315,6 +472,28 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
315
472
  }
316
473
  });
317
474
  }
475
+ /**
476
+ * Clean up locks on startup
477
+ * This method is useful for cleaning up stale locks from previous process instances
478
+ *
479
+ * WARNING: Only use this if you're sure the locks are from previous process instances!
480
+ *
481
+ * @param patterns - Array of lock patterns to clean up
482
+ * @param keyPrefix - Key prefix (default: 'lock')
483
+ * @returns Total number of locks deleted
484
+ *
485
+ * @example
486
+ * ```typescript
487
+ * // In your module's onModuleInit
488
+ * async onModuleInit() {
489
+ * // Clean up locks from this service that might be left from previous restart
490
+ * await this.lockService.cleanupOnStartup([
491
+ * 'MyService:*',
492
+ * 'AnotherService:*'
493
+ * ]);
494
+ * }
495
+ * ```
496
+ */
318
497
  cleanupOnStartup(patterns_1) {
319
498
  return __awaiter(this, arguments, void 0, function* (patterns, keyPrefix = 'lock') {
320
499
  this.logger.log(`Starting lock cleanup for ${patterns.length} pattern(s) on startup...`);
@@ -327,10 +506,17 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
327
506
  return totalDeleted;
328
507
  });
329
508
  }
509
+ /**
510
+ * Health check for Redis connection
511
+ * Returns information about Redis connectivity and lock service status
512
+ *
513
+ * @returns Health check result
514
+ */
330
515
  healthCheck() {
331
516
  return __awaiter(this, void 0, void 0, function* () {
332
517
  try {
333
518
  const redis = yield this.getRedis();
519
+ // Try to ping Redis
334
520
  const pong = yield redis.ping();
335
521
  if (pong === 'PONG') {
336
522
  return {
@@ -356,6 +542,14 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
356
542
  }
357
543
  });
358
544
  }
545
+ /**
546
+ * Get all active locks with optional pattern filtering
547
+ * Useful for monitoring and debugging
548
+ *
549
+ * @param pattern - Optional pattern to filter locks (e.g., 'MyService:*')
550
+ * @param keyPrefix - Key prefix (default: 'lock')
551
+ * @returns Array of active lock information
552
+ */
359
553
  getActiveLocks() {
360
554
  return __awaiter(this, arguments, void 0, function* (pattern = '*', keyPrefix = 'lock') {
361
555
  const redis = yield this.getRedis();
@@ -370,6 +564,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
370
564
  redis.get(key),
371
565
  redis.pttl(key),
372
566
  ]);
567
+ // Remove the key prefix for cleaner output
373
568
  const cleanKey = key.startsWith(`${keyPrefix}:`)
374
569
  ? key.substring(`${keyPrefix}:`.length)
375
570
  : key;
@@ -387,6 +582,10 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
387
582
  }
388
583
  });
389
584
  }
585
+ /**
586
+ * Get Redis connection
587
+ * Requires external Redis client to be set
588
+ */
390
589
  getRedis() {
391
590
  return __awaiter(this, void 0, void 0, function* () {
392
591
  if (!this.redis) {
@@ -395,12 +594,29 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
395
594
  return this.redis;
396
595
  });
397
596
  }
597
+ /**
598
+ * Generate a unique lock value
599
+ *
600
+ * @returns Unique lock identifier
601
+ */
398
602
  generateLockValue() {
399
603
  return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}-${process.pid}`;
400
604
  }
605
+ /**
606
+ * Build the full Redis key for a lock
607
+ *
608
+ * @param key - Lock key
609
+ * @param prefix - Key prefix
610
+ * @returns Full Redis key
611
+ */
401
612
  buildLockKey(key, prefix = 'lock') {
402
613
  return `${prefix}:${key}`;
403
614
  }
615
+ /**
616
+ * Sleep for a specified duration
617
+ *
618
+ * @param ms - Milliseconds to sleep
619
+ */
404
620
  sleep(ms) {
405
621
  return new Promise((resolve) => setTimeout(resolve, ms));
406
622
  }
@@ -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) {