ioredis-toolkit 0.0.9 → 0.5.0

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 (267) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/LICENSE +1 -1
  3. package/README.md +68 -1058
  4. package/dist/cache/cache.d.ts +30 -0
  5. package/dist/cache/cache.d.ts.map +1 -0
  6. package/dist/cache/cache.js +59 -0
  7. package/dist/cache/cache.js.map +1 -0
  8. package/dist/cache/config.d.ts +12 -0
  9. package/dist/cache/config.d.ts.map +1 -0
  10. package/dist/cache/config.js +13 -0
  11. package/dist/cache/config.js.map +1 -0
  12. package/dist/cache/types.d.ts +32 -0
  13. package/dist/cache/types.d.ts.map +1 -0
  14. package/dist/cache/types.js +5 -0
  15. package/dist/cache/types.js.map +1 -0
  16. package/dist/index.d.ts +43 -51
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +32 -44
  19. package/dist/index.js.map +1 -0
  20. package/dist/lock/config.d.ts +12 -0
  21. package/dist/lock/config.d.ts.map +1 -0
  22. package/dist/lock/config.js +8 -0
  23. package/dist/lock/config.js.map +1 -0
  24. package/dist/lock/lock.d.ts +20 -0
  25. package/dist/lock/lock.d.ts.map +1 -0
  26. package/dist/lock/lock.js +44 -0
  27. package/dist/lock/lock.js.map +1 -0
  28. package/dist/lock/types.d.ts +19 -0
  29. package/dist/lock/types.d.ts.map +1 -0
  30. package/dist/lock/types.js +2 -0
  31. package/dist/lock/types.js.map +1 -0
  32. package/dist/modules-config.d.ts +3 -0
  33. package/dist/modules-config.d.ts.map +1 -0
  34. package/dist/modules-config.js +2 -0
  35. package/dist/modules-config.js.map +1 -0
  36. package/dist/pubsub/config.d.ts +11 -0
  37. package/dist/pubsub/config.d.ts.map +1 -0
  38. package/dist/pubsub/config.js +6 -0
  39. package/dist/pubsub/config.js.map +1 -0
  40. package/dist/pubsub/pubsub.d.ts +20 -0
  41. package/dist/pubsub/pubsub.d.ts.map +1 -0
  42. package/dist/pubsub/pubsub.js +54 -0
  43. package/dist/pubsub/pubsub.js.map +1 -0
  44. package/dist/pubsub/types.d.ts +24 -0
  45. package/dist/pubsub/types.d.ts.map +1 -0
  46. package/dist/pubsub/types.js +2 -0
  47. package/dist/pubsub/types.js.map +1 -0
  48. package/dist/rate-limit/config.d.ts +12 -0
  49. package/dist/rate-limit/config.d.ts.map +1 -0
  50. package/dist/rate-limit/config.js +6 -0
  51. package/dist/rate-limit/config.js.map +1 -0
  52. package/dist/rate-limit/rate-limiter.d.ts +18 -0
  53. package/dist/rate-limit/rate-limiter.d.ts.map +1 -0
  54. package/dist/rate-limit/rate-limiter.js +37 -0
  55. package/dist/rate-limit/rate-limiter.js.map +1 -0
  56. package/dist/rate-limit/types.d.ts +27 -0
  57. package/dist/rate-limit/types.d.ts.map +1 -0
  58. package/dist/rate-limit/types.js +2 -0
  59. package/dist/rate-limit/types.js.map +1 -0
  60. package/dist/redis/client-facade.d.ts +77 -0
  61. package/dist/redis/client-facade.d.ts.map +1 -0
  62. package/dist/redis/client-facade.js +102 -0
  63. package/dist/redis/client-facade.js.map +1 -0
  64. package/dist/redis/client.d.ts +10 -0
  65. package/dist/redis/client.d.ts.map +1 -0
  66. package/dist/redis/client.js +29 -0
  67. package/dist/redis/client.js.map +1 -0
  68. package/dist/redis/cluster.d.ts +7 -0
  69. package/dist/redis/cluster.d.ts.map +1 -0
  70. package/dist/redis/cluster.js +47 -0
  71. package/dist/redis/cluster.js.map +1 -0
  72. package/dist/redis/config.d.ts +39 -0
  73. package/dist/redis/config.d.ts.map +1 -0
  74. package/dist/redis/config.js +52 -0
  75. package/dist/redis/config.js.map +1 -0
  76. package/dist/redis/errors.d.ts +5 -0
  77. package/dist/redis/errors.d.ts.map +1 -0
  78. package/dist/redis/errors.js +5 -0
  79. package/dist/redis/errors.js.map +1 -0
  80. package/dist/redis/types.d.ts +135 -0
  81. package/dist/redis/types.d.ts.map +1 -0
  82. package/dist/redis/types.js +2 -0
  83. package/dist/redis/types.js.map +1 -0
  84. package/dist/redis/wrapper.d.ts +88 -0
  85. package/dist/redis/wrapper.d.ts.map +1 -0
  86. package/dist/redis/wrapper.js +206 -0
  87. package/dist/redis/wrapper.js.map +1 -0
  88. package/dist/session/config.d.ts +47 -0
  89. package/dist/session/config.d.ts.map +1 -0
  90. package/dist/session/config.js +101 -0
  91. package/dist/session/config.js.map +1 -0
  92. package/dist/session/cookie.d.ts +16 -0
  93. package/dist/session/cookie.d.ts.map +1 -0
  94. package/dist/session/cookie.js +28 -0
  95. package/dist/session/cookie.js.map +1 -0
  96. package/dist/session/errors.d.ts +56 -0
  97. package/dist/session/errors.d.ts.map +1 -0
  98. package/dist/session/errors.js +58 -0
  99. package/dist/session/errors.js.map +1 -0
  100. package/dist/session/factory.d.ts +21 -0
  101. package/dist/session/factory.d.ts.map +1 -0
  102. package/dist/session/factory.js +30 -0
  103. package/dist/session/factory.js.map +1 -0
  104. package/dist/session/health.d.ts +12 -0
  105. package/dist/session/health.d.ts.map +1 -0
  106. package/dist/session/health.js +23 -0
  107. package/dist/session/health.js.map +1 -0
  108. package/dist/session/keys.d.ts +23 -0
  109. package/dist/session/keys.d.ts.map +1 -0
  110. package/dist/session/keys.js +27 -0
  111. package/dist/session/keys.js.map +1 -0
  112. package/dist/session/manager.d.ts +34 -0
  113. package/dist/session/manager.d.ts.map +1 -0
  114. package/dist/session/manager.js +31 -0
  115. package/dist/session/manager.js.map +1 -0
  116. package/dist/session/metrics.d.ts +11 -0
  117. package/dist/session/metrics.d.ts.map +1 -0
  118. package/dist/session/metrics.js +10 -0
  119. package/dist/session/metrics.js.map +1 -0
  120. package/dist/session/repository.d.ts +49 -0
  121. package/dist/session/repository.d.ts.map +1 -0
  122. package/dist/session/repository.js +203 -0
  123. package/dist/session/repository.js.map +1 -0
  124. package/dist/session/revocation.d.ts +22 -0
  125. package/dist/session/revocation.d.ts.map +1 -0
  126. package/dist/session/revocation.js +41 -0
  127. package/dist/session/revocation.js.map +1 -0
  128. package/dist/session/script-sources.d.ts +11 -0
  129. package/dist/session/script-sources.d.ts.map +1 -0
  130. package/dist/session/script-sources.js +140 -0
  131. package/dist/session/script-sources.js.map +1 -0
  132. package/dist/session/scripts.d.ts +15 -0
  133. package/dist/session/scripts.d.ts.map +1 -0
  134. package/dist/session/scripts.js +41 -0
  135. package/dist/session/scripts.js.map +1 -0
  136. package/dist/session/serializer.d.ts +12 -0
  137. package/dist/session/serializer.d.ts.map +1 -0
  138. package/dist/session/serializer.js +77 -0
  139. package/dist/session/serializer.js.map +1 -0
  140. package/dist/session/service.d.ts +48 -0
  141. package/dist/session/service.d.ts.map +1 -0
  142. package/dist/session/service.js +235 -0
  143. package/dist/session/service.js.map +1 -0
  144. package/dist/session/token.d.ts +16 -0
  145. package/dist/session/token.d.ts.map +1 -0
  146. package/dist/session/token.js +32 -0
  147. package/dist/session/token.js.map +1 -0
  148. package/dist/session/types.d.ts +134 -0
  149. package/dist/session/types.d.ts.map +1 -0
  150. package/dist/session/types.js +2 -0
  151. package/dist/session/types.js.map +1 -0
  152. package/dist/streams/config.d.ts +12 -0
  153. package/dist/streams/config.d.ts.map +1 -0
  154. package/dist/streams/config.js +6 -0
  155. package/dist/streams/config.js.map +1 -0
  156. package/dist/streams/streams.d.ts +24 -0
  157. package/dist/streams/streams.d.ts.map +1 -0
  158. package/dist/streams/streams.js +55 -0
  159. package/dist/streams/streams.js.map +1 -0
  160. package/dist/streams/types.d.ts +32 -0
  161. package/dist/streams/types.d.ts.map +1 -0
  162. package/dist/streams/types.js +2 -0
  163. package/dist/streams/types.js.map +1 -0
  164. package/docs/ACCEPTANCE-REPORT.md +70 -0
  165. package/docs/ARCHITECTURE.md +61 -0
  166. package/docs/CAPACITY.md +33 -0
  167. package/docs/DEPLOYMENT.md +22 -0
  168. package/docs/README-API.md +15 -0
  169. package/docs/STATE-MACHINE.md +38 -0
  170. package/docs/TESTING.md +37 -0
  171. package/docs/THREAT-MODEL.md +23 -0
  172. package/docs/TYPE-SAFETY.md +34 -0
  173. package/docs/modules/cache/README.md +7 -0
  174. package/docs/modules/cache/usage.md +156 -0
  175. package/docs/modules/lock/README.md +7 -0
  176. package/docs/modules/lock/usage.md +105 -0
  177. package/docs/modules/pubsub/README.md +7 -0
  178. package/docs/modules/pubsub/usage.md +106 -0
  179. package/docs/modules/rate-limit/README.md +7 -0
  180. package/docs/modules/rate-limit/usage.md +100 -0
  181. package/docs/modules/sessions/README.md +7 -0
  182. package/docs/modules/sessions/usage.md +262 -0
  183. package/docs/modules/streams/README.md +7 -0
  184. package/docs/modules/streams/usage.md +141 -0
  185. package/package.json +50 -60
  186. package/src/scripts/cleanup-index.lua +4 -0
  187. package/src/scripts/conditional-update.lua +21 -0
  188. package/src/scripts/consume-session.lua +21 -0
  189. package/src/scripts/create-session.lua +28 -0
  190. package/src/scripts/delete.lua +2 -0
  191. package/src/scripts/destroy-user.lua +13 -0
  192. package/src/scripts/enforce-limit.lua +17 -0
  193. package/src/scripts/revoke-session.lua +13 -0
  194. package/src/scripts/rotate.lua +24 -0
  195. package/src/scripts/touch-session.lua +28 -0
  196. package/src/scripts/update-session.lua +18 -0
  197. package/dist/cache.d.ts +0 -796
  198. package/dist/cache.js +0 -1120
  199. package/dist/client.d.ts +0 -284
  200. package/dist/client.js +0 -1114
  201. package/dist/cluster-slot.d.ts +0 -4
  202. package/dist/cluster-slot.js +0 -31
  203. package/dist/cluster.d.ts +0 -79
  204. package/dist/cluster.js +0 -156
  205. package/dist/errors.d.ts +0 -30
  206. package/dist/errors.js +0 -63
  207. package/dist/health.d.ts +0 -180
  208. package/dist/health.js +0 -239
  209. package/dist/lock.d.ts +0 -248
  210. package/dist/lock.js +0 -397
  211. package/dist/logger.d.ts +0 -12
  212. package/dist/logger.js +0 -40
  213. package/dist/pubsub.d.ts +0 -423
  214. package/dist/pubsub.js +0 -537
  215. package/dist/ratelimiter.d.ts +0 -441
  216. package/dist/ratelimiter.js +0 -539
  217. package/dist/session/index.d.ts +0 -23
  218. package/dist/session/index.js +0 -16
  219. package/dist/session/revocation-store.d.ts +0 -176
  220. package/dist/session/revocation-store.js +0 -318
  221. package/dist/session/scripts/cleanup-index.lua +0 -21
  222. package/dist/session/scripts/conditional-update-encrypted.lua +0 -60
  223. package/dist/session/scripts/conditional-update.lua +0 -63
  224. package/dist/session/scripts/create.lua +0 -83
  225. package/dist/session/scripts/delete-by-user.lua +0 -29
  226. package/dist/session/scripts/delete.lua +0 -15
  227. package/dist/session/scripts/enforce-limit.lua +0 -38
  228. package/dist/session/scripts/revoke.lua +0 -61
  229. package/dist/session/scripts/rotate-encrypted.lua +0 -110
  230. package/dist/session/scripts/rotate.lua +0 -122
  231. package/dist/session/scripts/touch-encrypted.lua +0 -89
  232. package/dist/session/scripts/touch.lua +0 -72
  233. package/dist/session/scripts/validate.lua +0 -90
  234. package/dist/session/session-circuit-breaker.d.ts +0 -42
  235. package/dist/session/session-circuit-breaker.js +0 -129
  236. package/dist/session/session-config.d.ts +0 -335
  237. package/dist/session/session-config.js +0 -162
  238. package/dist/session/session-cookie.d.ts +0 -72
  239. package/dist/session/session-cookie.js +0 -101
  240. package/dist/session/session-encryption.d.ts +0 -87
  241. package/dist/session/session-encryption.js +0 -139
  242. package/dist/session/session-errors.d.ts +0 -85
  243. package/dist/session/session-errors.js +0 -145
  244. package/dist/session/session-health.d.ts +0 -38
  245. package/dist/session/session-health.js +0 -60
  246. package/dist/session/session-keys.d.ts +0 -51
  247. package/dist/session/session-keys.js +0 -113
  248. package/dist/session/session-manager.d.ts +0 -73
  249. package/dist/session/session-manager.js +0 -94
  250. package/dist/session/session-metrics.d.ts +0 -33
  251. package/dist/session/session-metrics.js +0 -112
  252. package/dist/session/session-repository.d.ts +0 -161
  253. package/dist/session/session-repository.js +0 -683
  254. package/dist/session/session-scripts.d.ts +0 -36
  255. package/dist/session/session-scripts.js +0 -130
  256. package/dist/session/session-serializer.d.ts +0 -42
  257. package/dist/session/session-serializer.js +0 -248
  258. package/dist/session/session-service.d.ts +0 -104
  259. package/dist/session/session-service.js +0 -611
  260. package/dist/session/session-token.d.ts +0 -38
  261. package/dist/session/session-token.js +0 -86
  262. package/dist/session/session-types.d.ts +0 -253
  263. package/dist/session/session-types.js +0 -16
  264. package/dist/types.d.ts +0 -924
  265. package/dist/types.js +0 -151
  266. package/dist/utils/deepmerge.d.ts +0 -9
  267. package/dist/utils/deepmerge.js +0 -61
package/dist/health.js DELETED
@@ -1,239 +0,0 @@
1
- import { defaultLogger } from './logger.js';
2
- export class HealthChecker {
3
- client;
4
- logger;
5
- timer = null;
6
- callbacks = [];
7
- lastStatus = null;
8
- /**
9
- * Creates a health checker instance.
10
- *
11
- * @param client - The underlying {@link RedisClientWrapper}.
12
- * @param logger - Optional pino-compatible logger; defaults to `console`.
13
- *
14
- * @example
15
- * ```ts
16
- * const health = new HealthChecker(client);
17
- * ```
18
- */
19
- constructor(client, logger = defaultLogger) {
20
- this.client = client;
21
- this.logger = logger.child({ component: 'HealthChecker' });
22
- }
23
- /**
24
- * Starts periodic health checks.
25
- *
26
- * **Behavior:**
27
- * - If a timer is already running, it is cleared and replaced with the new interval.
28
- * - Health checks run at the specified `interval` in milliseconds.
29
- * - Each check runs asynchronously; errors are logged but do not stop the interval.
30
- * - The first check runs immediately when `start()` is called (depending on setInterval timing).
31
- *
32
- * **Parameters:**
33
- * - `interval` - Check interval in milliseconds. Default: `10000` (10 seconds).
34
- *
35
- * @example
36
- * ```ts
37
- * // Check every 5 seconds
38
- * health.start(5000);
39
- *
40
- * // Check every 30 seconds (default)
41
- * health.start();
42
- * ```
43
- *
44
- * @returns `void`
45
- */
46
- start(interval = 10000) {
47
- if (this.timer) {
48
- clearInterval(this.timer);
49
- }
50
- this.timer = setInterval(() => {
51
- this.check().catch((error) => {
52
- this.logger.error('Health check failed:', error);
53
- });
54
- }, interval);
55
- this.logger.info(`Health checker started (interval: ${interval}ms)`);
56
- }
57
- /**
58
- * Stops the health checker.
59
- *
60
- * **Behavior:**
61
- * - Clears the internal timer, stopping further health checks.
62
- * - Logs a warning if no timer was active.
63
- *
64
- * @example
65
- * ```ts
66
- * health.stop();
67
- * ```
68
- *
69
- * @returns `void`
70
- */
71
- stop() {
72
- if (this.timer) {
73
- clearInterval(this.timer);
74
- this.timer = null;
75
- this.logger.info('Health checker stopped');
76
- }
77
- }
78
- /**
79
- * Runs a single health check.
80
- *
81
- * **Behavior:**
82
- * - Performs a PING command to verify Redis connectivity.
83
- * - Attempts to fetch Redis INFO for additional details (connections, memory).
84
- * In cluster mode, INFO may not be available and is silently ignored.
85
- * - Measures latency of the PING command.
86
- * - Updates the internal `lastStatus` and notifies all registered callbacks.
87
- *
88
- * **Returns:**
89
- * - A {@link HealthStatus} object with the current health state.
90
- *
91
- * **Example:**
92
- * ```ts
93
- * const status = await health.check();
94
- * console.log(status.healthy, status.latency);
95
- * // healthy === true, latency === 1.2 (ms)
96
- * ```
97
- *
98
- * **Parameters:**
99
- * - None
100
- *
101
- * @returns Current health status.
102
- */
103
- async check() {
104
- const start = Date.now();
105
- const details = {
106
- ping: false,
107
- };
108
- try {
109
- const ping = await this.client.ping();
110
- details.ping = ping;
111
- // Try to get some info
112
- try {
113
- const info = await this.client.raw.info();
114
- const connections = info.match(/connected_clients:(\d+)/)?.[1];
115
- const memory = info.match(/used_memory_human:([^\n]+)/)?.[1];
116
- if (connections)
117
- details.connections = parseInt(connections, 10);
118
- if (memory)
119
- details.memory = memory.trim();
120
- }
121
- catch {
122
- // Info not available in cluster mode
123
- }
124
- }
125
- catch (error) {
126
- this.logger.error('Health check error:', error);
127
- details.ping = false;
128
- }
129
- const latency = Date.now() - start;
130
- const healthy = details.ping;
131
- const status = {
132
- healthy,
133
- status: healthy ? 'healthy' : 'unhealthy',
134
- latency,
135
- timestamp: new Date(),
136
- details,
137
- };
138
- this.lastStatus = status;
139
- this.notifyCallbacks(status);
140
- return status;
141
- }
142
- /**
143
- * Returns the most recent health check result.
144
- *
145
- * @returns The last {@link HealthStatus}, or `null` before the first check.
146
- *
147
- * @example
148
- * ```ts
149
- * const status = health.getStatus();
150
- * console.log(status?.healthy, status?.latency);
151
- * ```
152
- */
153
- /**
154
- * Returns the most recent health check result.
155
- *
156
- * **Returns:**
157
- * - The last {@link HealthStatus}, or `null` before the first check.
158
- *
159
- * **Example:**
160
- * ```ts
161
- * const status = health.getStatus();
162
- * console.log(status?.healthy, status?.latency);
163
- * ```
164
- *
165
- * **Parameters:**
166
- * - None
167
- *
168
- * @returns The last result, or `null`.
169
- */
170
- getStatus() {
171
- return this.lastStatus;
172
- }
173
- /**
174
- * Registers a callback for health status changes.
175
- *
176
- * **Behavior:**
177
- * - The callback is invoked whenever a health check runs and the status changes.
178
- * - Callbacks are invoked synchronously within the `check()` method.
179
- * - Multiple callbacks can be registered; they are invoked in registration order.
180
- *
181
- * **Parameters:**
182
- * - `callback` - A function receiving a {@link HealthStatus} object.
183
- *
184
- * @example
185
- * ```ts
186
- * health.onChange((status) => {
187
- * console.log(`Health status: ${status.status}, latency: ${status.latency}ms`);
188
- * });
189
- * ```
190
- *
191
- * @returns `void`
192
- */
193
- onChange(callback) {
194
- this.callbacks.push(callback);
195
- }
196
- notifyCallbacks(status) {
197
- for (const callback of this.callbacks) {
198
- try {
199
- callback(status);
200
- }
201
- catch (error) {
202
- this.logger.error('Callback error:', error);
203
- }
204
- }
205
- }
206
- /**
207
- * Waits until the Redis connection is healthy.
208
- *
209
- * **Behavior:**
210
- * - Polls {@link check} at 1-second intervals.
211
- * - Returns `true` as soon as `status.healthy` is `true`.
212
- * - Returns `false` if the timeout is reached without becoming healthy.
213
- *
214
- * **Parameters:**
215
- * - `timeout` - Maximum time to wait in milliseconds. Default: `30000` (30 seconds).
216
- *
217
- * **Returns:**
218
- * - `true` if the connection became healthy within the timeout.
219
- * - `false` if the timeout was reached without the connection becoming healthy.
220
- *
221
- * **Example:**
222
- * ```ts
223
- * const healthy = await health.waitForHealthy(10000);
224
- * // healthy === true if Redis became healthy within 10 seconds
225
- * ```
226
- *
227
- * @returns `true` if became healthy within timeout.
228
- */
229
- async waitForHealthy(timeout = 30000) {
230
- const start = Date.now();
231
- while (Date.now() - start < timeout) {
232
- const status = await this.check();
233
- if (status.healthy)
234
- return true;
235
- await new Promise(resolve => setTimeout(resolve, 1000));
236
- }
237
- return false;
238
- }
239
- }
package/dist/lock.d.ts DELETED
@@ -1,248 +0,0 @@
1
- import { RedisClientWrapper } from './client.js';
2
- import { LoggerLike } from './logger.js';
3
- /**
4
- * Information about a distributed lock.
5
- *
6
- * **Fields:**
7
- * - `locked`: Whether the lock is currently held.
8
- * - `ttl`: Remaining TTL in seconds (when held and TTL set).
9
- * - `lockId`: Unique owner id of the lock.
10
- *
11
- * **Example:**
12
- * ```ts
13
- * const info = await lock.getLockInfo('order:42');
14
- * // { locked: true, ttl: 29, lockId: 'a1b2c3...' }
15
- * ```
16
- */
17
- export type LockInfo = {
18
- /** Whether the lock is currently held. */
19
- locked: boolean;
20
- /** Remaining TTL in seconds (when held and TTL set). */
21
- ttl?: number;
22
- /** Unique owner id of the lock. */
23
- lockId?: string;
24
- };
25
- /**
26
- * Options for the distributed lock.
27
- *
28
- * **Fields:**
29
- * - `ttl`: Lock TTL in milliseconds. Default: `30000`.
30
- * - `retryCount`: Number of acquisition attempts. Default: `3`.
31
- * - `retryDelay`: Base delay between retries in ms (grows exponentially). Default: `200`.
32
- *
33
- * **Example:**
34
- * ```ts
35
- * const lock = new DistributedLock(client, { ttl: 10000, retryCount: 5 });
36
- * ```
37
- */
38
- export interface DistributedLockOptions {
39
- /** Lock TTL in milliseconds. Default: `30000`. */
40
- ttl?: number;
41
- /** Number of acquisition attempts. Default: `3`. */
42
- retryCount?: number;
43
- /** Base delay between retries in ms (grows exponentially). Default: `200`. */
44
- retryDelay?: number;
45
- }
46
- /**
47
- * Distributed mutual-exclusion lock backed by Redis.
48
- *
49
- * Works in standalone, sentinel and cluster modes. Acquisition uses atomic
50
- * `SET ... PX NX`; release and extension use Lua scripts so only the lock owner
51
- * can release or extend. `withLock` auto-extends the lock at half TTL while the
52
- * critical section runs and always releases afterwards.
53
- *
54
- * @example
55
- * ```ts
56
- * const lock = new DistributedLock(client, { ttl: 30000, retryCount: 5 });
57
- * const acquired = await lock.acquire('order:42');
58
- * if (acquired) {
59
- * try {
60
- * // critical section
61
- * } finally {
62
- * await lock.release('order:42');
63
- * }
64
- * }
65
- * ```
66
- */
67
- export declare class DistributedLock {
68
- private client;
69
- private logger;
70
- private defaultTTL;
71
- private defaultRetryCount;
72
- private defaultRetryDelay;
73
- /**
74
- * Creates a distributed lock bound to a Redis client.
75
- *
76
- * @param client - The underlying {@link RedisClientWrapper}.
77
- * @param logger - Optional pino-compatible logger; defaults to `console`.
78
- * @param options - Defaults for `ttl` (ms), `retryCount` and `retryDelay`.
79
- *
80
- * @example
81
- * ```ts
82
- * const lock = new DistributedLock(client, { ttl: 10000, retryCount: 3 });
83
- * ```
84
- */
85
- constructor(client: RedisClientWrapper, logger?: LoggerLike, options?: Partial<DistributedLockOptions>);
86
- private getLockKey;
87
- private generateLockId;
88
- private executeWithRetry;
89
- /**
90
- * Attempts to acquire the lock for a key.
91
- *
92
- * Uses atomic `SET lock:<key> <id> PX <ttl> NX` with exponential backoff
93
- * retries. Locks expire automatically after `ttl` ms, so a crashed holder
94
- * never blocks others forever.
95
- *
96
- * @param key - The resource to lock, e.g. `'order:42'` (stored as `lock:order:42`).
97
- * @param ttl - Lock TTL in milliseconds (default: `30000`).
98
- *
99
- * @returns `true` when the lock was acquired.
100
- *
101
- * @example
102
- * ```ts
103
- * const acquired = await lock.acquire('order:42', 10000);
104
- * // acquired === true when lock was successfully acquired
105
- * ```
106
- */
107
- acquire(key: string, ttl?: number): Promise<boolean>;
108
- /**
109
- * Releases the lock, but only if this process still owns it.
110
- *
111
- * Uses an atomic Lua check-and-delete so a lock whose TTL expired (and was
112
- * re-acquired by someone else) is never removed by the old owner.
113
- *
114
- * @param key - The locked resource.
115
- *
116
- * @returns `true` if the lock was released, `false` if not owned or missing.
117
- *
118
- * @example
119
- * ```ts
120
- * await lock.release('order:42');
121
- * ```
122
- */
123
- release(key: string): Promise<boolean>;
124
- /**
125
- * Force-releases a lock without checking ownership.
126
- *
127
- * Use with care: only for emergency cleanup or when the holder is known to
128
- * be gone. This is what `withLock` falls back to when a normal release fails.
129
- *
130
- * @param key - The locked resource.
131
- *
132
- * @returns `true` if a lock existed and was deleted.
133
- *
134
- * @example
135
- * ```ts
136
- * await lock.releaseForce('order:42');
137
- * ```
138
- */
139
- releaseForce(key: string): Promise<boolean>;
140
- /**
141
- * Extends the TTL of a lock this process still owns.
142
- *
143
- * Uses an atomic Lua script so a re-acquired lock is never extended by the
144
- * old owner.
145
- *
146
- * @param key - The locked resource.
147
- * @param ttl - New TTL in milliseconds (default: `30000`).
148
- *
149
- * @returns `true` if the lock was extended.
150
- *
151
- * @example
152
- * ```ts
153
- * const extended = await lock.extend('order:42', 30000);
154
- * // extended === true when lock TTL was renewed
155
- * ```
156
- */
157
- extend(key: string, ttl?: number): Promise<boolean>;
158
- /**
159
- * Runs a critical section while holding a lock.
160
- *
161
- * Acquires the lock (with retries), auto-extends it at half TTL while `fn`
162
- * runs, detects a lost lock, and always releases afterwards (force-releasing
163
- * if a normal release fails).
164
- *
165
- * @param key - The resource to lock.
166
- * @param fn - The critical section to run exclusively.
167
- * @param options - Per-call `ttl` (ms), `retryCount`, `retryDelay`.
168
- *
169
- * @returns The return value of `fn`.
170
- *
171
- * @throws {@link RedisError} with code `LOCK_ACQUISITION_FAILED` when the lock
172
- * cannot be acquired, or `LOCK_LOST` when the lock expired mid-execution.
173
- *
174
- * @example
175
- * ```ts
176
- * const result = await lock.withLock('inventory:sku-1', async () => {
177
- * return await updateStock();
178
- * });
179
- * ```
180
- */
181
- withLock<T>(key: string, fn: () => Promise<T>, options?: DistributedLockOptions): Promise<T>;
182
- /**
183
- * Checks whether a lock is currently held.
184
- *
185
- * @param key - The locked resource.
186
- *
187
- * @returns `true` if the lock exists (held by anyone).
188
- *
189
- * @example
190
- * ```ts
191
- * const busy = await lock.isLocked('order:42');
192
- * ```
193
- */
194
- isLocked(key: string): Promise<boolean>;
195
- /**
196
- * Returns details about a lock.
197
- *
198
- * @param key - The locked resource.
199
- *
200
- * @returns `{ locked: false }` when not held, otherwise `{ locked: true, ttl, lockId }`.
201
- *
202
- * @example
203
- * ```ts
204
- * const info = await lock.getLockInfo('order:42');
205
- * // { locked: true, ttl: 29, lockId: 'a1b2c3...' }
206
- * ```
207
- */
208
- getLockInfo(key: string): Promise<LockInfo>;
209
- /**
210
- * Returns the owner id of a lock.
211
- *
212
- * @param key - The locked resource.
213
- *
214
- * @returns The lock id (random hex token), or `null` when not held.
215
- *
216
- * @example
217
- * ```ts
218
- * const owner = await lock.getLockOwner('order:42');
219
- * ```
220
- */
221
- getLockOwner(key: string): Promise<string | null>;
222
- /**
223
- * Returns the remaining TTL of a lock in seconds.
224
- *
225
- * @param key - The locked resource.
226
- *
227
- * @returns Remaining seconds (`0` when not held or expired).
228
- *
229
- * @example
230
- * ```ts
231
- * const remaining = await lock.getLockTTL('order:42');
232
- * ```
233
- */
234
- getLockTTL(key: string): Promise<number>;
235
- /**
236
- * Deletes every lock key (`lock:*`) from Redis.
237
- *
238
- * Intended for tests and emergency recovery only.
239
- *
240
- * @returns The number of deleted locks.
241
- *
242
- * @example
243
- * ```ts
244
- * const removed = await lock.cleanupAll();
245
- * ```
246
- */
247
- cleanupAll(): Promise<number>;
248
- }