@nest-omni/core 4.1.3-0 → 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 -131
  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
@@ -1,4 +1,9 @@
1
1
  "use strict";
2
+ /**
3
+ * Lock Strategy Examples
4
+ *
5
+ * This file demonstrates the different lock acquisition strategies available in Redis Lock module.
6
+ */
2
7
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
8
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
9
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -23,18 +28,33 @@ exports.CombinedStrategiesExample = exports.WaitStrategyExample = exports.ThrowS
23
28
  const common_1 = require("@nestjs/common");
24
29
  const schedule_1 = require("@nestjs/schedule");
25
30
  const index_1 = require("../index");
31
+ // ============================================================================
32
+ // Strategy 1: SKIP (Default)
33
+ // ============================================================================
34
+ /**
35
+ * SKIP strategy - Skip execution if lock cannot be acquired
36
+ * This is the default behavior and is useful for scheduled tasks where you don't
37
+ * want to queue up requests if a previous execution is still running.
38
+ */
26
39
  let SkipStrategyExample = SkipStrategyExample_1 = class SkipStrategyExample {
27
40
  constructor(lockService) {
28
41
  this.lockService = lockService;
29
42
  this.logger = new common_1.Logger(SkipStrategyExample_1.name);
30
43
  }
44
+ /**
45
+ * Example 1: Using decorator with SKIP strategy (default)
46
+ */
31
47
  scheduledTask() {
32
48
  return __awaiter(this, void 0, void 0, function* () {
33
49
  this.logger.log('Executing scheduled task...');
50
+ // This will skip if another instance is already running
34
51
  yield this.simulateLongRunning();
35
52
  this.logger.log('Scheduled task completed');
36
53
  });
37
54
  }
55
+ /**
56
+ * Example 2: Using service directly with SKIP strategy
57
+ */
38
58
  processWithSkip() {
39
59
  return __awaiter(this, void 0, void 0, function* () {
40
60
  const lockResult = yield this.lockService.acquireLock('process-task', {
@@ -55,13 +75,16 @@ let SkipStrategyExample = SkipStrategyExample_1 = class SkipStrategyExample {
55
75
  }
56
76
  });
57
77
  }
78
+ /**
79
+ * Example 3: SKIP with retries
80
+ */
58
81
  processWithRetries() {
59
82
  return __awaiter(this, void 0, void 0, function* () {
60
83
  const lockResult = yield this.lockService.acquireLock('retry-task', {
61
84
  strategy: index_1.LockStrategy.SKIP,
62
85
  ttl: 30000,
63
- retryCount: 3,
64
- retryDelay: 500,
86
+ retryCount: 3, // Try 3 times
87
+ retryDelay: 500, // Wait 500ms between retries
65
88
  });
66
89
  if (!lockResult.acquired) {
67
90
  this.logger.warn('Failed to acquire lock after 3 retries');
@@ -84,10 +107,11 @@ let SkipStrategyExample = SkipStrategyExample_1 = class SkipStrategyExample {
84
107
  };
85
108
  exports.SkipStrategyExample = SkipStrategyExample;
86
109
  __decorate([
87
- (0, schedule_1.Cron)('* * * * *'),
110
+ (0, schedule_1.Cron)('* * * * *') // Every minute
111
+ ,
88
112
  (0, index_1.UseRedisLock)('scheduled-task', {
89
113
  ttl: 60000,
90
- strategy: index_1.LockStrategy.SKIP,
114
+ strategy: index_1.LockStrategy.SKIP, // Can be omitted as it's the default
91
115
  }),
92
116
  __metadata("design:type", Function),
93
117
  __metadata("design:paramtypes", []),
@@ -97,18 +121,33 @@ exports.SkipStrategyExample = SkipStrategyExample = SkipStrategyExample_1 = __de
97
121
  (0, common_1.Injectable)(),
98
122
  __metadata("design:paramtypes", [index_1.RedisLockService])
99
123
  ], SkipStrategyExample);
124
+ // ============================================================================
125
+ // Strategy 2: THROW
126
+ // ============================================================================
127
+ /**
128
+ * THROW strategy - Throw an error if lock cannot be acquired
129
+ * Use this for critical operations that must have exclusive access.
130
+ * If the lock cannot be acquired, an exception will be thrown.
131
+ */
100
132
  let ThrowStrategyExample = ThrowStrategyExample_1 = class ThrowStrategyExample {
101
133
  constructor(lockService) {
102
134
  this.lockService = lockService;
103
135
  this.logger = new common_1.Logger(ThrowStrategyExample_1.name);
104
136
  }
137
+ /**
138
+ * Example 1: Using decorator with THROW strategy
139
+ */
105
140
  criticalOperation() {
106
141
  return __awaiter(this, void 0, void 0, function* () {
107
142
  this.logger.log('Executing critical operation...');
143
+ // If lock cannot be acquired, an error will be thrown
108
144
  yield this.processData();
109
145
  this.logger.log('Critical operation completed');
110
146
  });
111
147
  }
148
+ /**
149
+ * Example 2: Using service with error handling
150
+ */
112
151
  processWithThrow() {
113
152
  return __awaiter(this, void 0, void 0, function* () {
114
153
  try {
@@ -127,20 +166,26 @@ let ThrowStrategyExample = ThrowStrategyExample_1 = class ThrowStrategyExample {
127
166
  }
128
167
  catch (error) {
129
168
  this.logger.error(`Failed to acquire lock: ${error.message}`);
169
+ // Handle the error appropriately
130
170
  throw new Error('Operation cannot proceed without exclusive access');
131
171
  }
132
172
  });
133
173
  }
174
+ /**
175
+ * Example 3: Critical payment processing
176
+ */
134
177
  processPayment(orderId, amount) {
135
178
  return __awaiter(this, void 0, void 0, function* () {
136
179
  const lockKey = `payment:${orderId}`;
137
180
  try {
181
+ // Must have exclusive access for payment processing
138
182
  const lockResult = yield this.lockService.acquireLock(lockKey, {
139
183
  strategy: index_1.LockStrategy.THROW,
140
184
  ttl: 60000,
141
185
  });
142
186
  try {
143
187
  this.logger.log(`Processing payment for order ${orderId}...`);
188
+ // Payment logic here
144
189
  yield this.chargePayment(orderId, amount);
145
190
  yield this.updateOrderStatus(orderId, 'paid');
146
191
  return { success: true };
@@ -162,11 +207,13 @@ let ThrowStrategyExample = ThrowStrategyExample_1 = class ThrowStrategyExample {
162
207
  }
163
208
  chargePayment(orderId, amount) {
164
209
  return __awaiter(this, void 0, void 0, function* () {
210
+ // Simulate payment processing
165
211
  yield new Promise((resolve) => setTimeout(resolve, 1000));
166
212
  });
167
213
  }
168
214
  updateOrderStatus(orderId, status) {
169
215
  return __awaiter(this, void 0, void 0, function* () {
216
+ // Update order status
170
217
  yield new Promise((resolve) => setTimeout(resolve, 500));
171
218
  });
172
219
  }
@@ -185,24 +232,39 @@ exports.ThrowStrategyExample = ThrowStrategyExample = ThrowStrategyExample_1 = _
185
232
  (0, common_1.Injectable)(),
186
233
  __metadata("design:paramtypes", [index_1.RedisLockService])
187
234
  ], ThrowStrategyExample);
235
+ // ============================================================================
236
+ // Strategy 3: WAIT
237
+ // ============================================================================
238
+ /**
239
+ * WAIT strategy - Block/wait until lock can be acquired
240
+ * Use this when you want to queue execution and ensure the operation eventually runs.
241
+ * The function will wait indefinitely (or until waitTimeout) for the lock to become available.
242
+ */
188
243
  let WaitStrategyExample = WaitStrategyExample_1 = class WaitStrategyExample {
189
244
  constructor(lockService) {
190
245
  this.lockService = lockService;
191
246
  this.logger = new common_1.Logger(WaitStrategyExample_1.name);
192
247
  }
248
+ /**
249
+ * Example 1: Using decorator with WAIT strategy
250
+ */
193
251
  sequentialTask() {
194
252
  return __awaiter(this, void 0, void 0, function* () {
195
253
  this.logger.log('Executing sequential task...');
254
+ // This will wait until lock is available
196
255
  yield this.processInOrder();
197
256
  this.logger.log('Sequential task completed');
198
257
  });
199
258
  }
259
+ /**
260
+ * Example 2: WAIT with timeout
261
+ */
200
262
  processWithWaitTimeout() {
201
263
  return __awaiter(this, void 0, void 0, function* () {
202
264
  const lockResult = yield this.lockService.acquireLock('wait-task', {
203
265
  strategy: index_1.LockStrategy.WAIT,
204
- waitTimeout: 30000,
205
- retryDelay: 200,
266
+ waitTimeout: 30000, // Wait maximum 30 seconds
267
+ retryDelay: 200, // Check every 200ms
206
268
  ttl: 60000,
207
269
  });
208
270
  if (!lockResult.acquired) {
@@ -219,16 +281,21 @@ let WaitStrategyExample = WaitStrategyExample_1 = class WaitStrategyExample {
219
281
  }
220
282
  });
221
283
  }
284
+ /**
285
+ * Example 3: Sequential data processing
286
+ * Perfect for operations that must be processed in order
287
+ */
222
288
  processDataSequentially(userId, data) {
223
289
  return __awaiter(this, void 0, void 0, function* () {
224
290
  const lockKey = `user-data:${userId}`;
225
291
  const lockResult = yield this.lockService.acquireLock(lockKey, {
226
292
  strategy: index_1.LockStrategy.WAIT,
227
293
  retryDelay: 50,
228
- ttl: 120000,
294
+ ttl: 120000, // 2 minutes
229
295
  });
230
296
  try {
231
297
  this.logger.log(`Processing data for user ${userId}...`);
298
+ // These operations will execute sequentially across all instances
232
299
  yield this.validateData(data);
233
300
  yield this.saveData(userId, data);
234
301
  yield this.notifyUser(userId);
@@ -239,6 +306,10 @@ let WaitStrategyExample = WaitStrategyExample_1 = class WaitStrategyExample {
239
306
  }
240
307
  });
241
308
  }
309
+ /**
310
+ * Example 4: Queue-like behavior
311
+ * Multiple requests will queue and execute one by one
312
+ */
242
313
  processQueue(queueName, item) {
243
314
  return __awaiter(this, void 0, void 0, function* () {
244
315
  const lockKey = `queue:${queueName}`;
@@ -258,15 +329,19 @@ let WaitStrategyExample = WaitStrategyExample_1 = class WaitStrategyExample {
258
329
  }
259
330
  });
260
331
  }
332
+ /**
333
+ * Example 5: Database migration with WAIT
334
+ * Ensures migrations run sequentially across all instances
335
+ */
261
336
  runMigration(migrationName) {
262
337
  return __awaiter(this, void 0, void 0, function* () {
263
338
  const lockKey = `migration:${migrationName}`;
264
339
  this.logger.log(`Waiting to run migration ${migrationName}...`);
265
340
  const lockResult = yield this.lockService.acquireLock(lockKey, {
266
341
  strategy: index_1.LockStrategy.WAIT,
267
- waitTimeout: 300000,
268
- retryDelay: 1000,
269
- ttl: 600000,
342
+ waitTimeout: 300000, // Wait up to 5 minutes
343
+ retryDelay: 1000, // Check every second
344
+ ttl: 600000, // Hold lock for 10 minutes max
270
345
  });
271
346
  if (!lockResult.acquired) {
272
347
  throw new Error(`Migration ${migrationName} timed out waiting for lock`);
@@ -318,7 +393,7 @@ __decorate([
318
393
  (0, index_1.UseRedisLock)('sequential-task', {
319
394
  ttl: 30000,
320
395
  strategy: index_1.LockStrategy.WAIT,
321
- retryDelay: 100,
396
+ retryDelay: 100, // Check every 100ms
322
397
  }),
323
398
  __metadata("design:type", Function),
324
399
  __metadata("design:paramtypes", []),
@@ -328,16 +403,50 @@ exports.WaitStrategyExample = WaitStrategyExample = WaitStrategyExample_1 = __de
328
403
  (0, common_1.Injectable)(),
329
404
  __metadata("design:paramtypes", [index_1.RedisLockService])
330
405
  ], WaitStrategyExample);
406
+ // ============================================================================
407
+ // Comparison: When to use each strategy
408
+ // ============================================================================
409
+ /**
410
+ * USE SKIP WHEN:
411
+ * - Running scheduled tasks where you don't want overlapping executions
412
+ * - Cron jobs that should skip if previous run is still in progress
413
+ * - Non-critical background tasks
414
+ * - Operations where it's okay to skip if busy
415
+ *
416
+ * USE THROW WHEN:
417
+ * - Critical operations that require exclusive access
418
+ * - Financial transactions
419
+ * - Operations where failure to acquire lock is an error
420
+ * - When you want to alert/fail fast if resource is busy
421
+ *
422
+ * USE WAIT WHEN:
423
+ * - Operations that must execute eventually
424
+ * - Sequential processing requirements
425
+ * - Queue-like behavior needed
426
+ * - Database migrations
427
+ * - Operations where order matters
428
+ * - When you want to ensure the operation runs (with optional timeout)
429
+ */
430
+ /**
431
+ * Example: Combining strategies in a single service
432
+ */
331
433
  let CombinedStrategiesExample = CombinedStrategiesExample_1 = class CombinedStrategiesExample {
332
434
  constructor(lockService) {
333
435
  this.lockService = lockService;
334
436
  this.logger = new common_1.Logger(CombinedStrategiesExample_1.name);
335
437
  }
438
+ /**
439
+ * Background cleanup - SKIP if already running
440
+ */
336
441
  cleanupOldData() {
337
442
  return __awaiter(this, void 0, void 0, function* () {
338
443
  this.logger.log('Running cleanup...');
444
+ // Cleanup logic
339
445
  });
340
446
  }
447
+ /**
448
+ * Payment processing - THROW if cannot get exclusive access
449
+ */
341
450
  processPayment(orderId) {
342
451
  return __awaiter(this, void 0, void 0, function* () {
343
452
  const lockResult = yield this.lockService.acquireLock(`payment:${orderId}`, {
@@ -345,24 +454,29 @@ let CombinedStrategiesExample = CombinedStrategiesExample_1 = class CombinedStra
345
454
  ttl: 60000,
346
455
  });
347
456
  try {
457
+ // Payment logic
348
458
  }
349
459
  finally {
350
460
  yield this.lockService.releaseLock(`payment:${orderId}`, lockResult.lockValue);
351
461
  }
352
462
  });
353
463
  }
464
+ /**
465
+ * Report generation - WAIT to ensure it runs eventually
466
+ */
354
467
  generateReport(reportId) {
355
468
  return __awaiter(this, void 0, void 0, function* () {
356
469
  const lockResult = yield this.lockService.acquireLock(`report:${reportId}`, {
357
470
  strategy: index_1.LockStrategy.WAIT,
358
- waitTimeout: 180000,
471
+ waitTimeout: 180000, // Wait up to 3 minutes
359
472
  retryDelay: 500,
360
- ttl: 300000,
473
+ ttl: 300000, // 5 minutes
361
474
  });
362
475
  if (!lockResult.acquired) {
363
476
  throw new Error('Report generation timed out');
364
477
  }
365
478
  try {
479
+ // Report generation logic
366
480
  }
367
481
  finally {
368
482
  yield this.lockService.releaseLock(`report:${reportId}`, lockResult.lockValue);
@@ -372,10 +486,11 @@ let CombinedStrategiesExample = CombinedStrategiesExample_1 = class CombinedStra
372
486
  };
373
487
  exports.CombinedStrategiesExample = CombinedStrategiesExample;
374
488
  __decorate([
375
- (0, schedule_1.Cron)('0 */6 * * *'),
489
+ (0, schedule_1.Cron)('0 */6 * * *') // Every 6 hours
490
+ ,
376
491
  (0, index_1.UseRedisLock)('cleanup-task', {
377
492
  strategy: index_1.LockStrategy.SKIP,
378
- ttl: 3600000,
493
+ ttl: 3600000, // 1 hour
379
494
  }),
380
495
  __metadata("design:type", Function),
381
496
  __metadata("design:paramtypes", []),
@@ -1,4 +1,6 @@
1
1
  export { RedisLockModule, type RedisLockModuleOptions, REDIS_LOCK_SERVICE, } from './redis-lock.module';
2
2
  export { RedisLockService, LockStrategy } from './redis-lock.service';
3
+ export { LockHeartbeatService } from './lock-heartbeat.service';
4
+ export { ComprehensiveLockCleanupService } from './comprehensive-lock-cleanup.service';
3
5
  export { UseRedisLock, UseRedisLockOrSkip, UseRedisLockSmart, UseRedisLockOrSkipSmart, setLockService, getLockService, } from './redis-lock.decorator';
4
6
  export type { LockOptions, LockResult } from './redis-lock.service';
@@ -1,12 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getLockService = exports.setLockService = exports.UseRedisLockOrSkipSmart = exports.UseRedisLockSmart = exports.UseRedisLockOrSkip = exports.UseRedisLock = exports.LockStrategy = exports.RedisLockService = exports.REDIS_LOCK_SERVICE = exports.RedisLockModule = void 0;
3
+ exports.getLockService = exports.setLockService = exports.UseRedisLockOrSkipSmart = exports.UseRedisLockSmart = exports.UseRedisLockOrSkip = exports.UseRedisLock = exports.ComprehensiveLockCleanupService = exports.LockHeartbeatService = exports.LockStrategy = exports.RedisLockService = exports.REDIS_LOCK_SERVICE = exports.RedisLockModule = void 0;
4
+ // Module
4
5
  var redis_lock_module_1 = require("./redis-lock.module");
5
6
  Object.defineProperty(exports, "RedisLockModule", { enumerable: true, get: function () { return redis_lock_module_1.RedisLockModule; } });
6
7
  Object.defineProperty(exports, "REDIS_LOCK_SERVICE", { enumerable: true, get: function () { return redis_lock_module_1.REDIS_LOCK_SERVICE; } });
8
+ // Service
7
9
  var redis_lock_service_1 = require("./redis-lock.service");
8
10
  Object.defineProperty(exports, "RedisLockService", { enumerable: true, get: function () { return redis_lock_service_1.RedisLockService; } });
9
11
  Object.defineProperty(exports, "LockStrategy", { enumerable: true, get: function () { return redis_lock_service_1.LockStrategy; } });
12
+ var lock_heartbeat_service_1 = require("./lock-heartbeat.service");
13
+ Object.defineProperty(exports, "LockHeartbeatService", { enumerable: true, get: function () { return lock_heartbeat_service_1.LockHeartbeatService; } });
14
+ var comprehensive_lock_cleanup_service_1 = require("./comprehensive-lock-cleanup.service");
15
+ Object.defineProperty(exports, "ComprehensiveLockCleanupService", { enumerable: true, get: function () { return comprehensive_lock_cleanup_service_1.ComprehensiveLockCleanupService; } });
16
+ // Decorators
10
17
  var redis_lock_decorator_1 = require("./redis-lock.decorator");
11
18
  Object.defineProperty(exports, "UseRedisLock", { enumerable: true, get: function () { return redis_lock_decorator_1.UseRedisLock; } });
12
19
  Object.defineProperty(exports, "UseRedisLockOrSkip", { enumerable: true, get: function () { return redis_lock_decorator_1.UseRedisLockOrSkip; } });
@@ -0,0 +1,78 @@
1
+ import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
2
+ import type Redis from 'ioredis';
3
+ /**
4
+ * Lock heartbeat service
5
+ *
6
+ * Provides heartbeat mechanism for distributed lock instances.
7
+ * Each instance sends periodic heartbeats to Redis to indicate it's alive.
8
+ * Dead instances can be detected by checking if their heartbeat has expired.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * constructor(private heartbeatService: LockHeartbeatService) {}
13
+ *
14
+ * async isInstanceAlive(instanceId: string): Promise<boolean> {
15
+ * return this.heartbeatService.isInstanceAlive(instanceId);
16
+ * }
17
+ * ```
18
+ */
19
+ export declare class LockHeartbeatService implements OnModuleInit, OnModuleDestroy {
20
+ private readonly logger;
21
+ private readonly instanceId;
22
+ private redis;
23
+ private heartbeatTimer;
24
+ /**
25
+ * Heartbeat interval in milliseconds
26
+ * @default 10000 (10 seconds)
27
+ */
28
+ private readonly heartbeatInterval;
29
+ /**
30
+ * Heartbeat TTL in seconds (3x interval for safety)
31
+ * @default 30 (30 seconds)
32
+ */
33
+ private readonly heartbeatTtl;
34
+ constructor();
35
+ onModuleInit(): Promise<void>;
36
+ onModuleDestroy(): Promise<void>;
37
+ /**
38
+ * Set Redis client (required for dependency injection)
39
+ */
40
+ setRedisClient(redis: Redis): void;
41
+ /**
42
+ * Send heartbeat to Redis
43
+ * Stores instance information with TTL
44
+ */
45
+ private sendHeartbeat;
46
+ /**
47
+ * Remove heartbeat record from Redis
48
+ */
49
+ private removeHeartbeat;
50
+ /**
51
+ * Check if an instance is alive by checking its heartbeat
52
+ *
53
+ * @param instanceId - Instance identifier to check
54
+ * @returns True if instance is alive (heartbeat exists), false otherwise
55
+ */
56
+ isInstanceAlive(instanceId: string): Promise<boolean>;
57
+ /**
58
+ * Get heartbeat information for an instance
59
+ *
60
+ * @param instanceId - Instance identifier
61
+ * @returns Heartbeat data or null if not found
62
+ */
63
+ getHeartbeatInfo(instanceId: string): Promise<{
64
+ instanceId: string;
65
+ timestamp: number;
66
+ pid: number;
67
+ } | null>;
68
+ /**
69
+ * Get all active instances (with heartbeat)
70
+ *
71
+ * @returns Array of instance IDs that are currently alive
72
+ */
73
+ getActiveInstances(): Promise<string[]>;
74
+ /**
75
+ * Get current instance ID
76
+ */
77
+ getInstanceId(): string;
78
+ }
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ var LockHeartbeatService_1;
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.LockHeartbeatService = void 0;
23
+ const common_1 = require("@nestjs/common");
24
+ /**
25
+ * Lock heartbeat service
26
+ *
27
+ * Provides heartbeat mechanism for distributed lock instances.
28
+ * Each instance sends periodic heartbeats to Redis to indicate it's alive.
29
+ * Dead instances can be detected by checking if their heartbeat has expired.
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * constructor(private heartbeatService: LockHeartbeatService) {}
34
+ *
35
+ * async isInstanceAlive(instanceId: string): Promise<boolean> {
36
+ * return this.heartbeatService.isInstanceAlive(instanceId);
37
+ * }
38
+ * ```
39
+ */
40
+ let LockHeartbeatService = LockHeartbeatService_1 = class LockHeartbeatService {
41
+ constructor() {
42
+ this.logger = new common_1.Logger(LockHeartbeatService_1.name);
43
+ this.redis = null;
44
+ this.heartbeatTimer = null;
45
+ /**
46
+ * Heartbeat interval in milliseconds
47
+ * @default 10000 (10 seconds)
48
+ */
49
+ this.heartbeatInterval = 10000;
50
+ /**
51
+ * Heartbeat TTL in seconds (3x interval for safety)
52
+ * @default 30 (30 seconds)
53
+ */
54
+ this.heartbeatTtl = 30;
55
+ this.instanceId = this.getInstanceId();
56
+ }
57
+ onModuleInit() {
58
+ return __awaiter(this, void 0, void 0, function* () {
59
+ if (!this.redis) {
60
+ this.logger.warn('LockHeartbeatService initialized but no Redis client provided. Heartbeat functionality will not work.');
61
+ return;
62
+ }
63
+ // Send initial heartbeat
64
+ yield this.sendHeartbeat();
65
+ // Start periodic heartbeat
66
+ this.heartbeatTimer = setInterval(() => {
67
+ this.sendHeartbeat().catch((error) => {
68
+ this.logger.error('Failed to send heartbeat:', error);
69
+ });
70
+ }, this.heartbeatInterval);
71
+ this.logger.log(`Heartbeat started for instance: ${this.instanceId}`);
72
+ });
73
+ }
74
+ onModuleDestroy() {
75
+ return __awaiter(this, void 0, void 0, function* () {
76
+ // Stop heartbeat timer
77
+ if (this.heartbeatTimer) {
78
+ clearInterval(this.heartbeatTimer);
79
+ this.heartbeatTimer = null;
80
+ }
81
+ // Remove heartbeat record
82
+ yield this.removeHeartbeat();
83
+ this.logger.log('Heartbeat stopped');
84
+ });
85
+ }
86
+ /**
87
+ * Set Redis client (required for dependency injection)
88
+ */
89
+ setRedisClient(redis) {
90
+ this.redis = redis;
91
+ this.logger.log('Redis client set for LockHeartbeatService');
92
+ }
93
+ /**
94
+ * Send heartbeat to Redis
95
+ * Stores instance information with TTL
96
+ */
97
+ sendHeartbeat() {
98
+ return __awaiter(this, void 0, void 0, function* () {
99
+ if (!this.redis) {
100
+ return;
101
+ }
102
+ const key = `heartbeat:${this.instanceId}`;
103
+ const data = {
104
+ instanceId: this.instanceId,
105
+ timestamp: Date.now(),
106
+ pid: process.pid,
107
+ };
108
+ try {
109
+ // Set heartbeat with TTL (3x interval for safety)
110
+ yield this.redis.setex(key, this.heartbeatTtl, JSON.stringify(data));
111
+ }
112
+ catch (error) {
113
+ this.logger.error('Error sending heartbeat:', error);
114
+ }
115
+ });
116
+ }
117
+ /**
118
+ * Remove heartbeat record from Redis
119
+ */
120
+ removeHeartbeat() {
121
+ return __awaiter(this, void 0, void 0, function* () {
122
+ if (!this.redis) {
123
+ return;
124
+ }
125
+ const key = `heartbeat:${this.instanceId}`;
126
+ try {
127
+ yield this.redis.del(key);
128
+ }
129
+ catch (error) {
130
+ this.logger.error('Error removing heartbeat:', error);
131
+ }
132
+ });
133
+ }
134
+ /**
135
+ * Check if an instance is alive by checking its heartbeat
136
+ *
137
+ * @param instanceId - Instance identifier to check
138
+ * @returns True if instance is alive (heartbeat exists), false otherwise
139
+ */
140
+ isInstanceAlive(instanceId) {
141
+ return __awaiter(this, void 0, void 0, function* () {
142
+ if (!this.redis) {
143
+ this.logger.warn('Redis client not available, cannot check instance status');
144
+ return false;
145
+ }
146
+ const key = `heartbeat:${instanceId}`;
147
+ try {
148
+ const exists = yield this.redis.exists(key);
149
+ return exists === 1;
150
+ }
151
+ catch (error) {
152
+ this.logger.error(`Error checking instance ${instanceId} status:`, error);
153
+ return false;
154
+ }
155
+ });
156
+ }
157
+ /**
158
+ * Get heartbeat information for an instance
159
+ *
160
+ * @param instanceId - Instance identifier
161
+ * @returns Heartbeat data or null if not found
162
+ */
163
+ getHeartbeatInfo(instanceId) {
164
+ return __awaiter(this, void 0, void 0, function* () {
165
+ if (!this.redis) {
166
+ return null;
167
+ }
168
+ const key = `heartbeat:${instanceId}`;
169
+ try {
170
+ const data = yield this.redis.get(key);
171
+ if (!data) {
172
+ return null;
173
+ }
174
+ return JSON.parse(data);
175
+ }
176
+ catch (error) {
177
+ this.logger.error(`Error getting heartbeat info for ${instanceId}:`, error);
178
+ return null;
179
+ }
180
+ });
181
+ }
182
+ /**
183
+ * Get all active instances (with heartbeat)
184
+ *
185
+ * @returns Array of instance IDs that are currently alive
186
+ */
187
+ getActiveInstances() {
188
+ return __awaiter(this, void 0, void 0, function* () {
189
+ if (!this.redis) {
190
+ return [];
191
+ }
192
+ try {
193
+ const keys = yield this.redis.keys('heartbeat:*');
194
+ return keys.map((key) => key.replace('heartbeat:', ''));
195
+ }
196
+ catch (error) {
197
+ this.logger.error('Error getting active instances:', error);
198
+ return [];
199
+ }
200
+ });
201
+ }
202
+ /**
203
+ * Get current instance ID
204
+ */
205
+ getInstanceId() {
206
+ // 1. Kubernetes Pod name
207
+ if (process.env.HOSTNAME) {
208
+ return process.env.HOSTNAME;
209
+ }
210
+ // 2. Custom instance ID
211
+ if (process.env.INSTANCE_ID) {
212
+ return process.env.INSTANCE_ID;
213
+ }
214
+ // 3. Generate unique ID
215
+ return `instance-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
216
+ }
217
+ };
218
+ exports.LockHeartbeatService = LockHeartbeatService;
219
+ exports.LockHeartbeatService = LockHeartbeatService = LockHeartbeatService_1 = __decorate([
220
+ (0, common_1.Injectable)(),
221
+ __metadata("design:paramtypes", [])
222
+ ], LockHeartbeatService);