ioredis-toolkit 0.0.8 → 0.0.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.
package/dist/cache.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { RedisClientWrapper } from './client.js';
2
- import { CacheOptions, CacheInputConfig } from './types.js';
3
- import { LoggerLike } from './logger.js';
1
+ import { RedisClientWrapper } from "./client.js";
2
+ import { CacheOptions, CacheInputConfig } from "./types.js";
3
+ import { LoggerLike } from "./logger.js";
4
4
  /**
5
5
  * Cache layer on top of {@link RedisClientWrapper} with JSON serialization,
6
6
  * optional gzip compression and namespace support.
@@ -20,6 +20,7 @@ export declare class Cache {
20
20
  private logger;
21
21
  private defaultTTL;
22
22
  private compressionThreshold;
23
+ private namespace;
23
24
  /**
24
25
  * Creates a cache bound to a Redis client.
25
26
  *
@@ -31,6 +32,7 @@ export declare class Cache {
31
32
  * applied when no per-call TTL is specified.
32
33
  * - `compressionThreshold` (number, optional, default: `1024`) - Byte threshold
33
34
  * above which values are gzip-compressed transparently.
35
+ * - `namespace` (string, optional, default: `''`) - Namespace prefix for all keys.
34
36
  * - `logger` - Optional pino-compatible logger. Supports `trace/debug/info/warn/error/fatal`
35
37
  * levels and `child()` for namespace logging. Defaults to `console`.
36
38
  *
@@ -39,12 +41,13 @@ export declare class Cache {
39
41
  *
40
42
  * **Example:**
41
43
  * ```ts
42
- * const cache = new Cache(client, { defaultTTL: 600, compressionThreshold: 2048 });
44
+ * const cache = new Cache(client, { defaultTTL: 600, compressionThreshold: 2048, namespace: 'myapp' });
43
45
  * ```
44
46
  */
45
47
  constructor(client: RedisClientWrapper, config: CacheInputConfig, logger?: LoggerLike);
46
48
  private serialize;
47
49
  private deserialize;
50
+ private get getNamespace();
48
51
  private getKey;
49
52
  /**
50
53
  * Reads a cached value.
@@ -132,7 +135,7 @@ export declare class Cache {
132
135
  *
133
136
  * **Type Parameters:**
134
137
  * - `T` - The type of the value being stored. Can be any serializable JavaScript value.
135
- *
138
+ *
136
139
  * **Returns:**
137
140
  * - `true` when the value was stored successfully (`result === 'OK'`).
138
141
  *
@@ -266,36 +269,36 @@ export declare class Cache {
266
269
  * ```
267
270
  */
268
271
  /**
269
- * Reads multiple cache keys in one call.
270
- *
271
- * **Behavior:**
272
- * - Cluster-safe: keys are grouped by hash slot under the hood, avoiding CROSS-SLOT errors.
273
- * - Values are deserialized from JSON when stored as JSON. Strings/numbers/buffers
274
- * are returned as-is.
275
- * - Missing keys return `null` in the corresponding position.
276
- *
277
- * **Type Parameters:**
278
- * - `T` - The expected type of each returned value. When the stored value is JSON,
279
- * it will be parsed and coerced to `T`.
280
- *
281
- * **Returns:**
282
- * - An array of values in the same order as the input `keys`. Each element is `T | null`.
283
- * `null` indicates the key did not exist.
284
- *
285
- * **Example:**
286
- * ```ts
287
- * const [a, b] = await cache.mget(['user:1', 'user:2']);
288
- * // a === { name: 'alice' }, b === { name: 'bob' }
289
- * ```
290
- *
291
- * **Parameters:**
292
- * - `keys` - Cache keys to read. Will have the namespace prefix applied automatically
293
- * if a namespace is configured.
294
- * - `namespace` - Optional namespace prefix applied to every key. When provided,
295
- * each key is internally transformed to `${namespace}:${key}`.
296
- *
297
- * @returns Values in input order; `null` for missing keys.
298
- */
272
+ * Reads multiple cache keys in one call.
273
+ *
274
+ * **Behavior:**
275
+ * - Cluster-safe: keys are grouped by hash slot under the hood, avoiding CROSS-SLOT errors.
276
+ * - Values are deserialized from JSON when stored as JSON. Strings/numbers/buffers
277
+ * are returned as-is.
278
+ * - Missing keys return `null` in the corresponding position.
279
+ *
280
+ * **Type Parameters:**
281
+ * - `T` - The expected type of each returned value. When the stored value is JSON,
282
+ * it will be parsed and coerced to `T`.
283
+ *
284
+ * **Returns:**
285
+ * - An array of values in the same order as the input `keys`. Each element is `T | null`.
286
+ * `null` indicates the key did not exist.
287
+ *
288
+ * **Example:**
289
+ * ```ts
290
+ * const [a, b] = await cache.mget(['user:1', 'user:2']);
291
+ * // a === { name: 'alice' }, b === { name: 'bob' }
292
+ * ```
293
+ *
294
+ * **Parameters:**
295
+ * - `keys` - Cache keys to read. Will have the namespace prefix applied automatically
296
+ * if a namespace is configured.
297
+ * - `namespace` - Optional namespace prefix applied to every key. When provided,
298
+ * each key is internally transformed to `${namespace}:${key}`.
299
+ *
300
+ * @returns Values in input order; `null` for missing keys.
301
+ */
299
302
  mget<T = any>(keys: string[], namespace?: string): Promise<(T | null)[]>;
300
303
  /**
301
304
  * Stores multiple key/value entries in one call.
@@ -366,7 +369,7 @@ export declare class Cache {
366
369
  *
367
370
  * **Returns:**
368
371
  * - `true` if the key existed and was deleted.
369
- *
372
+ *
370
373
  * **Example:**
371
374
  * ```ts
372
375
  * const removed = await cache.delete('user:1');
package/dist/cache.js CHANGED
@@ -1,6 +1,6 @@
1
- import zlib from 'node:zlib';
2
- import { promisify } from 'node:util';
3
- import { defaultLogger } from './logger.js';
1
+ import zlib from "node:zlib";
2
+ import { promisify } from "node:util";
3
+ import { defaultLogger } from "./logger.js";
4
4
  const gzip = promisify(zlib.gzip);
5
5
  const gunzip = promisify(zlib.gunzip);
6
6
  /**
@@ -23,6 +23,7 @@ export class Cache {
23
23
  // private config: RedisConfig;
24
24
  defaultTTL;
25
25
  compressionThreshold;
26
+ namespace;
26
27
  /**
27
28
  * Creates a cache bound to a Redis client.
28
29
  *
@@ -34,6 +35,7 @@ export class Cache {
34
35
  * applied when no per-call TTL is specified.
35
36
  * - `compressionThreshold` (number, optional, default: `1024`) - Byte threshold
36
37
  * above which values are gzip-compressed transparently.
38
+ * - `namespace` (string, optional, default: `''`) - Namespace prefix for all keys.
37
39
  * - `logger` - Optional pino-compatible logger. Supports `trace/debug/info/warn/error/fatal`
38
40
  * levels and `child()` for namespace logging. Defaults to `console`.
39
41
  *
@@ -42,15 +44,16 @@ export class Cache {
42
44
  *
43
45
  * **Example:**
44
46
  * ```ts
45
- * const cache = new Cache(client, { defaultTTL: 600, compressionThreshold: 2048 });
47
+ * const cache = new Cache(client, { defaultTTL: 600, compressionThreshold: 2048, namespace: 'myapp' });
46
48
  * ```
47
49
  */
48
50
  constructor(client, config, logger = defaultLogger) {
49
51
  this.client = client;
50
- this.logger = logger.child({ component: 'Cache' });
52
+ this.logger = logger.child({ component: "Cache" });
51
53
  // this.config = config;
52
54
  this.defaultTTL = config.defaultTTL || 3600;
53
55
  this.compressionThreshold = config.compressionThreshold || 1024;
56
+ this.namespace = config.namespace || "";
54
57
  }
55
58
  async serialize(value) {
56
59
  // Convert to Buffer
@@ -58,10 +61,10 @@ export class Cache {
58
61
  if (Buffer.isBuffer(value)) {
59
62
  data = value;
60
63
  }
61
- else if (typeof value === 'string') {
64
+ else if (typeof value === "string") {
62
65
  data = Buffer.from(value);
63
66
  }
64
- else if (typeof value === 'number' || typeof value === 'boolean') {
67
+ else if (typeof value === "number" || typeof value === "boolean") {
65
68
  data = Buffer.from(String(value));
66
69
  }
67
70
  else {
@@ -75,7 +78,7 @@ export class Cache {
75
78
  return { data: compressed, compressed: true };
76
79
  }
77
80
  catch (error) {
78
- this.logger.warn('Compression failed, storing uncompressed');
81
+ this.logger.warn("Compression failed, storing uncompressed");
79
82
  return { data, compressed: false };
80
83
  }
81
84
  }
@@ -88,14 +91,14 @@ export class Cache {
88
91
  buffer = await gunzip(data);
89
92
  }
90
93
  catch (error) {
91
- this.logger.warn('Decompression failed, trying raw data');
94
+ this.logger.warn("Decompression failed, trying raw data");
92
95
  // Attempt to use raw data if decompression fails
93
96
  }
94
97
  }
95
98
  // Try to parse as JSON if it looks like JSON
96
99
  const str = buffer.toString();
97
100
  try {
98
- if (str.startsWith('{') || str.startsWith('[')) {
101
+ if (str.startsWith("{") || str.startsWith("[")) {
99
102
  return JSON.parse(str);
100
103
  }
101
104
  }
@@ -104,8 +107,14 @@ export class Cache {
104
107
  }
105
108
  return str;
106
109
  }
110
+ get getNamespace() {
111
+ return this.namespace?.trim() ? `${this.namespace}:` : "";
112
+ }
107
113
  getKey(key, namespace) {
108
- return namespace ? `${namespace}:${key}` : key;
114
+ if (namespace?.trim()) {
115
+ return `${this.getNamespace}${namespace.trim()}:${key}`;
116
+ }
117
+ return `${this.getNamespace}${key}`;
109
118
  }
110
119
  /**
111
120
  * Reads a cached value.
@@ -170,7 +179,7 @@ export class Cache {
170
179
  // Check if stored with metadata
171
180
  const parsed = JSON.parse(raw);
172
181
  if (parsed._compressed && parsed._data) {
173
- const data = Buffer.from(parsed._data, 'base64');
182
+ const data = Buffer.from(parsed._data, "base64");
174
183
  return this.deserialize(data, parsed._compressed);
175
184
  }
176
185
  // Legacy format - try to parse as JSON
@@ -212,7 +221,7 @@ export class Cache {
212
221
  *
213
222
  * **Type Parameters:**
214
223
  * - `T` - The type of the value being stored. Can be any serializable JavaScript value.
215
- *
224
+ *
216
225
  * **Returns:**
217
226
  * - `true` when the value was stored successfully (`result === 'OK'`).
218
227
  *
@@ -250,7 +259,7 @@ export class Cache {
250
259
  // Store with metadata
251
260
  rawValue = JSON.stringify({
252
261
  _compressed: true,
253
- _data: data.toString('base64'),
262
+ _data: data.toString("base64"),
254
263
  });
255
264
  }
256
265
  else {
@@ -258,7 +267,7 @@ export class Cache {
258
267
  }
259
268
  }
260
269
  else {
261
- if (typeof value === 'string') {
270
+ if (typeof value === "string") {
262
271
  rawValue = value;
263
272
  }
264
273
  else if (Buffer.isBuffer(value)) {
@@ -269,11 +278,15 @@ export class Cache {
269
278
  }
270
279
  }
271
280
  const result = await this.client.set(fullKey, rawValue, ttl);
272
- this.logger.debug('Cache set', { key: fullKey, ttl, compressed: shouldCompress });
273
- return result === 'OK';
281
+ this.logger.debug("Cache set", {
282
+ key: fullKey,
283
+ ttl,
284
+ compressed: shouldCompress,
285
+ });
286
+ return result === "OK";
274
287
  }
275
288
  catch (error) {
276
- this.logger.error('Cache set failed:', error);
289
+ this.logger.error("Cache set failed:", error);
277
290
  return false;
278
291
  }
279
292
  }
@@ -324,12 +337,12 @@ export class Cache {
324
337
  const fullKey = this.getKey(key, options.namespace);
325
338
  const ttl = options.ttl || this.defaultTTL;
326
339
  try {
327
- const rawValue = typeof value === 'string' ? value : JSON.stringify(value);
340
+ const rawValue = typeof value === "string" ? value : JSON.stringify(value);
328
341
  const result = await this.client.setnx(fullKey, rawValue, ttl);
329
342
  return result === 1;
330
343
  }
331
344
  catch (error) {
332
- this.logger.error('Cache setNX failed:', error);
345
+ this.logger.error("Cache setNX failed:", error);
333
346
  return false;
334
347
  }
335
348
  }
@@ -384,12 +397,12 @@ export class Cache {
384
397
  const fullKey = this.getKey(key, options.namespace);
385
398
  const ttl = options.ttl || this.defaultTTL;
386
399
  try {
387
- const rawValue = typeof value === 'string' ? value : JSON.stringify(value);
400
+ const rawValue = typeof value === "string" ? value : JSON.stringify(value);
388
401
  const result = await this.client.setexnx(fullKey, rawValue, ttl);
389
- return result === 'OK';
402
+ return result === "OK";
390
403
  }
391
404
  catch (error) {
392
- this.logger.error('Cache setEXNX failed:', error);
405
+ this.logger.error("Cache setEXNX failed:", error);
393
406
  return false;
394
407
  }
395
408
  }
@@ -430,38 +443,38 @@ export class Cache {
430
443
  * ```
431
444
  */
432
445
  /**
433
- * Reads multiple cache keys in one call.
434
- *
435
- * **Behavior:**
436
- * - Cluster-safe: keys are grouped by hash slot under the hood, avoiding CROSS-SLOT errors.
437
- * - Values are deserialized from JSON when stored as JSON. Strings/numbers/buffers
438
- * are returned as-is.
439
- * - Missing keys return `null` in the corresponding position.
440
- *
441
- * **Type Parameters:**
442
- * - `T` - The expected type of each returned value. When the stored value is JSON,
443
- * it will be parsed and coerced to `T`.
444
- *
445
- * **Returns:**
446
- * - An array of values in the same order as the input `keys`. Each element is `T | null`.
447
- * `null` indicates the key did not exist.
448
- *
449
- * **Example:**
450
- * ```ts
451
- * const [a, b] = await cache.mget(['user:1', 'user:2']);
452
- * // a === { name: 'alice' }, b === { name: 'bob' }
453
- * ```
454
- *
455
- * **Parameters:**
456
- * - `keys` - Cache keys to read. Will have the namespace prefix applied automatically
457
- * if a namespace is configured.
458
- * - `namespace` - Optional namespace prefix applied to every key. When provided,
459
- * each key is internally transformed to `${namespace}:${key}`.
460
- *
461
- * @returns Values in input order; `null` for missing keys.
462
- */
446
+ * Reads multiple cache keys in one call.
447
+ *
448
+ * **Behavior:**
449
+ * - Cluster-safe: keys are grouped by hash slot under the hood, avoiding CROSS-SLOT errors.
450
+ * - Values are deserialized from JSON when stored as JSON. Strings/numbers/buffers
451
+ * are returned as-is.
452
+ * - Missing keys return `null` in the corresponding position.
453
+ *
454
+ * **Type Parameters:**
455
+ * - `T` - The expected type of each returned value. When the stored value is JSON,
456
+ * it will be parsed and coerced to `T`.
457
+ *
458
+ * **Returns:**
459
+ * - An array of values in the same order as the input `keys`. Each element is `T | null`.
460
+ * `null` indicates the key did not exist.
461
+ *
462
+ * **Example:**
463
+ * ```ts
464
+ * const [a, b] = await cache.mget(['user:1', 'user:2']);
465
+ * // a === { name: 'alice' }, b === { name: 'bob' }
466
+ * ```
467
+ *
468
+ * **Parameters:**
469
+ * - `keys` - Cache keys to read. Will have the namespace prefix applied automatically
470
+ * if a namespace is configured.
471
+ * - `namespace` - Optional namespace prefix applied to every key. When provided,
472
+ * each key is internally transformed to `${namespace}:${key}`.
473
+ *
474
+ * @returns Values in input order; `null` for missing keys.
475
+ */
463
476
  async mget(keys, namespace) {
464
- const fullKeys = keys.map(k => this.getKey(k, namespace));
477
+ const fullKeys = keys.map((k) => this.getKey(k, namespace));
465
478
  const raw = await this.client.mgetClusterAware(fullKeys);
466
479
  return Promise.all(raw.map(async (item) => {
467
480
  if (!item)
@@ -469,7 +482,7 @@ export class Cache {
469
482
  try {
470
483
  const parsed = JSON.parse(item);
471
484
  if (parsed._compressed && parsed._data) {
472
- const data = Buffer.from(parsed._data, 'base64');
485
+ const data = Buffer.from(parsed._data, "base64");
473
486
  return this.deserialize(data, parsed._compressed);
474
487
  }
475
488
  return parsed;
@@ -558,7 +571,7 @@ export class Cache {
558
571
  const groups = new Map();
559
572
  for (const [key, value] of Object.entries(entries)) {
560
573
  const fullKey = this.getKey(key, namespace);
561
- const rawValue = typeof value === 'string' ? value : JSON.stringify(value);
574
+ const rawValue = typeof value === "string" ? value : JSON.stringify(value);
562
575
  const slot = this.client.calculateSlot(fullKey);
563
576
  if (!groups.has(slot)) {
564
577
  groups.set(slot, []);
@@ -568,17 +581,17 @@ export class Cache {
568
581
  for (const group of groups.values()) {
569
582
  const pipeline = this.client.pipeline();
570
583
  for (const [fullKey, rawValue] of group) {
571
- pipeline.set(fullKey, rawValue, 'EX', ttl);
584
+ pipeline.set(fullKey, rawValue, "EX", ttl);
572
585
  }
573
586
  const results = await pipeline.exec();
574
- if (!results?.every((result) => result[1] === 'OK')) {
587
+ if (!results?.every((result) => result[1] === "OK")) {
575
588
  return false;
576
589
  }
577
590
  }
578
591
  return true;
579
592
  }
580
593
  catch (error) {
581
- this.logger.error('Cache mset failed:', error);
594
+ this.logger.error("Cache mset failed:", error);
582
595
  return false;
583
596
  }
584
597
  }
@@ -603,7 +616,7 @@ export class Cache {
603
616
  *
604
617
  * **Returns:**
605
618
  * - `true` if the key existed and was deleted.
606
- *
619
+ *
607
620
  * **Example:**
608
621
  * ```ts
609
622
  * const removed = await cache.delete('user:1');
@@ -912,7 +925,7 @@ export class Cache {
912
925
  */
913
926
  async hset(key, field, value, namespace) {
914
927
  const fullKey = this.getKey(key, namespace);
915
- const rawValue = typeof value === 'string' ? value : JSON.stringify(value);
928
+ const rawValue = typeof value === "string" ? value : JSON.stringify(value);
916
929
  const result = await this.client.hset(fullKey, field, rawValue);
917
930
  return result === 1;
918
931
  }
@@ -1006,7 +1019,7 @@ export class Cache {
1006
1019
  * @returns The number of deleted keys.
1007
1020
  */
1008
1021
  async deletePattern(pattern, namespace) {
1009
- const fullPattern = namespace ? `${namespace}:${pattern}` : pattern;
1022
+ const fullPattern = this.getKey(pattern, namespace);
1010
1023
  let deleted = 0;
1011
1024
  for await (const key of this.client.scanIterator(fullPattern)) {
1012
1025
  const result = await this.client.del(key);
@@ -1055,7 +1068,7 @@ export class Cache {
1055
1068
  * @returns Matching keys.
1056
1069
  */
1057
1070
  async keys(pattern, namespace) {
1058
- const fullPattern = namespace ? `${namespace}:${pattern}` : pattern;
1071
+ const fullPattern = this.getKey(pattern, namespace);
1059
1072
  const keys = [];
1060
1073
  for await (const key of this.client.scanIterator(fullPattern)) {
1061
1074
  keys.push(key);
@@ -1097,6 +1110,6 @@ export class Cache {
1097
1110
  * @returns The number of deleted keys.
1098
1111
  */
1099
1112
  async clearNamespace(namespace) {
1100
- return this.deletePattern('*', namespace);
1113
+ return this.deletePattern("*", namespace);
1101
1114
  }
1102
1115
  }
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Cluster, Redis as RedisClient } from "ioredis";
2
- import { RateLimitOptionsInput, type ClusterInfo, type ClusterSlotRange, type ConnectionStatus, type RedisConfigInput, type RedisMode, DistributedLockInputOptions, CacheInputConfig } from "./types.js";
2
+ import { RateLimitOptionsInput, type ClusterInfo, type ClusterRedisConfig, type ClusterSlotRange, type ConnectionStatus, type RedisConfig, type RedisConfigInput, type RedisMode, type SentinelRedisConfig, type StandaloneRedisConfig, DistributedLockInputOptions, CacheInputConfig } from "./types.js";
3
3
  import { type LoggerLike } from "./logger.js";
4
4
  import { Cache } from "./cache.js";
5
5
  import { PubSub } from "./pubsub.js";
@@ -48,6 +48,9 @@ type DeletePatternOptions = {
48
48
  batchSize?: number;
49
49
  scanCount?: number;
50
50
  };
51
+ export declare function isClusterConfig(config: RedisConfig): config is ClusterRedisConfig;
52
+ export declare function isSentinelConfig(config: RedisConfig): config is SentinelRedisConfig;
53
+ export declare function isStandaloneConfig(config: RedisConfig): config is StandaloneRedisConfig;
51
54
  /**
52
55
  * Production-grade Redis client wrapper supporting:
53
56
  *
package/dist/client.js CHANGED
@@ -15,13 +15,13 @@ import { deepMerge } from "./utils/deepmerge.js";
15
15
  // ============================================================================
16
16
  // Type Guards
17
17
  // ============================================================================
18
- function isClusterConfig(config) {
18
+ export function isClusterConfig(config) {
19
19
  return config.mode === "cluster";
20
20
  }
21
- function isSentinelConfig(config) {
21
+ export function isSentinelConfig(config) {
22
22
  return config.mode === "sentinel";
23
23
  }
24
- function isStandaloneConfig(config) {
24
+ export function isStandaloneConfig(config) {
25
25
  return config.mode === "standalone";
26
26
  }
27
27
  // ============================================================================
@@ -295,7 +295,6 @@ export class RedisClientWrapper {
295
295
  revocationStore: options.revocationStore ?? this.revocationStore,
296
296
  };
297
297
  this._session = createSessionManager(params);
298
- void this._session.init();
299
298
  this.config.sessionOptions = params;
300
299
  }
301
300
  return this._session;
package/dist/lock.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { RedisClientWrapper } from './client.js';
2
2
  import { LoggerLike } from './logger.js';
3
+ import { DistributedLockOptions, LockInfo } from './types.js';
3
4
  /**
4
5
  * Information about a distributed lock.
5
6
  *
@@ -14,14 +15,6 @@ import { LoggerLike } from './logger.js';
14
15
  * // { locked: true, ttl: 29, lockId: 'a1b2c3...' }
15
16
  * ```
16
17
  */
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
18
  /**
26
19
  * Options for the distributed lock.
27
20
  *
@@ -35,14 +28,6 @@ export type LockInfo = {
35
28
  * const lock = new DistributedLock(client, { ttl: 10000, retryCount: 5 });
36
29
  * ```
37
30
  */
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
31
  /**
47
32
  * Distributed mutual-exclusion lock backed by Redis.
48
33
  *
package/dist/lock.js CHANGED
@@ -1,6 +1,49 @@
1
1
  import { RedisError } from './errors.js';
2
2
  import { randomBytes } from 'node:crypto';
3
3
  import { defaultLogger } from './logger.js';
4
+ /**
5
+ * Information about a distributed lock.
6
+ *
7
+ * **Fields:**
8
+ * - `locked`: Whether the lock is currently held.
9
+ * - `ttl`: Remaining TTL in seconds (when held and TTL set).
10
+ * - `lockId`: Unique owner id of the lock.
11
+ *
12
+ * **Example:**
13
+ * ```ts
14
+ * const info = await lock.getLockInfo('order:42');
15
+ * // { locked: true, ttl: 29, lockId: 'a1b2c3...' }
16
+ * ```
17
+ */
18
+ // export type LockInfo = {
19
+ // /** Whether the lock is currently held. */
20
+ // locked: boolean;
21
+ // /** Remaining TTL in seconds (when held and TTL set). */
22
+ // ttl?: number;
23
+ // /** Unique owner id of the lock. */
24
+ // lockId?: string;
25
+ // };
26
+ /**
27
+ * Options for the distributed lock.
28
+ *
29
+ * **Fields:**
30
+ * - `ttl`: Lock TTL in milliseconds. Default: `30000`.
31
+ * - `retryCount`: Number of acquisition attempts. Default: `3`.
32
+ * - `retryDelay`: Base delay between retries in ms (grows exponentially). Default: `200`.
33
+ *
34
+ * **Example:**
35
+ * ```ts
36
+ * const lock = new DistributedLock(client, { ttl: 10000, retryCount: 5 });
37
+ * ```
38
+ */
39
+ // export interface DistributedLockOptions {
40
+ // /** Lock TTL in milliseconds. Default: `30000`. */
41
+ // ttl?: number;
42
+ // /** Number of acquisition attempts. Default: `3`. */
43
+ // retryCount?: number;
44
+ // /** Base delay between retries in ms (grows exponentially). Default: `200`. */
45
+ // retryDelay?: number;
46
+ // }
4
47
  /**
5
48
  * Distributed mutual-exclusion lock backed by Redis.
6
49
  *