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,227 @@
1
+ //#region src/utils/useful-stuff/semaphore.d.ts
2
+ /**
3
+ * Async semaphore implementation for controlling access to a limited pool of resources.
4
+ * Allows a specified number of concurrent operations while blocking additional requests.
5
+ */
6
+ /**
7
+ * Interface for semaphore storage implementations.
8
+ * Provides methods to store, retrieve, and manage semaphore permit data.
9
+ */
10
+ interface SemaphoreStorage {
11
+ /**
12
+ * Attempts to acquire a permit for a given key
13
+ * @param key - The unique identifier for the semaphore
14
+ * @param timeout - Optional timeout in milliseconds for permit acquisition
15
+ * @param signal - Optional AbortSignal for cancelling the acquisition
16
+ * @returns Promise resolving to true if permit was acquired, false if timeout or no permits available
17
+ */
18
+ acquire(key: string, timeout?: number, signal?: AbortSignal): Promise<boolean>;
19
+ /**
20
+ * Releases a permit for a given key
21
+ * @param key - The unique identifier for the semaphore
22
+ * @returns Promise that resolves when the permit is released
23
+ */
24
+ release(key: string): Promise<void>;
25
+ /**
26
+ * Gets the number of available permits for a given key
27
+ * @param key - The unique identifier for the semaphore
28
+ * @returns Promise resolving to the number of available permits
29
+ */
30
+ getAvailablePermits(key: string): Promise<number>;
31
+ /**
32
+ * Gets the total number of permits for a given key
33
+ * @param key - The unique identifier for the semaphore
34
+ * @returns Promise resolving to the total number of permits
35
+ */
36
+ getTotalPermits(key: string): Promise<number>;
37
+ }
38
+ /**
39
+ * Configuration options for semaphore
40
+ */
41
+ interface SemaphoreOptions {
42
+ /** Maximum number of concurrent permits allowed. Default: 1 */
43
+ permits?: number;
44
+ /** Default timeout in milliseconds for permit acquisition. Default: 30000 */
45
+ timeout?: number;
46
+ /** Storage implementation for persisting semaphore data. Default: {@link MemorySemaphoreStorage} */
47
+ storage?: SemaphoreStorage;
48
+ }
49
+ /**
50
+ * In-memory storage implementation for semaphore permits.
51
+ * Suitable for single-instance applications.
52
+ */
53
+ declare class MemorySemaphoreStorage implements SemaphoreStorage {
54
+ private readonly semaphores;
55
+ /**
56
+ * Attempts to acquire a permit for a given key
57
+ * @param key - The unique identifier for the semaphore
58
+ * @param timeout - Optional timeout in milliseconds for permit acquisition
59
+ * @param signal - Optional AbortSignal for cancelling the acquisition
60
+ * @returns Promise resolving to true if permit was acquired, false if timeout or no permits available
61
+ */
62
+ acquire(key: string, timeout?: number, signal?: AbortSignal): Promise<boolean>;
63
+ /**
64
+ * Releases a permit for a given key
65
+ * @param key - The unique identifier for the semaphore
66
+ * @returns Promise that resolves when the permit is released
67
+ */
68
+ release(key: string): Promise<void>;
69
+ /**
70
+ * Gets the number of available permits for a given key
71
+ * @param key - The unique identifier for the semaphore
72
+ * @returns Promise resolving to the number of available permits
73
+ */
74
+ getAvailablePermits(key: string): Promise<number>;
75
+ /**
76
+ * Gets the total number of permits for a given key
77
+ * @param key - The unique identifier for the semaphore
78
+ * @returns Promise resolving to the total number of permits
79
+ */
80
+ getTotalPermits(key: string): Promise<number>;
81
+ /**
82
+ * Initializes a semaphore with the specified number of permits
83
+ * @param key - The unique identifier for the semaphore
84
+ * @param permits - The total number of permits to allocate
85
+ */
86
+ initialize(key: string, permits: number): void;
87
+ private delay;
88
+ }
89
+ /**
90
+ * Async semaphore implementation that controls access to a limited pool of resources.
91
+ * Allows a specified number of concurrent operations while blocking additional requests.
92
+ */
93
+ declare class Semaphore {
94
+ private storage;
95
+ private readonly defaultPermits;
96
+ private readonly defaultTimeout;
97
+ /**
98
+ * Creates a new semaphore instance
99
+ * @param options - Configuration options for the semaphore
100
+ */
101
+ constructor(options?: SemaphoreOptions);
102
+ /**
103
+ * Sets the storage implementation for the semaphore
104
+ * @param storage - The storage implementation to use
105
+ */
106
+ setStorage(storage: SemaphoreStorage): void;
107
+ /**
108
+ * Gets the storage implementation for the semaphore
109
+ * @returns The storage implementation
110
+ */
111
+ getStorage(): SemaphoreStorage;
112
+ /**
113
+ * Acquires a permit for the given key
114
+ * @param key - The unique identifier for the semaphore
115
+ * @param timeout - Optional timeout in milliseconds for permit acquisition
116
+ * @param signal - Optional AbortSignal for cancelling the acquisition
117
+ * @returns Promise resolving to true if permit was acquired, false if timeout
118
+ */
119
+ acquire(key: string, timeout?: number, signal?: AbortSignal): Promise<boolean>;
120
+ /**
121
+ * Releases a permit for the given key
122
+ * @param key - The unique identifier for the semaphore
123
+ * @returns Promise that resolves when the permit is released
124
+ */
125
+ release(key: string): Promise<void>;
126
+ /**
127
+ * Gets the number of available permits for the given key
128
+ * @param key - The unique identifier for the semaphore
129
+ * @returns Promise resolving to the number of available permits
130
+ */
131
+ getAvailablePermits(key: string): Promise<number>;
132
+ /**
133
+ * Gets the total number of permits for the given key
134
+ * @param key - The unique identifier for the semaphore
135
+ * @returns Promise resolving to the total number of permits
136
+ */
137
+ getTotalPermits(key: string): Promise<number>;
138
+ /**
139
+ * Gets the number of acquired permits for the given key
140
+ * @param key - The unique identifier for the semaphore
141
+ * @returns Promise resolving to the number of acquired permits
142
+ */
143
+ getAcquiredPermits(key: string): Promise<number>;
144
+ /**
145
+ * Executes a function with a permit from the semaphore
146
+ * @param key - The unique identifier for the semaphore
147
+ * @param fn - The function to execute with a permit
148
+ * @param timeout - Optional timeout in milliseconds for permit acquisition
149
+ * @param signal - Optional AbortSignal for cancelling the permit acquisition
150
+ * @returns Promise resolving to the result of the function execution
151
+ * @throws Error if permit acquisition fails or function execution fails
152
+ */
153
+ withPermit<T>(key: string, fn: () => Promise<T> | T, timeout?: number, signal?: AbortSignal): Promise<T>;
154
+ /**
155
+ * Gets the current configuration of the semaphore
156
+ * @returns Object containing the current permits and timeout values
157
+ */
158
+ getConfig(): Omit<SemaphoreOptions, 'storage'>;
159
+ }
160
+ /**
161
+ * Default semaphore instance for global use
162
+ */
163
+ declare const defaultSemaphore: Semaphore;
164
+ /**
165
+ * Convenience function to execute a function with a permit using the default semaphore.
166
+ *
167
+ * @param key - The unique identifier for the semaphore
168
+ * @param fn - The function to execute with a permit
169
+ * @param timeout - Optional timeout in milliseconds for permit acquisition
170
+ * @param signal - Optional AbortSignal for cancelling the permit acquisition
171
+ * @returns Promise resolving to the result of the function execution
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * const controller = new AbortController();
176
+ * const result = await withPermit('database-connection', async () => {
177
+ * // This code runs with a permit from the semaphore
178
+ * return await executeDatabaseQuery();
179
+ * }, 30000, controller.signal);
180
+ * controller.abort(); // Cancels the permit acquisition
181
+ * ```
182
+ */
183
+ declare function withPermit<T>(key: string, fn: () => Promise<T> | T, timeout?: number, signal?: AbortSignal): Promise<T>;
184
+ /**
185
+ * Creates a new semaphore instance with the specified configuration
186
+ * @param options - Configuration options for the semaphore
187
+ * @returns New Semaphore instance
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * const semaphore = createSemaphore({
192
+ * permits: 5,
193
+ * timeout: 60000,
194
+ * storage: new RedisSemaphoreStorage()
195
+ * });
196
+ * ```
197
+ */
198
+ declare function createSemaphore(options: SemaphoreOptions): Semaphore;
199
+ /**
200
+ * Acquires a permit using the default semaphore
201
+ * @param key - The unique identifier for the semaphore
202
+ * @param timeout - Optional timeout in milliseconds for permit acquisition
203
+ * @param signal - Optional AbortSignal for cancelling the acquisition
204
+ * @returns Promise resolving to true if permit was acquired, false if timeout
205
+ */
206
+ declare function acquirePermit(key: string, timeout?: number, signal?: AbortSignal): Promise<boolean>;
207
+ /**
208
+ * Releases a permit using the default semaphore
209
+ * @param key - The unique identifier for the semaphore
210
+ * @returns Promise that resolves when the permit is released
211
+ */
212
+ declare function releasePermit(key: string): Promise<void>;
213
+ /**
214
+ * Gets the number of available permits using the default semaphore
215
+ * @param key - The unique identifier for the semaphore
216
+ * @returns Promise resolving to the number of available permits
217
+ */
218
+ declare function getAvailablePermits(key: string): Promise<number>;
219
+ /**
220
+ * Gets the number of acquired permits using the default semaphore
221
+ * @param key - The unique identifier for the semaphore
222
+ * @returns Promise resolving to the number of acquired permits
223
+ */
224
+ declare function getAcquiredPermits(key: string): Promise<number>;
225
+ //#endregion
226
+ export { MemorySemaphoreStorage, Semaphore, SemaphoreOptions, SemaphoreStorage, acquirePermit, createSemaphore, defaultSemaphore, getAcquiredPermits, getAvailablePermits, releasePermit, withPermit };
227
+ //# sourceMappingURL=semaphore.d.ts.map
@@ -0,0 +1,267 @@
1
+
2
+ //#region src/utils/useful-stuff/semaphore.ts
3
+ /**
4
+ * In-memory storage implementation for semaphore permits.
5
+ * Suitable for single-instance applications.
6
+ */
7
+ var MemorySemaphoreStorage = class {
8
+ semaphores = /* @__PURE__ */ new Map();
9
+ /**
10
+ * Attempts to acquire a permit for a given key
11
+ * @param key - The unique identifier for the semaphore
12
+ * @param timeout - Optional timeout in milliseconds for permit acquisition
13
+ * @param signal - Optional AbortSignal for cancelling the acquisition
14
+ * @returns Promise resolving to true if permit was acquired, false if timeout or no permits available
15
+ */
16
+ async acquire(key, timeout = 3e4, signal) {
17
+ const startTime = Date.now();
18
+ while (Date.now() - startTime < timeout) {
19
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) throw new Error("Permit acquisition was aborted");
20
+ const semaphore = this.semaphores.get(key);
21
+ if (semaphore && semaphore.available > 0) {
22
+ semaphore.available--;
23
+ return true;
24
+ }
25
+ await this.delay(10);
26
+ }
27
+ return false;
28
+ }
29
+ /**
30
+ * Releases a permit for a given key
31
+ * @param key - The unique identifier for the semaphore
32
+ * @returns Promise that resolves when the permit is released
33
+ */
34
+ async release(key) {
35
+ const semaphore = this.semaphores.get(key);
36
+ if (semaphore && semaphore.available < semaphore.total) semaphore.available++;
37
+ }
38
+ /**
39
+ * Gets the number of available permits for a given key
40
+ * @param key - The unique identifier for the semaphore
41
+ * @returns Promise resolving to the number of available permits
42
+ */
43
+ async getAvailablePermits(key) {
44
+ const semaphore = this.semaphores.get(key);
45
+ return semaphore ? semaphore.available : 0;
46
+ }
47
+ /**
48
+ * Gets the total number of permits for a given key
49
+ * @param key - The unique identifier for the semaphore
50
+ * @returns Promise resolving to the total number of permits
51
+ */
52
+ async getTotalPermits(key) {
53
+ const semaphore = this.semaphores.get(key);
54
+ return semaphore ? semaphore.total : 0;
55
+ }
56
+ /**
57
+ * Initializes a semaphore with the specified number of permits
58
+ * @param key - The unique identifier for the semaphore
59
+ * @param permits - The total number of permits to allocate
60
+ */
61
+ initialize(key, permits) {
62
+ this.semaphores.set(key, {
63
+ total: permits,
64
+ available: permits
65
+ });
66
+ }
67
+ delay(ms) {
68
+ return new Promise((resolve) => setTimeout(resolve, ms));
69
+ }
70
+ };
71
+ /**
72
+ * Async semaphore implementation that controls access to a limited pool of resources.
73
+ * Allows a specified number of concurrent operations while blocking additional requests.
74
+ */
75
+ var Semaphore = class {
76
+ storage;
77
+ defaultPermits;
78
+ defaultTimeout;
79
+ /**
80
+ * Creates a new semaphore instance
81
+ * @param options - Configuration options for the semaphore
82
+ */
83
+ constructor(options = {}) {
84
+ this.storage = options.storage || new MemorySemaphoreStorage();
85
+ this.defaultPermits = options.permits || 1;
86
+ this.defaultTimeout = options.timeout || 3e4;
87
+ }
88
+ /**
89
+ * Sets the storage implementation for the semaphore
90
+ * @param storage - The storage implementation to use
91
+ */
92
+ setStorage(storage) {
93
+ this.storage = storage;
94
+ }
95
+ /**
96
+ * Gets the storage implementation for the semaphore
97
+ * @returns The storage implementation
98
+ */
99
+ getStorage() {
100
+ return this.storage;
101
+ }
102
+ /**
103
+ * Acquires a permit for the given key
104
+ * @param key - The unique identifier for the semaphore
105
+ * @param timeout - Optional timeout in milliseconds for permit acquisition
106
+ * @param signal - Optional AbortSignal for cancelling the acquisition
107
+ * @returns Promise resolving to true if permit was acquired, false if timeout
108
+ */
109
+ async acquire(key, timeout, signal) {
110
+ if (this.storage instanceof MemorySemaphoreStorage) {
111
+ const totalPermits = await this.storage.getTotalPermits(key);
112
+ if (totalPermits === 0) this.storage.initialize(key, this.defaultPermits);
113
+ }
114
+ return this.storage.acquire(key, timeout || this.defaultTimeout, signal);
115
+ }
116
+ /**
117
+ * Releases a permit for the given key
118
+ * @param key - The unique identifier for the semaphore
119
+ * @returns Promise that resolves when the permit is released
120
+ */
121
+ async release(key) {
122
+ return this.storage.release(key);
123
+ }
124
+ /**
125
+ * Gets the number of available permits for the given key
126
+ * @param key - The unique identifier for the semaphore
127
+ * @returns Promise resolving to the number of available permits
128
+ */
129
+ async getAvailablePermits(key) {
130
+ return this.storage.getAvailablePermits(key);
131
+ }
132
+ /**
133
+ * Gets the total number of permits for the given key
134
+ * @param key - The unique identifier for the semaphore
135
+ * @returns Promise resolving to the total number of permits
136
+ */
137
+ async getTotalPermits(key) {
138
+ return this.storage.getTotalPermits(key);
139
+ }
140
+ /**
141
+ * Gets the number of acquired permits for the given key
142
+ * @param key - The unique identifier for the semaphore
143
+ * @returns Promise resolving to the number of acquired permits
144
+ */
145
+ async getAcquiredPermits(key) {
146
+ const total = await this.getTotalPermits(key);
147
+ const available = await this.getAvailablePermits(key);
148
+ return total - available;
149
+ }
150
+ /**
151
+ * Executes a function with a permit from the semaphore
152
+ * @param key - The unique identifier for the semaphore
153
+ * @param fn - The function to execute with a permit
154
+ * @param timeout - Optional timeout in milliseconds for permit acquisition
155
+ * @param signal - Optional AbortSignal for cancelling the permit acquisition
156
+ * @returns Promise resolving to the result of the function execution
157
+ * @throws Error if permit acquisition fails or function execution fails
158
+ */
159
+ async withPermit(key, fn, timeout, signal) {
160
+ const acquired = await this.acquire(key, timeout, signal);
161
+ if (!acquired) throw new Error(`Failed to acquire permit for key: ${key}`);
162
+ try {
163
+ return await fn();
164
+ } finally {
165
+ await this.release(key);
166
+ }
167
+ }
168
+ /**
169
+ * Gets the current configuration of the semaphore
170
+ * @returns Object containing the current permits and timeout values
171
+ */
172
+ getConfig() {
173
+ return {
174
+ permits: this.defaultPermits,
175
+ timeout: this.defaultTimeout
176
+ };
177
+ }
178
+ };
179
+ /**
180
+ * Default semaphore instance for global use
181
+ */
182
+ const defaultSemaphore = new Semaphore();
183
+ /**
184
+ * Convenience function to execute a function with a permit using the default semaphore.
185
+ *
186
+ * @param key - The unique identifier for the semaphore
187
+ * @param fn - The function to execute with a permit
188
+ * @param timeout - Optional timeout in milliseconds for permit acquisition
189
+ * @param signal - Optional AbortSignal for cancelling the permit acquisition
190
+ * @returns Promise resolving to the result of the function execution
191
+ *
192
+ * @example
193
+ * ```typescript
194
+ * const controller = new AbortController();
195
+ * const result = await withPermit('database-connection', async () => {
196
+ * // This code runs with a permit from the semaphore
197
+ * return await executeDatabaseQuery();
198
+ * }, 30000, controller.signal);
199
+ * controller.abort(); // Cancels the permit acquisition
200
+ * ```
201
+ */
202
+ async function withPermit(key, fn, timeout, signal) {
203
+ return defaultSemaphore.withPermit(key, fn, timeout, signal);
204
+ }
205
+ /**
206
+ * Creates a new semaphore instance with the specified configuration
207
+ * @param options - Configuration options for the semaphore
208
+ * @returns New Semaphore instance
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * const semaphore = createSemaphore({
213
+ * permits: 5,
214
+ * timeout: 60000,
215
+ * storage: new RedisSemaphoreStorage()
216
+ * });
217
+ * ```
218
+ */
219
+ function createSemaphore(options) {
220
+ return new Semaphore(options);
221
+ }
222
+ /**
223
+ * Acquires a permit using the default semaphore
224
+ * @param key - The unique identifier for the semaphore
225
+ * @param timeout - Optional timeout in milliseconds for permit acquisition
226
+ * @param signal - Optional AbortSignal for cancelling the acquisition
227
+ * @returns Promise resolving to true if permit was acquired, false if timeout
228
+ */
229
+ async function acquirePermit(key, timeout, signal) {
230
+ return defaultSemaphore.acquire(key, timeout, signal);
231
+ }
232
+ /**
233
+ * Releases a permit using the default semaphore
234
+ * @param key - The unique identifier for the semaphore
235
+ * @returns Promise that resolves when the permit is released
236
+ */
237
+ async function releasePermit(key) {
238
+ return defaultSemaphore.release(key);
239
+ }
240
+ /**
241
+ * Gets the number of available permits using the default semaphore
242
+ * @param key - The unique identifier for the semaphore
243
+ * @returns Promise resolving to the number of available permits
244
+ */
245
+ async function getAvailablePermits(key) {
246
+ return defaultSemaphore.getAvailablePermits(key);
247
+ }
248
+ /**
249
+ * Gets the number of acquired permits using the default semaphore
250
+ * @param key - The unique identifier for the semaphore
251
+ * @returns Promise resolving to the number of acquired permits
252
+ */
253
+ async function getAcquiredPermits(key) {
254
+ return defaultSemaphore.getAcquiredPermits(key);
255
+ }
256
+
257
+ //#endregion
258
+ exports.MemorySemaphoreStorage = MemorySemaphoreStorage;
259
+ exports.Semaphore = Semaphore;
260
+ exports.acquirePermit = acquirePermit;
261
+ exports.createSemaphore = createSemaphore;
262
+ exports.defaultSemaphore = defaultSemaphore;
263
+ exports.getAcquiredPermits = getAcquiredPermits;
264
+ exports.getAvailablePermits = getAvailablePermits;
265
+ exports.releasePermit = releasePermit;
266
+ exports.withPermit = withPermit;
267
+ //# sourceMappingURL=semaphore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semaphore.js","names":[],"sources":["../../../src/utils/useful-stuff/semaphore.ts"],"sourcesContent":["/**\n * Async semaphore implementation for controlling access to a limited pool of resources.\n * Allows a specified number of concurrent operations while blocking additional requests.\n */\n\n/**\n * Interface for semaphore storage implementations.\n * Provides methods to store, retrieve, and manage semaphore permit data.\n */\nexport interface SemaphoreStorage {\n /**\n * Attempts to acquire a permit for a given key\n * @param key - The unique identifier for the semaphore\n * @param timeout - Optional timeout in milliseconds for permit acquisition\n * @param signal - Optional AbortSignal for cancelling the acquisition\n * @returns Promise resolving to true if permit was acquired, false if timeout or no permits available\n */\n acquire(\n key: string,\n timeout?: number,\n signal?: AbortSignal,\n ): Promise<boolean>;\n\n /**\n * Releases a permit for a given key\n * @param key - The unique identifier for the semaphore\n * @returns Promise that resolves when the permit is released\n */\n release(key: string): Promise<void>;\n\n /**\n * Gets the number of available permits for a given key\n * @param key - The unique identifier for the semaphore\n * @returns Promise resolving to the number of available permits\n */\n getAvailablePermits(key: string): Promise<number>;\n\n /**\n * Gets the total number of permits for a given key\n * @param key - The unique identifier for the semaphore\n * @returns Promise resolving to the total number of permits\n */\n getTotalPermits(key: string): Promise<number>;\n}\n\n/**\n * Configuration options for semaphore\n */\nexport interface SemaphoreOptions {\n /** Maximum number of concurrent permits allowed. Default: 1 */\n permits?: number;\n /** Default timeout in milliseconds for permit acquisition. Default: 30000 */\n timeout?: number;\n /** Storage implementation for persisting semaphore data. Default: {@link MemorySemaphoreStorage} */\n storage?: SemaphoreStorage;\n}\n\n/**\n * In-memory storage implementation for semaphore permits.\n * Suitable for single-instance applications.\n */\nexport class MemorySemaphoreStorage implements SemaphoreStorage {\n private readonly semaphores = new Map<\n string,\n { total: number; available: number }\n >();\n\n /**\n * Attempts to acquire a permit for a given key\n * @param key - The unique identifier for the semaphore\n * @param timeout - Optional timeout in milliseconds for permit acquisition\n * @param signal - Optional AbortSignal for cancelling the acquisition\n * @returns Promise resolving to true if permit was acquired, false if timeout or no permits available\n */\n async acquire(\n key: string,\n timeout: number = 30000,\n signal?: AbortSignal,\n ): Promise<boolean> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n // Check if aborted\n if (signal?.aborted) {\n throw new Error('Permit acquisition was aborted');\n }\n\n const semaphore = this.semaphores.get(key);\n if (semaphore && semaphore.available > 0) {\n semaphore.available--;\n return true;\n }\n await this.delay(10);\n }\n\n return false;\n }\n\n /**\n * Releases a permit for a given key\n * @param key - The unique identifier for the semaphore\n * @returns Promise that resolves when the permit is released\n */\n async release(key: string): Promise<void> {\n const semaphore = this.semaphores.get(key);\n if (semaphore && semaphore.available < semaphore.total) {\n semaphore.available++;\n }\n }\n\n /**\n * Gets the number of available permits for a given key\n * @param key - The unique identifier for the semaphore\n * @returns Promise resolving to the number of available permits\n */\n async getAvailablePermits(key: string): Promise<number> {\n const semaphore = this.semaphores.get(key);\n return semaphore ? semaphore.available : 0;\n }\n\n /**\n * Gets the total number of permits for a given key\n * @param key - The unique identifier for the semaphore\n * @returns Promise resolving to the total number of permits\n */\n async getTotalPermits(key: string): Promise<number> {\n const semaphore = this.semaphores.get(key);\n return semaphore ? semaphore.total : 0;\n }\n\n /**\n * Initializes a semaphore with the specified number of permits\n * @param key - The unique identifier for the semaphore\n * @param permits - The total number of permits to allocate\n */\n initialize(key: string, permits: number): void {\n this.semaphores.set(key, { total: permits, available: permits });\n }\n\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\n/**\n * Async semaphore implementation that controls access to a limited pool of resources.\n * Allows a specified number of concurrent operations while blocking additional requests.\n */\nexport class Semaphore {\n private storage: SemaphoreStorage;\n private readonly defaultPermits: number;\n private readonly defaultTimeout: number;\n\n /**\n * Creates a new semaphore instance\n * @param options - Configuration options for the semaphore\n */\n public constructor(options: SemaphoreOptions = {}) {\n this.storage = options.storage || new MemorySemaphoreStorage();\n this.defaultPermits = options.permits || 1;\n this.defaultTimeout = options.timeout || 30000;\n }\n\n /**\n * Sets the storage implementation for the semaphore\n * @param storage - The storage implementation to use\n */\n public setStorage(storage: SemaphoreStorage) {\n this.storage = storage;\n }\n\n /**\n * Gets the storage implementation for the semaphore\n * @returns The storage implementation\n */\n public getStorage(): SemaphoreStorage {\n return this.storage;\n }\n\n /**\n * Acquires a permit for the given key\n * @param key - The unique identifier for the semaphore\n * @param timeout - Optional timeout in milliseconds for permit acquisition\n * @param signal - Optional AbortSignal for cancelling the acquisition\n * @returns Promise resolving to true if permit was acquired, false if timeout\n */\n public async acquire(\n key: string,\n timeout?: number,\n signal?: AbortSignal,\n ): Promise<boolean> {\n // Initialize semaphore if it doesn't exist\n if (this.storage instanceof MemorySemaphoreStorage) {\n const totalPermits = await this.storage.getTotalPermits(key);\n if (totalPermits === 0) {\n (this.storage as MemorySemaphoreStorage).initialize(\n key,\n this.defaultPermits,\n );\n }\n }\n\n return this.storage.acquire(key, timeout || this.defaultTimeout, signal);\n }\n\n /**\n * Releases a permit for the given key\n * @param key - The unique identifier for the semaphore\n * @returns Promise that resolves when the permit is released\n */\n public async release(key: string): Promise<void> {\n return this.storage.release(key);\n }\n\n /**\n * Gets the number of available permits for the given key\n * @param key - The unique identifier for the semaphore\n * @returns Promise resolving to the number of available permits\n */\n public async getAvailablePermits(key: string): Promise<number> {\n return this.storage.getAvailablePermits(key);\n }\n\n /**\n * Gets the total number of permits for the given key\n * @param key - The unique identifier for the semaphore\n * @returns Promise resolving to the total number of permits\n */\n public async getTotalPermits(key: string): Promise<number> {\n return this.storage.getTotalPermits(key);\n }\n\n /**\n * Gets the number of acquired permits for the given key\n * @param key - The unique identifier for the semaphore\n * @returns Promise resolving to the number of acquired permits\n */\n public async getAcquiredPermits(key: string): Promise<number> {\n const total = await this.getTotalPermits(key);\n const available = await this.getAvailablePermits(key);\n return total - available;\n }\n\n /**\n * Executes a function with a permit from the semaphore\n * @param key - The unique identifier for the semaphore\n * @param fn - The function to execute with a permit\n * @param timeout - Optional timeout in milliseconds for permit acquisition\n * @param signal - Optional AbortSignal for cancelling the permit acquisition\n * @returns Promise resolving to the result of the function execution\n * @throws Error if permit acquisition fails or function execution fails\n */\n public async withPermit<T>(\n key: string,\n fn: () => Promise<T> | T,\n timeout?: number,\n signal?: AbortSignal,\n ): Promise<T> {\n const acquired = await this.acquire(key, timeout, signal);\n if (!acquired) {\n throw new Error(`Failed to acquire permit for key: ${key}`);\n }\n\n try {\n return await fn();\n } finally {\n await this.release(key);\n }\n }\n\n /**\n * Gets the current configuration of the semaphore\n * @returns Object containing the current permits and timeout values\n */\n public getConfig(): Omit<SemaphoreOptions, 'storage'> {\n return {\n permits: this.defaultPermits,\n timeout: this.defaultTimeout,\n };\n }\n}\n\n/**\n * Default semaphore instance for global use\n */\nexport const defaultSemaphore = new Semaphore();\n\n/**\n * Convenience function to execute a function with a permit using the default semaphore.\n *\n * @param key - The unique identifier for the semaphore\n * @param fn - The function to execute with a permit\n * @param timeout - Optional timeout in milliseconds for permit acquisition\n * @param signal - Optional AbortSignal for cancelling the permit acquisition\n * @returns Promise resolving to the result of the function execution\n *\n * @example\n * ```typescript\n * const controller = new AbortController();\n * const result = await withPermit('database-connection', async () => {\n * // This code runs with a permit from the semaphore\n * return await executeDatabaseQuery();\n * }, 30000, controller.signal);\n * controller.abort(); // Cancels the permit acquisition\n * ```\n */\nexport async function withPermit<T>(\n key: string,\n fn: () => Promise<T> | T,\n timeout?: number,\n signal?: AbortSignal,\n): Promise<T> {\n return defaultSemaphore.withPermit(key, fn, timeout, signal);\n}\n\n/**\n * Creates a new semaphore instance with the specified configuration\n * @param options - Configuration options for the semaphore\n * @returns New Semaphore instance\n *\n * @example\n * ```typescript\n * const semaphore = createSemaphore({\n * permits: 5,\n * timeout: 60000,\n * storage: new RedisSemaphoreStorage()\n * });\n * ```\n */\nexport function createSemaphore(options: SemaphoreOptions): Semaphore {\n return new Semaphore(options);\n}\n\n/**\n * Acquires a permit using the default semaphore\n * @param key - The unique identifier for the semaphore\n * @param timeout - Optional timeout in milliseconds for permit acquisition\n * @param signal - Optional AbortSignal for cancelling the acquisition\n * @returns Promise resolving to true if permit was acquired, false if timeout\n */\nexport async function acquirePermit(\n key: string,\n timeout?: number,\n signal?: AbortSignal,\n): Promise<boolean> {\n return defaultSemaphore.acquire(key, timeout, signal);\n}\n\n/**\n * Releases a permit using the default semaphore\n * @param key - The unique identifier for the semaphore\n * @returns Promise that resolves when the permit is released\n */\nexport async function releasePermit(key: string): Promise<void> {\n return defaultSemaphore.release(key);\n}\n\n/**\n * Gets the number of available permits using the default semaphore\n * @param key - The unique identifier for the semaphore\n * @returns Promise resolving to the number of available permits\n */\nexport async function getAvailablePermits(key: string): Promise<number> {\n return defaultSemaphore.getAvailablePermits(key);\n}\n\n/**\n * Gets the number of acquired permits using the default semaphore\n * @param key - The unique identifier for the semaphore\n * @returns Promise resolving to the number of acquired permits\n */\nexport async function getAcquiredPermits(key: string): Promise<number> {\n return defaultSemaphore.getAcquiredPermits(key);\n}\n"],"mappings":"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"}
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * The current version of CommandKit.
8
8
  */
9
- const version = "1.0.0-dev.20250622124751";
9
+ const version = "1.0.0-dev.20250622135945";
10
10
 
11
11
  //#endregion
12
12
  Object.defineProperty(exports, 'version', {
@@ -15,4 +15,4 @@ Object.defineProperty(exports, 'version', {
15
15
  return version;
16
16
  }
17
17
  });
18
- //# sourceMappingURL=version-CRg5idya.js.map
18
+ //# sourceMappingURL=version-DfdnkNI2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version-CRg5idya.js","names":[],"sources":["../src/version.ts"],"sourcesContent":["/**\n * @private\n */\nfunction $version(): string {\n 'use macro';\n return require('../package.json').version;\n}\n\n/**\n * The current version of CommandKit.\n */\nexport const version: string = $version();\n"],"mappings":";;;;;;;;AAWA,MAAa,UAA4B"}
1
+ {"version":3,"file":"version-DfdnkNI2.js","names":[],"sources":["../src/version.ts"],"sourcesContent":["/**\n * @private\n */\nfunction $version(): string {\n 'use macro';\n return require('../package.json').version;\n}\n\n/**\n * The current version of CommandKit.\n */\nexport const version: string = $version();\n"],"mappings":";;;;;;;;AAWA,MAAa,UAA4B"}
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
- const require_version = require('./version-CRg5idya.js');
1
+ const require_version = require('./version-DfdnkNI2.js');
2
2
 
3
3
  exports.version = require_version.version;
package/env.cjs ADDED
@@ -0,0 +1,13 @@
1
+ const {
2
+ COMMANDKIT_BOOTSTRAP_MODE,
3
+ COMMANDKIT_IS_CLI,
4
+ COMMANDKIT_IS_DEV,
5
+ COMMANDKIT_IS_TEST,
6
+ } = require('commandkit');
7
+
8
+ module.exports = {
9
+ COMMANDKIT_BOOTSTRAP_MODE,
10
+ COMMANDKIT_IS_CLI,
11
+ COMMANDKIT_IS_DEV,
12
+ COMMANDKIT_IS_TEST,
13
+ };
package/env.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export {
2
+ COMMANDKIT_BOOTSTRAP_MODE,
3
+ COMMANDKIT_IS_CLI,
4
+ COMMANDKIT_IS_DEV,
5
+ COMMANDKIT_IS_TEST,
6
+ } from 'commandkit';
package/mutex.cjs ADDED
@@ -0,0 +1,21 @@
1
+ const {
2
+ MemoryMutexStorage,
3
+ Mutex,
4
+ acquireLock,
5
+ createMutex,
6
+ defaultMutex,
7
+ isLocked,
8
+ releaseLock,
9
+ withMutex,
10
+ } = require('./dist/utils/useful-stuff/mutex.js');
11
+
12
+ module.exports = {
13
+ MemoryMutexStorage,
14
+ Mutex,
15
+ acquireLock,
16
+ createMutex,
17
+ defaultMutex,
18
+ isLocked,
19
+ releaseLock,
20
+ withMutex,
21
+ };
package/mutex.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/utils/useful-stuff/mutex.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "commandkit",
3
3
  "description": "Beginner friendly command & event handler for Discord.js",
4
- "version": "1.0.0-dev.20250622124751",
4
+ "version": "1.0.0-dev.20250622135945",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
7
7
  "main": "./dist/index.js",
@@ -34,7 +34,17 @@
34
34
  "./analytics.cjs",
35
35
  "./analytics.d.ts",
36
36
  "./ai.cjs",
37
- "./ai.d.ts"
37
+ "./ai.d.ts",
38
+ "./env.cjs",
39
+ "./env.d.ts",
40
+ "./async-queue.cjs",
41
+ "./async-queue.d.ts",
42
+ "./ratelimit.cjs",
43
+ "./ratelimit.d.ts",
44
+ "./semaphore.cjs",
45
+ "./semaphore.d.ts",
46
+ "./mutex.cjs",
47
+ "./mutex.d.ts"
38
48
  ],
39
49
  "exports": {
40
50
  ".": {
@@ -101,6 +111,31 @@
101
111
  "require": "./ai.cjs",
102
112
  "import": "./ai.cjs",
103
113
  "types": "./ai.d.ts"
114
+ },
115
+ "./env": {
116
+ "require": "./env.cjs",
117
+ "import": "./env.cjs",
118
+ "types": "./env.d.ts"
119
+ },
120
+ "./async-queue": {
121
+ "require": "./async-queue.cjs",
122
+ "import": "./async-queue.cjs",
123
+ "types": "./async-queue.d.ts"
124
+ },
125
+ "./ratelimit": {
126
+ "require": "./ratelimit.cjs",
127
+ "import": "./ratelimit.cjs",
128
+ "types": "./ratelimit.d.ts"
129
+ },
130
+ "./semaphore": {
131
+ "require": "./semaphore.cjs",
132
+ "import": "./semaphore.cjs",
133
+ "types": "./semaphore.d.ts"
134
+ },
135
+ "./mutex": {
136
+ "require": "./mutex.cjs",
137
+ "import": "./mutex.cjs",
138
+ "types": "./mutex.d.ts"
104
139
  }
105
140
  },
106
141
  "repository": {
@@ -136,7 +171,7 @@
136
171
  "tsx": "^4.19.2",
137
172
  "typescript": "^5.7.3",
138
173
  "vitest": "^3.0.5",
139
- "tsconfig": "0.0.0-dev.20250622124751"
174
+ "tsconfig": "0.0.0-dev.20250622135945"
140
175
  },
141
176
  "peerDependencies": {
142
177
  "discord.js": "^14"