commandkit 1.0.0-dev.20250622124751 → 1.0.0-dev.20250622135945

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.
@@ -0,0 +1,9 @@
1
+ const {
2
+ AsyncQueue,
3
+ createAsyncQueue,
4
+ } = require('./dist/utils/useful-stuff/async-queue.js');
5
+
6
+ module.exports = {
7
+ AsyncQueue,
8
+ createAsyncQueue,
9
+ };
@@ -0,0 +1 @@
1
+ export * from './dist/utils/useful-stuff/async-queue.js';
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require('../chunk-nOFOJqeH.js');
2
- const require_version = require('../version-CRg5idya.js');
2
+ const require_version = require('../version-DfdnkNI2.js');
3
3
  const node_fs = require_chunk.__toESM(require("node:fs"));
4
4
  const node_path = require_chunk.__toESM(require("node:path"));
5
5
  const node_child_process = require_chunk.__toESM(require("node:child_process"));
package/dist/index.js CHANGED
@@ -36,7 +36,7 @@ require('./store-CyzliDXj.js');
36
36
  const require_helpers = require('./helpers-DfV6HlgI.js');
37
37
  require('./app-gCenKq8k.js');
38
38
  require('./ILogger-BMIMljYD.js');
39
- const require_version = require('./version-CRg5idya.js');
39
+ const require_version = require('./version-DfdnkNI2.js');
40
40
  const require_feature_flags = require('./feature-flags-CFoqosTw.js');
41
41
  const require_init = require('./init-muFynnQh.js');
42
42
 
@@ -0,0 +1,84 @@
1
+ //#region src/utils/useful-stuff/async-queue.d.ts
2
+ /**
3
+ * Async queue implementation for processing tasks sequentially or with limited concurrency.
4
+ * Useful for rate-limiting, batching, or controlling resource usage.
5
+ */
6
+ interface AsyncQueueOptions {
7
+ /** Maximum number of concurrent tasks. Default: 1 (sequential) */
8
+ concurrency?: number;
9
+ /** Optional callback invoked when all tasks are completed */
10
+ onDrain?: () => void | Promise<void>;
11
+ /** Optional AbortSignal for cancelling the queue */
12
+ signal?: AbortSignal;
13
+ }
14
+ type AsyncQueueTask<T> = () => Promise<T>;
15
+ declare class AsyncQueue {
16
+ private readonly concurrency;
17
+ private readonly onDrain?;
18
+ private readonly signal?;
19
+ private running;
20
+ private paused;
21
+ private aborted;
22
+ private queue;
23
+ constructor(options?: AsyncQueueOptions);
24
+ /**
25
+ * Adds a task to the queue.
26
+ * @param task - The async function to execute.
27
+ * @param signal - Optional AbortSignal for cancelling this specific task.
28
+ * @returns Promise resolving to the result of the task.
29
+ */
30
+ add<T>(task: AsyncQueueTask<T>, signal?: AbortSignal): Promise<T>;
31
+ /**
32
+ * Pauses the queue. No new tasks will be started until resumed.
33
+ */
34
+ pause(): void;
35
+ /**
36
+ * Resumes the queue and processes pending tasks.
37
+ */
38
+ resume(): void;
39
+ /**
40
+ * Aborts the queue, rejecting all pending tasks.
41
+ */
42
+ abort(): void;
43
+ /**
44
+ * Clears all pending tasks from the queue.
45
+ */
46
+ clear(): void;
47
+ /**
48
+ * Returns the number of running tasks.
49
+ */
50
+ getRunning(): number;
51
+ /**
52
+ * Returns the number of pending tasks in the queue.
53
+ */
54
+ getPending(): number;
55
+ /**
56
+ * Returns true if the queue is currently paused.
57
+ */
58
+ isPaused(): boolean;
59
+ /**
60
+ * Returns true if the queue has been aborted.
61
+ */
62
+ isAborted(): boolean;
63
+ private next;
64
+ }
65
+ /**
66
+ * Creates a new async queue instance with the specified configuration.
67
+ * @param options - Configuration options for the async queue.
68
+ * @returns New AsyncQueue instance.
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const controller = new AbortController();
73
+ * const queue = createAsyncQueue({
74
+ * concurrency: 2,
75
+ * signal: controller.signal
76
+ * });
77
+ * queue.add(async () => await doSomething());
78
+ * controller.abort(); // Aborts the queue
79
+ * ```
80
+ */
81
+ declare function createAsyncQueue(options?: AsyncQueueOptions): AsyncQueue;
82
+ //#endregion
83
+ export { AsyncQueue, AsyncQueueOptions, AsyncQueueTask, createAsyncQueue };
84
+ //# sourceMappingURL=async-queue.d.ts.map
@@ -0,0 +1,136 @@
1
+
2
+ //#region src/utils/useful-stuff/async-queue.ts
3
+ var AsyncQueue = class {
4
+ concurrency;
5
+ onDrain;
6
+ signal;
7
+ running = 0;
8
+ paused = false;
9
+ aborted = false;
10
+ queue = [];
11
+ constructor(options = {}) {
12
+ this.concurrency = options.concurrency ?? 1;
13
+ this.onDrain = options.onDrain;
14
+ this.signal = options.signal;
15
+ if (this.signal) this.signal.addEventListener("abort", () => {
16
+ this.abort();
17
+ });
18
+ }
19
+ /**
20
+ * Adds a task to the queue.
21
+ * @param task - The async function to execute.
22
+ * @param signal - Optional AbortSignal for cancelling this specific task.
23
+ * @returns Promise resolving to the result of the task.
24
+ */
25
+ add(task, signal) {
26
+ if (this.aborted) return Promise.reject(new Error("Queue has been aborted"));
27
+ return new Promise((resolve, reject) => {
28
+ const run = async () => {
29
+ if (this.paused || this.aborted) {
30
+ if (this.aborted) reject(new Error("Queue has been aborted"));
31
+ else this.queue.push(run);
32
+ return;
33
+ }
34
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
35
+ reject(new Error("Task was aborted"));
36
+ return;
37
+ }
38
+ this.running++;
39
+ try {
40
+ const result = await task();
41
+ resolve(result);
42
+ } catch (err) {
43
+ reject(err);
44
+ } finally {
45
+ this.running--;
46
+ this.next();
47
+ }
48
+ };
49
+ if (this.running < this.concurrency && !this.paused && !this.aborted) run();
50
+ else this.queue.push(run);
51
+ });
52
+ }
53
+ /**
54
+ * Pauses the queue. No new tasks will be started until resumed.
55
+ */
56
+ pause() {
57
+ this.paused = true;
58
+ }
59
+ /**
60
+ * Resumes the queue and processes pending tasks.
61
+ */
62
+ resume() {
63
+ if (!this.paused) return;
64
+ this.paused = false;
65
+ this.next();
66
+ }
67
+ /**
68
+ * Aborts the queue, rejecting all pending tasks.
69
+ */
70
+ abort() {
71
+ this.aborted = true;
72
+ this.clear();
73
+ }
74
+ /**
75
+ * Clears all pending tasks from the queue.
76
+ */
77
+ clear() {
78
+ this.queue = [];
79
+ }
80
+ /**
81
+ * Returns the number of running tasks.
82
+ */
83
+ getRunning() {
84
+ return this.running;
85
+ }
86
+ /**
87
+ * Returns the number of pending tasks in the queue.
88
+ */
89
+ getPending() {
90
+ return this.queue.length;
91
+ }
92
+ /**
93
+ * Returns true if the queue is currently paused.
94
+ */
95
+ isPaused() {
96
+ return this.paused;
97
+ }
98
+ /**
99
+ * Returns true if the queue has been aborted.
100
+ */
101
+ isAborted() {
102
+ return this.aborted;
103
+ }
104
+ next() {
105
+ if (this.paused || this.aborted) return;
106
+ while (this.running < this.concurrency && this.queue.length > 0) {
107
+ const fn = this.queue.shift();
108
+ if (fn) fn();
109
+ }
110
+ if (this.running === 0 && this.queue.length === 0 && this.onDrain) this.onDrain();
111
+ }
112
+ };
113
+ /**
114
+ * Creates a new async queue instance with the specified configuration.
115
+ * @param options - Configuration options for the async queue.
116
+ * @returns New AsyncQueue instance.
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * const controller = new AbortController();
121
+ * const queue = createAsyncQueue({
122
+ * concurrency: 2,
123
+ * signal: controller.signal
124
+ * });
125
+ * queue.add(async () => await doSomething());
126
+ * controller.abort(); // Aborts the queue
127
+ * ```
128
+ */
129
+ function createAsyncQueue(options) {
130
+ return new AsyncQueue(options);
131
+ }
132
+
133
+ //#endregion
134
+ exports.AsyncQueue = AsyncQueue;
135
+ exports.createAsyncQueue = createAsyncQueue;
136
+ //# sourceMappingURL=async-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-queue.js","names":[],"sources":["../../../src/utils/useful-stuff/async-queue.ts"],"sourcesContent":["/**\n * Async queue implementation for processing tasks sequentially or with limited concurrency.\n * Useful for rate-limiting, batching, or controlling resource usage.\n */\n\nexport interface AsyncQueueOptions {\n /** Maximum number of concurrent tasks. Default: 1 (sequential) */\n concurrency?: number;\n /** Optional callback invoked when all tasks are completed */\n onDrain?: () => void | Promise<void>;\n /** Optional AbortSignal for cancelling the queue */\n signal?: AbortSignal;\n}\n\nexport type AsyncQueueTask<T> = () => Promise<T>;\n\nexport class AsyncQueue {\n private readonly concurrency: number;\n private readonly onDrain?: () => void | Promise<void>;\n private readonly signal?: AbortSignal;\n private running = 0;\n private paused = false;\n private aborted = false;\n private queue: Array<() => void> = [];\n\n constructor(options: AsyncQueueOptions = {}) {\n this.concurrency = options.concurrency ?? 1;\n this.onDrain = options.onDrain;\n this.signal = options.signal;\n\n if (this.signal) {\n this.signal.addEventListener('abort', () => {\n this.abort();\n });\n }\n }\n\n /**\n * Adds a task to the queue.\n * @param task - The async function to execute.\n * @param signal - Optional AbortSignal for cancelling this specific task.\n * @returns Promise resolving to the result of the task.\n */\n public add<T>(task: AsyncQueueTask<T>, signal?: AbortSignal): Promise<T> {\n if (this.aborted) {\n return Promise.reject(new Error('Queue has been aborted'));\n }\n\n return new Promise<T>((resolve, reject) => {\n const run = async () => {\n if (this.paused || this.aborted) {\n if (this.aborted) {\n reject(new Error('Queue has been aborted'));\n } else {\n this.queue.push(run);\n }\n return;\n }\n\n // Check if task-specific signal is aborted\n if (signal?.aborted) {\n reject(new Error('Task was aborted'));\n return;\n }\n\n this.running++;\n try {\n const result = await task();\n resolve(result);\n } catch (err) {\n reject(err);\n } finally {\n this.running--;\n this.next();\n }\n };\n\n if (this.running < this.concurrency && !this.paused && !this.aborted) {\n run();\n } else {\n this.queue.push(run);\n }\n });\n }\n\n /**\n * Pauses the queue. No new tasks will be started until resumed.\n */\n public pause() {\n this.paused = true;\n }\n\n /**\n * Resumes the queue and processes pending tasks.\n */\n public resume() {\n if (!this.paused) return;\n this.paused = false;\n this.next();\n }\n\n /**\n * Aborts the queue, rejecting all pending tasks.\n */\n public abort() {\n this.aborted = true;\n this.clear();\n }\n\n /**\n * Clears all pending tasks from the queue.\n */\n public clear() {\n this.queue = [];\n }\n\n /**\n * Returns the number of running tasks.\n */\n public getRunning(): number {\n return this.running;\n }\n\n /**\n * Returns the number of pending tasks in the queue.\n */\n public getPending(): number {\n return this.queue.length;\n }\n\n /**\n * Returns true if the queue is currently paused.\n */\n public isPaused(): boolean {\n return this.paused;\n }\n\n /**\n * Returns true if the queue has been aborted.\n */\n public isAborted(): boolean {\n return this.aborted;\n }\n\n private next() {\n if (this.paused || this.aborted) return;\n while (this.running < this.concurrency && this.queue.length > 0) {\n const fn = this.queue.shift();\n if (fn) fn();\n }\n if (this.running === 0 && this.queue.length === 0 && this.onDrain) {\n this.onDrain();\n }\n }\n}\n\n/**\n * Creates a new async queue instance with the specified configuration.\n * @param options - Configuration options for the async queue.\n * @returns New AsyncQueue instance.\n *\n * @example\n * ```typescript\n * const controller = new AbortController();\n * const queue = createAsyncQueue({\n * concurrency: 2,\n * signal: controller.signal\n * });\n * queue.add(async () => await doSomething());\n * controller.abort(); // Aborts the queue\n * ```\n */\nexport function createAsyncQueue(options?: AsyncQueueOptions): AsyncQueue {\n return new AsyncQueue(options);\n}\n"],"mappings":";;AAgBA,IAAa,aAAb,MAAwB;CACtB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAQ,UAAU;CAClB,AAAQ,SAAS;CACjB,AAAQ,UAAU;CAClB,AAAQ,QAA2B,CAAE;CAErC,YAAY,UAA6B,CAAE,GAAE;AAC3C,OAAK,cAAc,QAAQ,eAAe;AAC1C,OAAK,UAAU,QAAQ;AACvB,OAAK,SAAS,QAAQ;AAEtB,MAAI,KAAK,OACP,MAAK,OAAO,iBAAiB,SAAS,MAAM;AAC1C,QAAK,OAAO;EACb,EAAC;CAEN;;;;;;;CAQA,AAAO,IAAO,MAAyB,QAAkC;AACvE,MAAI,KAAK,QACP,QAAO,QAAQ,OAAO,IAAI,MAAM,0BAA0B;AAG5D,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;GACzC,MAAM,MAAM,YAAY;AACtB,QAAI,KAAK,UAAU,KAAK,SAAS;AAC/B,SAAI,KAAK,QACP,QAAO,IAAI,MAAM,0BAA0B;SAE3C,MAAK,MAAM,KAAK,IAAI;AAEtB;IACF;AAGA,wDAAI,OAAQ,SAAS;AACnB,YAAO,IAAI,MAAM,oBAAoB;AACrC;IACF;AAEA,SAAK;AACL,QAAI;KACF,MAAM,SAAS,MAAM,MAAM;AAC3B,aAAQ,OAAO;IAChB,SAAQ,KAAK;AACZ,YAAO,IAAI;IACZ,UAAS;AACR,UAAK;AACL,UAAK,MAAM;IACb;GACD;AAED,OAAI,KAAK,UAAU,KAAK,gBAAgB,KAAK,WAAW,KAAK,QAC3D,MAAK;OAEL,MAAK,MAAM,KAAK,IAAI;EAEvB;CACH;;;;CAKA,AAAO,QAAQ;AACb,OAAK,SAAS;CAChB;;;;CAKA,AAAO,SAAS;AACd,OAAK,KAAK,OAAQ;AAClB,OAAK,SAAS;AACd,OAAK,MAAM;CACb;;;;CAKA,AAAO,QAAQ;AACb,OAAK,UAAU;AACf,OAAK,OAAO;CACd;;;;CAKA,AAAO,QAAQ;AACb,OAAK,QAAQ,CAAE;CACjB;;;;CAKA,AAAO,aAAqB;AAC1B,SAAO,KAAK;CACd;;;;CAKA,AAAO,aAAqB;AAC1B,SAAO,KAAK,MAAM;CACpB;;;;CAKA,AAAO,WAAoB;AACzB,SAAO,KAAK;CACd;;;;CAKA,AAAO,YAAqB;AAC1B,SAAO,KAAK;CACd;CAEA,AAAQ,OAAO;AACb,MAAI,KAAK,UAAU,KAAK,QAAS;AACjC,SAAO,KAAK,UAAU,KAAK,eAAe,KAAK,MAAM,SAAS,GAAG;GAC/D,MAAM,KAAK,KAAK,MAAM,OAAO;AAC7B,OAAI,GAAI,KAAI;EACd;AACA,MAAI,KAAK,YAAY,KAAK,KAAK,MAAM,WAAW,KAAK,KAAK,QACxD,MAAK,SAAS;CAElB;AACF;;;;;;;;;;;;;;;;;AAkBA,SAAgB,iBAAiB,SAAyC;AACxE,QAAO,IAAI,WAAW;AACxB"}
@@ -0,0 +1,188 @@
1
+ //#region src/utils/useful-stuff/mutex.d.ts
2
+ /**
3
+ * Async mutex implementation for coordinating access to shared resources.
4
+ * Provides mutual exclusion to ensure only one task can access a resource at a time.
5
+ */
6
+ /**
7
+ * Interface for mutex storage implementations.
8
+ * Provides methods to store, retrieve, and delete mutex lock data.
9
+ */
10
+ interface MutexStorage {
11
+ /**
12
+ * Attempts to acquire a lock for a given key
13
+ * @param key - The unique identifier for the mutex lock
14
+ * @param timeout - Optional timeout in milliseconds for the lock
15
+ * @param signal - Optional AbortSignal for cancelling the acquisition
16
+ * @returns Promise resolving to true if lock was acquired, false if timeout or already locked
17
+ */
18
+ acquire(key: string, timeout?: number, signal?: AbortSignal): Promise<boolean>;
19
+ /**
20
+ * Releases the lock for a given key
21
+ * @param key - The unique identifier for the mutex lock
22
+ * @returns Promise that resolves when the lock is released
23
+ */
24
+ release(key: string): Promise<void>;
25
+ /**
26
+ * Checks if a lock is currently held for a given key
27
+ * @param key - The unique identifier for the mutex lock
28
+ * @returns Promise resolving to true if the lock is held, false otherwise
29
+ */
30
+ isLocked(key: string): Promise<boolean>;
31
+ }
32
+ /**
33
+ * Configuration options for mutex
34
+ */
35
+ interface MutexOptions {
36
+ /** Default timeout in milliseconds for lock acquisition. Default: 30000 */
37
+ timeout?: number;
38
+ /** Storage implementation for persisting mutex data. Default: {@link MemoryMutexStorage} */
39
+ storage?: MutexStorage;
40
+ }
41
+ /**
42
+ * In-memory storage implementation for mutex locks.
43
+ * Suitable for single-instance applications.
44
+ */
45
+ declare class MemoryMutexStorage implements MutexStorage {
46
+ private readonly locks;
47
+ /**
48
+ * Attempts to acquire a lock for a given key
49
+ * @param key - The unique identifier for the mutex lock
50
+ * @param timeout - Optional timeout in milliseconds for the lock
51
+ * @param signal - Optional AbortSignal for cancelling the acquisition
52
+ * @returns Promise resolving to true if lock was acquired, false if timeout or already locked
53
+ */
54
+ acquire(key: string, timeout?: number, signal?: AbortSignal): Promise<boolean>;
55
+ /**
56
+ * Releases the lock for a given key
57
+ * @param key - The unique identifier for the mutex lock
58
+ * @returns Promise that resolves when the lock is released
59
+ */
60
+ release(key: string): Promise<void>;
61
+ /**
62
+ * Checks if a lock is currently held for a given key
63
+ * @param key - The unique identifier for the mutex lock
64
+ * @returns Promise resolving to true if the lock is held, false otherwise
65
+ */
66
+ isLocked(key: string): Promise<boolean>;
67
+ private generateHolderId;
68
+ private delay;
69
+ }
70
+ /**
71
+ * Async mutex implementation that provides mutual exclusion for shared resources.
72
+ * Ensures only one task can access a protected resource at a time.
73
+ */
74
+ declare class Mutex {
75
+ private storage;
76
+ private readonly defaultTimeout;
77
+ /**
78
+ * Creates a new mutex instance
79
+ * @param options - Configuration options for the mutex
80
+ */
81
+ constructor(options?: MutexOptions);
82
+ /**
83
+ * Sets the storage implementation for the mutex
84
+ * @param storage - The storage implementation to use
85
+ */
86
+ setStorage(storage: MutexStorage): void;
87
+ /**
88
+ * Gets the storage implementation for the mutex
89
+ * @returns The storage implementation
90
+ */
91
+ getStorage(): MutexStorage;
92
+ /**
93
+ * Acquires a lock for the given key
94
+ * @param key - The unique identifier for the mutex lock
95
+ * @param timeout - Optional timeout in milliseconds for lock acquisition
96
+ * @param signal - Optional AbortSignal for cancelling the acquisition
97
+ * @returns Promise resolving to true if lock was acquired, false if timeout
98
+ */
99
+ acquire(key: string, timeout?: number, signal?: AbortSignal): Promise<boolean>;
100
+ /**
101
+ * Releases the lock for the given key
102
+ * @param key - The unique identifier for the mutex lock
103
+ * @returns Promise that resolves when the lock is released
104
+ */
105
+ release(key: string): Promise<void>;
106
+ /**
107
+ * Checks if a lock is currently held for the given key
108
+ * @param key - The unique identifier for the mutex lock
109
+ * @returns Promise resolving to true if the lock is held, false otherwise
110
+ */
111
+ isLocked(key: string): Promise<boolean>;
112
+ /**
113
+ * Executes a function with exclusive access to the resource
114
+ * @param key - The unique identifier for the mutex lock
115
+ * @param fn - The function to execute with exclusive access
116
+ * @param timeout - Optional timeout in milliseconds for lock acquisition
117
+ * @param signal - Optional AbortSignal for cancelling the lock acquisition
118
+ * @returns Promise resolving to the result of the function execution
119
+ * @throws Error if lock acquisition fails or function execution fails
120
+ */
121
+ withLock<T>(key: string, fn: () => Promise<T> | T, timeout?: number, signal?: AbortSignal): Promise<T>;
122
+ /**
123
+ * Gets the current configuration of the mutex
124
+ * @returns Object containing the current timeout value
125
+ */
126
+ getConfig(): Omit<MutexOptions, 'storage'>;
127
+ }
128
+ /**
129
+ * Default mutex instance for global use
130
+ */
131
+ declare const defaultMutex: Mutex;
132
+ /**
133
+ * Convenience function to execute a function with exclusive access using the default mutex.
134
+ *
135
+ * @param key - The unique identifier for the mutex lock
136
+ * @param fn - The function to execute with exclusive access
137
+ * @param timeout - Optional timeout in milliseconds for lock acquisition
138
+ * @param signal - Optional AbortSignal for cancelling the lock acquisition
139
+ * @returns Promise resolving to the result of the function execution
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * const controller = new AbortController();
144
+ * const result = await withMutex('shared-resource', async () => {
145
+ * // This code runs with exclusive access
146
+ * return await updateSharedResource();
147
+ * }, 30000, controller.signal);
148
+ * controller.abort(); // Cancels the lock acquisition
149
+ * ```
150
+ */
151
+ declare function withMutex<T>(key: string, fn: () => Promise<T> | T, timeout?: number, signal?: AbortSignal): Promise<T>;
152
+ /**
153
+ * Creates a new mutex instance with the specified configuration
154
+ * @param options - Configuration options for the mutex
155
+ * @returns New Mutex instance
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * const mutex = createMutex({
160
+ * timeout: 60000,
161
+ * storage: new RedisMutexStorage()
162
+ * });
163
+ * ```
164
+ */
165
+ declare function createMutex(options: MutexOptions): Mutex;
166
+ /**
167
+ * Acquires a lock using the default mutex
168
+ * @param key - The unique identifier for the mutex lock
169
+ * @param timeout - Optional timeout in milliseconds for lock acquisition
170
+ * @param signal - Optional AbortSignal for cancelling the acquisition
171
+ * @returns Promise resolving to true if lock was acquired, false if timeout
172
+ */
173
+ declare function acquireLock(key: string, timeout?: number, signal?: AbortSignal): Promise<boolean>;
174
+ /**
175
+ * Releases a lock using the default mutex
176
+ * @param key - The unique identifier for the mutex lock
177
+ * @returns Promise that resolves when the lock is released
178
+ */
179
+ declare function releaseLock(key: string): Promise<void>;
180
+ /**
181
+ * Checks if a lock is held using the default mutex
182
+ * @param key - The unique identifier for the mutex lock
183
+ * @returns Promise resolving to true if the lock is held, false otherwise
184
+ */
185
+ declare function isLocked(key: string): Promise<boolean>;
186
+ //#endregion
187
+ export { MemoryMutexStorage, Mutex, MutexOptions, MutexStorage, acquireLock, createMutex, defaultMutex, isLocked, releaseLock, withMutex };
188
+ //# sourceMappingURL=mutex.d.ts.map
@@ -0,0 +1,214 @@
1
+
2
+ //#region src/utils/useful-stuff/mutex.ts
3
+ /**
4
+ * In-memory storage implementation for mutex locks.
5
+ * Suitable for single-instance applications.
6
+ */
7
+ var MemoryMutexStorage = class {
8
+ locks = /* @__PURE__ */ new Map();
9
+ /**
10
+ * Attempts to acquire a lock for a given key
11
+ * @param key - The unique identifier for the mutex lock
12
+ * @param timeout - Optional timeout in milliseconds for the lock
13
+ * @param signal - Optional AbortSignal for cancelling the acquisition
14
+ * @returns Promise resolving to true if lock was acquired, false if timeout or already locked
15
+ */
16
+ async acquire(key, timeout = 3e4, signal) {
17
+ const holder = this.generateHolderId();
18
+ const startTime = Date.now();
19
+ while (Date.now() - startTime < timeout) {
20
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) throw new Error("Lock acquisition was aborted");
21
+ if (!this.locks.has(key)) {
22
+ this.locks.set(key, {
23
+ holder,
24
+ acquiredAt: Date.now()
25
+ });
26
+ return true;
27
+ }
28
+ await this.delay(10);
29
+ }
30
+ return false;
31
+ }
32
+ /**
33
+ * Releases the lock for a given key
34
+ * @param key - The unique identifier for the mutex lock
35
+ * @returns Promise that resolves when the lock is released
36
+ */
37
+ async release(key) {
38
+ this.locks.delete(key);
39
+ }
40
+ /**
41
+ * Checks if a lock is currently held for a given key
42
+ * @param key - The unique identifier for the mutex lock
43
+ * @returns Promise resolving to true if the lock is held, false otherwise
44
+ */
45
+ async isLocked(key) {
46
+ return this.locks.has(key);
47
+ }
48
+ generateHolderId() {
49
+ return `holder_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
50
+ }
51
+ delay(ms) {
52
+ return new Promise((resolve) => setTimeout(resolve, ms));
53
+ }
54
+ };
55
+ /**
56
+ * Async mutex implementation that provides mutual exclusion for shared resources.
57
+ * Ensures only one task can access a protected resource at a time.
58
+ */
59
+ var Mutex = class {
60
+ storage;
61
+ defaultTimeout;
62
+ /**
63
+ * Creates a new mutex instance
64
+ * @param options - Configuration options for the mutex
65
+ */
66
+ constructor(options = {}) {
67
+ this.storage = options.storage || new MemoryMutexStorage();
68
+ this.defaultTimeout = options.timeout || 3e4;
69
+ }
70
+ /**
71
+ * Sets the storage implementation for the mutex
72
+ * @param storage - The storage implementation to use
73
+ */
74
+ setStorage(storage) {
75
+ this.storage = storage;
76
+ }
77
+ /**
78
+ * Gets the storage implementation for the mutex
79
+ * @returns The storage implementation
80
+ */
81
+ getStorage() {
82
+ return this.storage;
83
+ }
84
+ /**
85
+ * Acquires a lock for the given key
86
+ * @param key - The unique identifier for the mutex lock
87
+ * @param timeout - Optional timeout in milliseconds for lock acquisition
88
+ * @param signal - Optional AbortSignal for cancelling the acquisition
89
+ * @returns Promise resolving to true if lock was acquired, false if timeout
90
+ */
91
+ async acquire(key, timeout, signal) {
92
+ return this.storage.acquire(key, timeout || this.defaultTimeout, signal);
93
+ }
94
+ /**
95
+ * Releases the lock for the given key
96
+ * @param key - The unique identifier for the mutex lock
97
+ * @returns Promise that resolves when the lock is released
98
+ */
99
+ async release(key) {
100
+ return this.storage.release(key);
101
+ }
102
+ /**
103
+ * Checks if a lock is currently held for the given key
104
+ * @param key - The unique identifier for the mutex lock
105
+ * @returns Promise resolving to true if the lock is held, false otherwise
106
+ */
107
+ async isLocked(key) {
108
+ return this.storage.isLocked(key);
109
+ }
110
+ /**
111
+ * Executes a function with exclusive access to the resource
112
+ * @param key - The unique identifier for the mutex lock
113
+ * @param fn - The function to execute with exclusive access
114
+ * @param timeout - Optional timeout in milliseconds for lock acquisition
115
+ * @param signal - Optional AbortSignal for cancelling the lock acquisition
116
+ * @returns Promise resolving to the result of the function execution
117
+ * @throws Error if lock acquisition fails or function execution fails
118
+ */
119
+ async withLock(key, fn, timeout, signal) {
120
+ const acquired = await this.acquire(key, timeout, signal);
121
+ if (!acquired) throw new Error(`Failed to acquire lock for key: ${key}`);
122
+ try {
123
+ return await fn();
124
+ } finally {
125
+ await this.release(key);
126
+ }
127
+ }
128
+ /**
129
+ * Gets the current configuration of the mutex
130
+ * @returns Object containing the current timeout value
131
+ */
132
+ getConfig() {
133
+ return { timeout: this.defaultTimeout };
134
+ }
135
+ };
136
+ /**
137
+ * Default mutex instance for global use
138
+ */
139
+ const defaultMutex = new Mutex();
140
+ /**
141
+ * Convenience function to execute a function with exclusive access using the default mutex.
142
+ *
143
+ * @param key - The unique identifier for the mutex lock
144
+ * @param fn - The function to execute with exclusive access
145
+ * @param timeout - Optional timeout in milliseconds for lock acquisition
146
+ * @param signal - Optional AbortSignal for cancelling the lock acquisition
147
+ * @returns Promise resolving to the result of the function execution
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * const controller = new AbortController();
152
+ * const result = await withMutex('shared-resource', async () => {
153
+ * // This code runs with exclusive access
154
+ * return await updateSharedResource();
155
+ * }, 30000, controller.signal);
156
+ * controller.abort(); // Cancels the lock acquisition
157
+ * ```
158
+ */
159
+ async function withMutex(key, fn, timeout, signal) {
160
+ return defaultMutex.withLock(key, fn, timeout, signal);
161
+ }
162
+ /**
163
+ * Creates a new mutex instance with the specified configuration
164
+ * @param options - Configuration options for the mutex
165
+ * @returns New Mutex instance
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * const mutex = createMutex({
170
+ * timeout: 60000,
171
+ * storage: new RedisMutexStorage()
172
+ * });
173
+ * ```
174
+ */
175
+ function createMutex(options) {
176
+ return new Mutex(options);
177
+ }
178
+ /**
179
+ * Acquires a lock using the default mutex
180
+ * @param key - The unique identifier for the mutex lock
181
+ * @param timeout - Optional timeout in milliseconds for lock acquisition
182
+ * @param signal - Optional AbortSignal for cancelling the acquisition
183
+ * @returns Promise resolving to true if lock was acquired, false if timeout
184
+ */
185
+ async function acquireLock(key, timeout, signal) {
186
+ return defaultMutex.acquire(key, timeout, signal);
187
+ }
188
+ /**
189
+ * Releases a lock using the default mutex
190
+ * @param key - The unique identifier for the mutex lock
191
+ * @returns Promise that resolves when the lock is released
192
+ */
193
+ async function releaseLock(key) {
194
+ return defaultMutex.release(key);
195
+ }
196
+ /**
197
+ * Checks if a lock is held using the default mutex
198
+ * @param key - The unique identifier for the mutex lock
199
+ * @returns Promise resolving to true if the lock is held, false otherwise
200
+ */
201
+ async function isLocked(key) {
202
+ return defaultMutex.isLocked(key);
203
+ }
204
+
205
+ //#endregion
206
+ exports.MemoryMutexStorage = MemoryMutexStorage;
207
+ exports.Mutex = Mutex;
208
+ exports.acquireLock = acquireLock;
209
+ exports.createMutex = createMutex;
210
+ exports.defaultMutex = defaultMutex;
211
+ exports.isLocked = isLocked;
212
+ exports.releaseLock = releaseLock;
213
+ exports.withMutex = withMutex;
214
+ //# sourceMappingURL=mutex.js.map