commandkit 1.0.0-dev.20250622061654 → 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,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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.js","names":[],"sources":["../../../src/utils/useful-stuff/mutex.ts"],"sourcesContent":["/**\n * Async mutex implementation for coordinating access to shared resources.\n * Provides mutual exclusion to ensure only one task can access a resource at a time.\n */\n\n/**\n * Interface for mutex storage implementations.\n * Provides methods to store, retrieve, and delete mutex lock data.\n */\nexport interface MutexStorage {\n /**\n * Attempts to acquire a lock for a given key\n * @param key - The unique identifier for the mutex lock\n * @param timeout - Optional timeout in milliseconds for the lock\n * @param signal - Optional AbortSignal for cancelling the acquisition\n * @returns Promise resolving to true if lock was acquired, false if timeout or already locked\n */\n acquire(\n key: string,\n timeout?: number,\n signal?: AbortSignal,\n ): Promise<boolean>;\n\n /**\n * Releases the lock for a given key\n * @param key - The unique identifier for the mutex lock\n * @returns Promise that resolves when the lock is released\n */\n release(key: string): Promise<void>;\n\n /**\n * Checks if a lock is currently held for a given key\n * @param key - The unique identifier for the mutex lock\n * @returns Promise resolving to true if the lock is held, false otherwise\n */\n isLocked(key: string): Promise<boolean>;\n}\n\n/**\n * Configuration options for mutex\n */\nexport interface MutexOptions {\n /** Default timeout in milliseconds for lock acquisition. Default: 30000 */\n timeout?: number;\n /** Storage implementation for persisting mutex data. Default: {@link MemoryMutexStorage} */\n storage?: MutexStorage;\n}\n\n/**\n * In-memory storage implementation for mutex locks.\n * Suitable for single-instance applications.\n */\nexport class MemoryMutexStorage implements MutexStorage {\n private readonly locks = new Map<\n string,\n { holder: string; acquiredAt: number }\n >();\n\n /**\n * Attempts to acquire a lock for a given key\n * @param key - The unique identifier for the mutex lock\n * @param timeout - Optional timeout in milliseconds for the lock\n * @param signal - Optional AbortSignal for cancelling the acquisition\n * @returns Promise resolving to true if lock was acquired, false if timeout or already locked\n */\n async acquire(\n key: string,\n timeout: number = 30000,\n signal?: AbortSignal,\n ): Promise<boolean> {\n const holder = this.generateHolderId();\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n // Check if aborted\n if (signal?.aborted) {\n throw new Error('Lock acquisition was aborted');\n }\n\n if (!this.locks.has(key)) {\n this.locks.set(key, { holder, acquiredAt: Date.now() });\n return true;\n }\n await this.delay(10);\n }\n\n return false;\n }\n\n /**\n * Releases the lock for a given key\n * @param key - The unique identifier for the mutex lock\n * @returns Promise that resolves when the lock is released\n */\n async release(key: string): Promise<void> {\n this.locks.delete(key);\n }\n\n /**\n * Checks if a lock is currently held for a given key\n * @param key - The unique identifier for the mutex lock\n * @returns Promise resolving to true if the lock is held, false otherwise\n */\n async isLocked(key: string): Promise<boolean> {\n return this.locks.has(key);\n }\n\n private generateHolderId(): string {\n return `holder_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\n/**\n * Async mutex implementation that provides mutual exclusion for shared resources.\n * Ensures only one task can access a protected resource at a time.\n */\nexport class Mutex {\n private storage: MutexStorage;\n private readonly defaultTimeout: number;\n\n /**\n * Creates a new mutex instance\n * @param options - Configuration options for the mutex\n */\n public constructor(options: MutexOptions = {}) {\n this.storage = options.storage || new MemoryMutexStorage();\n this.defaultTimeout = options.timeout || 30000;\n }\n\n /**\n * Sets the storage implementation for the mutex\n * @param storage - The storage implementation to use\n */\n public setStorage(storage: MutexStorage) {\n this.storage = storage;\n }\n\n /**\n * Gets the storage implementation for the mutex\n * @returns The storage implementation\n */\n public getStorage(): MutexStorage {\n return this.storage;\n }\n\n /**\n * Acquires a lock for the given key\n * @param key - The unique identifier for the mutex lock\n * @param timeout - Optional timeout in milliseconds for lock acquisition\n * @param signal - Optional AbortSignal for cancelling the acquisition\n * @returns Promise resolving to true if lock was acquired, false if timeout\n */\n public async acquire(\n key: string,\n timeout?: number,\n signal?: AbortSignal,\n ): Promise<boolean> {\n return this.storage.acquire(key, timeout || this.defaultTimeout, signal);\n }\n\n /**\n * Releases the lock for the given key\n * @param key - The unique identifier for the mutex lock\n * @returns Promise that resolves when the lock is released\n */\n public async release(key: string): Promise<void> {\n return this.storage.release(key);\n }\n\n /**\n * Checks if a lock is currently held for the given key\n * @param key - The unique identifier for the mutex lock\n * @returns Promise resolving to true if the lock is held, false otherwise\n */\n public async isLocked(key: string): Promise<boolean> {\n return this.storage.isLocked(key);\n }\n\n /**\n * Executes a function with exclusive access to the resource\n * @param key - The unique identifier for the mutex lock\n * @param fn - The function to execute with exclusive access\n * @param timeout - Optional timeout in milliseconds for lock acquisition\n * @param signal - Optional AbortSignal for cancelling the lock acquisition\n * @returns Promise resolving to the result of the function execution\n * @throws Error if lock acquisition fails or function execution fails\n */\n public async withLock<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 lock 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 mutex\n * @returns Object containing the current timeout value\n */\n public getConfig(): Omit<MutexOptions, 'storage'> {\n return {\n timeout: this.defaultTimeout,\n };\n }\n}\n\n/**\n * Default mutex instance for global use\n */\nexport const defaultMutex = new Mutex();\n\n/**\n * Convenience function to execute a function with exclusive access using the default mutex.\n *\n * @param key - The unique identifier for the mutex lock\n * @param fn - The function to execute with exclusive access\n * @param timeout - Optional timeout in milliseconds for lock acquisition\n * @param signal - Optional AbortSignal for cancelling the lock 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 withMutex('shared-resource', async () => {\n * // This code runs with exclusive access\n * return await updateSharedResource();\n * }, 30000, controller.signal);\n * controller.abort(); // Cancels the lock acquisition\n * ```\n */\nexport async function withMutex<T>(\n key: string,\n fn: () => Promise<T> | T,\n timeout?: number,\n signal?: AbortSignal,\n): Promise<T> {\n return defaultMutex.withLock(key, fn, timeout, signal);\n}\n\n/**\n * Creates a new mutex instance with the specified configuration\n * @param options - Configuration options for the mutex\n * @returns New Mutex instance\n *\n * @example\n * ```typescript\n * const mutex = createMutex({\n * timeout: 60000,\n * storage: new RedisMutexStorage()\n * });\n * ```\n */\nexport function createMutex(options: MutexOptions): Mutex {\n return new Mutex(options);\n}\n\n/**\n * Acquires a lock using the default mutex\n * @param key - The unique identifier for the mutex lock\n * @param timeout - Optional timeout in milliseconds for lock acquisition\n * @param signal - Optional AbortSignal for cancelling the acquisition\n * @returns Promise resolving to true if lock was acquired, false if timeout\n */\nexport async function acquireLock(\n key: string,\n timeout?: number,\n signal?: AbortSignal,\n): Promise<boolean> {\n return defaultMutex.acquire(key, timeout, signal);\n}\n\n/**\n * Releases a lock using the default mutex\n * @param key - The unique identifier for the mutex lock\n * @returns Promise that resolves when the lock is released\n */\nexport async function releaseLock(key: string): Promise<void> {\n return defaultMutex.release(key);\n}\n\n/**\n * Checks if a lock is held using the default mutex\n * @param key - The unique identifier for the mutex lock\n * @returns Promise resolving to true if the lock is held, false otherwise\n */\nexport async function isLocked(key: string): Promise<boolean> {\n return defaultMutex.isLocked(key);\n}\n"],"mappings":";;;;;;AAoDA,IAAa,qBAAb,MAAwD;CACtD,AAAiB,wBAAQ,IAAI;;;;;;;;CAY7B,MAAM,QACN,KACA,UAAkB,KAClB,QACmB;EACjB,MAAM,SAAS,KAAK,kBAAkB;EACtC,MAAM,YAAY,KAAK,KAAK;AAE5B,SAAO,KAAK,KAAK,GAAG,YAAY,SAAS;AAEvC,uDAAI,OAAQ,QACV,OAAM,IAAI,MAAM;AAGlB,QAAK,KAAK,MAAM,IAAI,IAAI,EAAE;AACxB,SAAK,MAAM,IAAI,KAAK;KAAE;KAAQ,YAAY,KAAK,KAAK;IAAE,EAAC;AACvD,WAAO;GACT;AACA,SAAM,KAAK,MAAM,GAAG;EACtB;AAEA,SAAO;CACT;;;;;;CAOA,MAAM,QAAQ,KAA4B;AACxC,OAAK,MAAM,OAAO,IAAI;CACxB;;;;;;CAOA,MAAM,SAAS,KAA+B;AAC5C,SAAO,KAAK,MAAM,IAAI,IAAI;CAC5B;CAEA,AAAQ,mBAA2B;AACjC,UAAQ,SAAS,KAAK,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,OAAO,GAAG,EAAE,CAAC;CACzE;CAEA,AAAQ,MAAM,IAA2B;AACvC,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG;CACzD;AACF;;;;;AAMA,IAAa,QAAb,MAAmB;CACjB,AAAQ;CACR,AAAiB;;;;;CAMjB,AAAO,YAAY,UAAwB,CAAE,GAAE;AAC7C,OAAK,UAAU,QAAQ,WAAW,IAAI;AACtC,OAAK,iBAAiB,QAAQ,WAAW;CAC3C;;;;;CAMA,AAAO,WAAW,SAAuB;AACvC,OAAK,UAAU;CACjB;;;;;CAMA,AAAO,aAA2B;AAChC,SAAO,KAAK;CACd;;;;;;;;CASA,MAAa,QACb,KACA,SACA,QACmB;AACjB,SAAO,KAAK,QAAQ,QAAQ,KAAK,WAAW,KAAK,gBAAgB,OAAO;CAC1E;;;;;;CAOA,MAAa,QAAQ,KAA4B;AAC/C,SAAO,KAAK,QAAQ,QAAQ,IAAI;CAClC;;;;;;CAOA,MAAa,SAAS,KAA+B;AACnD,SAAO,KAAK,QAAQ,SAAS,IAAI;CACnC;;;;;;;;;;CAWA,MAAa,SACb,KACA,IACA,SACA,QACa;EACX,MAAM,WAAW,MAAM,KAAK,QAAQ,KAAK,SAAS,OAAO;AACzD,OAAK,SACH,OAAM,IAAI,OAAO,kCAAkC,IAAI;AAGzD,MAAI;AACF,UAAO,MAAM,IAAI;EAClB,UAAS;AACR,SAAM,KAAK,QAAQ,IAAI;EACzB;CACF;;;;;CAMA,AAAO,YAA2C;AAChD,SAAO,EACL,SAAS,KAAK,eACf;CACH;AACF;;;;AAKA,MAAa,eAAe,IAAI;;;;;;;;;;;;;;;;;;;;AAqBhC,eAAsB,UACtB,KACA,IACA,SACA,QACa;AACX,QAAO,aAAa,SAAS,KAAK,IAAI,SAAS,OAAO;AACxD;;;;;;;;;;;;;;AAeA,SAAgB,YAAY,SAA8B;AACxD,QAAO,IAAI,MAAM;AACnB;;;;;;;;AASA,eAAsB,YACtB,KACA,SACA,QACmB;AACjB,QAAO,aAAa,QAAQ,KAAK,SAAS,OAAO;AACnD;;;;;;AAOA,eAAsB,YAAY,KAA4B;AAC5D,QAAO,aAAa,QAAQ,IAAI;AAClC;;;;;;AAOA,eAAsB,SAAS,KAA+B;AAC5D,QAAO,aAAa,SAAS,IAAI;AACnC"}
@@ -0,0 +1,193 @@
1
+ //#region src/utils/useful-stuff/ratelimiter.d.ts
2
+ /**
3
+ * Default timeout interval for rate limiting in milliseconds
4
+ */
5
+ declare const DEFAULT_TIMEOUT = 60000;
6
+ /**
7
+ * Default maximum number of requests allowed per interval
8
+ */
9
+ declare const DEFAULT_MAX_REQUESTS = 10;
10
+ /**
11
+ * Interface for rate limit storage implementations.
12
+ * Provides methods to store, retrieve, and delete rate limit data.
13
+ */
14
+ interface RateLimitStorage {
15
+ /**
16
+ * Retrieves the current request count for a given key
17
+ * @param key - The unique identifier for the rate limit entry
18
+ * @returns Promise resolving to the current request count
19
+ */
20
+ get(key: string): Promise<number>;
21
+ /**
22
+ * Sets the request count for a given key
23
+ * @param key - The unique identifier for the rate limit entry
24
+ * @param value - The request count to store
25
+ * @returns Promise that resolves when the value is stored
26
+ */
27
+ set(key: string, value: number): Promise<void>;
28
+ /**
29
+ * Deletes the rate limit entry for a given key
30
+ * @param key - The unique identifier for the rate limit entry
31
+ * @returns Promise that resolves when the entry is deleted
32
+ */
33
+ delete(key: string): Promise<void>;
34
+ }
35
+ /**
36
+ * Configuration options for rate limiting
37
+ */
38
+ interface RateLimitOptions {
39
+ /** Maximum number of requests allowed per interval. Default: 10 */
40
+ maxRequests?: number;
41
+ /** Time interval in milliseconds for the rate limit window. Default: 60000 */
42
+ interval?: number;
43
+ /** Storage implementation for persisting rate limit data. Default: {@link MemoryRateLimitStorage} */
44
+ storage?: RateLimitStorage;
45
+ }
46
+ /**
47
+ * In-memory storage implementation for rate limiting.
48
+ * Suitable for single-instance applications.
49
+ */
50
+ declare class MemoryRateLimitStorage implements RateLimitStorage {
51
+ private readonly store;
52
+ /**
53
+ * Retrieves the current request count for a given key
54
+ * @param key - The unique identifier for the rate limit entry
55
+ * @returns Promise resolving to the current request count or 0 if not found
56
+ */
57
+ get(key: string): Promise<number>;
58
+ /**
59
+ * Sets the request count for a given key
60
+ * @param key - The unique identifier for the rate limit entry
61
+ * @param value - The request count to store
62
+ * @returns Promise that resolves immediately
63
+ */
64
+ set(key: string, value: number): Promise<void>;
65
+ /**
66
+ * Deletes the rate limit entry for a given key
67
+ * @param key - The unique identifier for the rate limit entry
68
+ * @returns Promise that resolves immediately
69
+ */
70
+ delete(key: string): Promise<void>;
71
+ }
72
+ /**
73
+ * Rate limiter implementation that enforces request limits per key.
74
+ * Supports configurable request limits and time intervals.
75
+ */
76
+ declare class RateLimiter {
77
+ private readonly maxRequests;
78
+ private readonly interval;
79
+ private storage;
80
+ private readonly limits;
81
+ private readonly lastReset;
82
+ private readonly resetInterval;
83
+ /**
84
+ * Creates a new rate limiter instance
85
+ * @param maxRequests - Maximum number of requests allowed per interval (default: 10)
86
+ * @param interval - Time interval in milliseconds for the rate limit window (default: 60000)
87
+ * @param storage - Optional storage implementation (default: MemoryRateLimitStorage)
88
+ */
89
+ constructor(maxRequests?: number, interval?: number, storage?: RateLimitStorage);
90
+ /**
91
+ * Sets the storage implementation for the rate limiter
92
+ * @param storage - The storage implementation to use
93
+ */
94
+ setStorage(storage: RateLimitStorage): void;
95
+ /**
96
+ * Gets the storage implementation for the rate limiter
97
+ * @returns The storage implementation
98
+ */
99
+ getStorage(): RateLimitStorage;
100
+ /**
101
+ * Checks if a request is allowed for the given key and increments the counter if allowed
102
+ * @param key - The unique identifier for the rate limit entry
103
+ * @returns Promise resolving to true if the request is allowed, false if rate limited
104
+ */
105
+ limit(key: string): Promise<boolean>;
106
+ /**
107
+ * Gets the remaining requests allowed for a given key
108
+ * @param key - The unique identifier for the rate limit entry
109
+ * @returns Promise resolving to the number of remaining requests
110
+ */
111
+ getRemaining(key: string): Promise<number>;
112
+ /**
113
+ * Gets the time until the rate limit resets for a given key
114
+ * @param key - The unique identifier for the rate limit entry
115
+ * @returns Promise resolving to the time in milliseconds until reset, or 0 if no limit is active
116
+ */
117
+ getResetTime(key: string): Promise<number>;
118
+ /**
119
+ * Resets the rate limit for a given key
120
+ * @param key - The unique identifier for the rate limit entry
121
+ * @returns Promise that resolves when the reset is complete
122
+ */
123
+ reset(key: string): Promise<void>;
124
+ /**
125
+ * Gets the current configuration of the rate limiter
126
+ * @returns Object containing the current maxRequests and interval values
127
+ */
128
+ getConfig(): Omit<RateLimitOptions, 'storage'>;
129
+ }
130
+ /**
131
+ * Default rate limiter instance for global use
132
+ */
133
+ declare const defaultRateLimiter: RateLimiter;
134
+ /**
135
+ * Convenience function to check if a request is allowed for a given key.
136
+ * Uses the default rate limiter instance.
137
+ *
138
+ * @param key - The unique identifier for the rate limit entry
139
+ * @returns Promise resolving to true if the request is allowed, false if rate limited
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * const allowed = await ratelimit('user:123');
144
+ * // update the default rate limiter config
145
+ * import { defaultRateLimiter } from 'commandkit/ratelimit';
146
+ *
147
+ * // update max allowed requests
148
+ * defaultRateLimiter.setMaxRequests(10);
149
+ *
150
+ * // update the timeout interval
151
+ * defaultRateLimiter.setInterval(30000);
152
+ *
153
+ * // update the storage implementation
154
+ * defaultRateLimiter.setStorage(new RedisStorage());
155
+ * ```
156
+ */
157
+ declare function ratelimit(key: string): Promise<boolean>;
158
+ /**
159
+ * Creates a new rate limiter instance with the specified configuration
160
+ * @param options - Configuration options for the rate limiter
161
+ * @returns New RateLimiter instance
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * const limiter = createRateLimiter({
166
+ * maxRequests: 5,
167
+ * interval: 30000,
168
+ * storage: new CustomStorage()
169
+ * });
170
+ * ```
171
+ */
172
+ declare function createRateLimiter(options: RateLimitOptions): RateLimiter;
173
+ /**
174
+ * Gets the remaining requests for a key using the default rate limiter
175
+ * @param key - The unique identifier for the rate limit entry
176
+ * @returns Promise resolving to the number of remaining requests
177
+ */
178
+ declare function getRemainingRequests(key: string): Promise<number>;
179
+ /**
180
+ * Gets the reset time for a key using the default rate limiter
181
+ * @param key - The unique identifier for the rate limit entry
182
+ * @returns Promise resolving to the time in milliseconds until reset
183
+ */
184
+ declare function getResetTime(key: string): Promise<number>;
185
+ /**
186
+ * Resets the rate limit for a key using the default rate limiter
187
+ * @param key - The unique identifier for the rate limit entry
188
+ * @returns Promise that resolves when the reset is complete
189
+ */
190
+ declare function resetRateLimit(key: string): Promise<void>;
191
+ //#endregion
192
+ export { DEFAULT_MAX_REQUESTS, DEFAULT_TIMEOUT, MemoryRateLimitStorage, RateLimitOptions, RateLimitStorage, RateLimiter, createRateLimiter, defaultRateLimiter, getRemainingRequests, getResetTime, ratelimit, resetRateLimit };
193
+ //# sourceMappingURL=ratelimiter.d.ts.map
@@ -0,0 +1,223 @@
1
+
2
+ //#region src/utils/useful-stuff/ratelimiter.ts
3
+ /**
4
+ * Default timeout interval for rate limiting in milliseconds
5
+ */
6
+ const DEFAULT_TIMEOUT = 6e4;
7
+ /**
8
+ * Default maximum number of requests allowed per interval
9
+ */
10
+ const DEFAULT_MAX_REQUESTS = 10;
11
+ /**
12
+ * In-memory storage implementation for rate limiting.
13
+ * Suitable for single-instance applications.
14
+ */
15
+ var MemoryRateLimitStorage = class {
16
+ store = /* @__PURE__ */ new Map();
17
+ /**
18
+ * Retrieves the current request count for a given key
19
+ * @param key - The unique identifier for the rate limit entry
20
+ * @returns Promise resolving to the current request count or 0 if not found
21
+ */
22
+ async get(key) {
23
+ return this.store.get(key) || 0;
24
+ }
25
+ /**
26
+ * Sets the request count for a given key
27
+ * @param key - The unique identifier for the rate limit entry
28
+ * @param value - The request count to store
29
+ * @returns Promise that resolves immediately
30
+ */
31
+ async set(key, value) {
32
+ this.store.set(key, value);
33
+ }
34
+ /**
35
+ * Deletes the rate limit entry for a given key
36
+ * @param key - The unique identifier for the rate limit entry
37
+ * @returns Promise that resolves immediately
38
+ */
39
+ async delete(key) {
40
+ this.store.delete(key);
41
+ }
42
+ };
43
+ /**
44
+ * Rate limiter implementation that enforces request limits per key.
45
+ * Supports configurable request limits and time intervals.
46
+ */
47
+ var RateLimiter = class {
48
+ limits = /* @__PURE__ */ new Map();
49
+ lastReset = /* @__PURE__ */ new Map();
50
+ resetInterval;
51
+ /**
52
+ * Creates a new rate limiter instance
53
+ * @param maxRequests - Maximum number of requests allowed per interval (default: 10)
54
+ * @param interval - Time interval in milliseconds for the rate limit window (default: 60000)
55
+ * @param storage - Optional storage implementation (default: MemoryRateLimitStorage)
56
+ */
57
+ constructor(maxRequests = DEFAULT_MAX_REQUESTS, interval = DEFAULT_TIMEOUT, storage = new MemoryRateLimitStorage()) {
58
+ this.maxRequests = maxRequests;
59
+ this.interval = interval;
60
+ this.storage = storage;
61
+ this.resetInterval = interval;
62
+ }
63
+ /**
64
+ * Sets the storage implementation for the rate limiter
65
+ * @param storage - The storage implementation to use
66
+ */
67
+ setStorage(storage) {
68
+ this.storage = storage;
69
+ }
70
+ /**
71
+ * Gets the storage implementation for the rate limiter
72
+ * @returns The storage implementation
73
+ */
74
+ getStorage() {
75
+ return this.storage;
76
+ }
77
+ /**
78
+ * Checks if a request is allowed for the given key and increments the counter if allowed
79
+ * @param key - The unique identifier for the rate limit entry
80
+ * @returns Promise resolving to true if the request is allowed, false if rate limited
81
+ */
82
+ async limit(key) {
83
+ const now = Date.now();
84
+ const lastReset = this.lastReset.get(key) || 0;
85
+ const timeSinceReset = now - lastReset;
86
+ if (timeSinceReset > this.resetInterval) {
87
+ await this.storage.delete(key);
88
+ this.lastReset.set(key, now);
89
+ this.limits.set(key, 0);
90
+ }
91
+ const currentCount = await this.storage.get(key);
92
+ if (currentCount >= this.maxRequests) return false;
93
+ const newCount = currentCount + 1;
94
+ await this.storage.set(key, newCount);
95
+ this.limits.set(key, newCount);
96
+ return true;
97
+ }
98
+ /**
99
+ * Gets the remaining requests allowed for a given key
100
+ * @param key - The unique identifier for the rate limit entry
101
+ * @returns Promise resolving to the number of remaining requests
102
+ */
103
+ async getRemaining(key) {
104
+ const currentCount = await this.storage.get(key);
105
+ return Math.max(0, this.maxRequests - currentCount);
106
+ }
107
+ /**
108
+ * Gets the time until the rate limit resets for a given key
109
+ * @param key - The unique identifier for the rate limit entry
110
+ * @returns Promise resolving to the time in milliseconds until reset, or 0 if no limit is active
111
+ */
112
+ async getResetTime(key) {
113
+ const lastReset = this.lastReset.get(key) || 0;
114
+ const now = Date.now();
115
+ const timeSinceReset = now - lastReset;
116
+ if (timeSinceReset >= this.resetInterval) return 0;
117
+ return this.resetInterval - timeSinceReset;
118
+ }
119
+ /**
120
+ * Resets the rate limit for a given key
121
+ * @param key - The unique identifier for the rate limit entry
122
+ * @returns Promise that resolves when the reset is complete
123
+ */
124
+ async reset(key) {
125
+ await this.storage.delete(key);
126
+ this.limits.delete(key);
127
+ this.lastReset.delete(key);
128
+ }
129
+ /**
130
+ * Gets the current configuration of the rate limiter
131
+ * @returns Object containing the current maxRequests and interval values
132
+ */
133
+ getConfig() {
134
+ return {
135
+ maxRequests: this.maxRequests,
136
+ interval: this.interval
137
+ };
138
+ }
139
+ };
140
+ /**
141
+ * Default rate limiter instance for global use
142
+ */
143
+ const defaultRateLimiter = new RateLimiter();
144
+ /**
145
+ * Convenience function to check if a request is allowed for a given key.
146
+ * Uses the default rate limiter instance.
147
+ *
148
+ * @param key - The unique identifier for the rate limit entry
149
+ * @returns Promise resolving to true if the request is allowed, false if rate limited
150
+ *
151
+ * @example
152
+ * ```typescript
153
+ * const allowed = await ratelimit('user:123');
154
+ * // update the default rate limiter config
155
+ * import { defaultRateLimiter } from 'commandkit/ratelimit';
156
+ *
157
+ * // update max allowed requests
158
+ * defaultRateLimiter.setMaxRequests(10);
159
+ *
160
+ * // update the timeout interval
161
+ * defaultRateLimiter.setInterval(30000);
162
+ *
163
+ * // update the storage implementation
164
+ * defaultRateLimiter.setStorage(new RedisStorage());
165
+ * ```
166
+ */
167
+ async function ratelimit(key) {
168
+ return defaultRateLimiter.limit(key);
169
+ }
170
+ /**
171
+ * Creates a new rate limiter instance with the specified configuration
172
+ * @param options - Configuration options for the rate limiter
173
+ * @returns New RateLimiter instance
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * const limiter = createRateLimiter({
178
+ * maxRequests: 5,
179
+ * interval: 30000,
180
+ * storage: new CustomStorage()
181
+ * });
182
+ * ```
183
+ */
184
+ function createRateLimiter(options) {
185
+ return new RateLimiter(options.maxRequests, options.interval, options.storage);
186
+ }
187
+ /**
188
+ * Gets the remaining requests for a key using the default rate limiter
189
+ * @param key - The unique identifier for the rate limit entry
190
+ * @returns Promise resolving to the number of remaining requests
191
+ */
192
+ async function getRemainingRequests(key) {
193
+ return defaultRateLimiter.getRemaining(key);
194
+ }
195
+ /**
196
+ * Gets the reset time for a key using the default rate limiter
197
+ * @param key - The unique identifier for the rate limit entry
198
+ * @returns Promise resolving to the time in milliseconds until reset
199
+ */
200
+ async function getResetTime(key) {
201
+ return defaultRateLimiter.getResetTime(key);
202
+ }
203
+ /**
204
+ * Resets the rate limit for a key using the default rate limiter
205
+ * @param key - The unique identifier for the rate limit entry
206
+ * @returns Promise that resolves when the reset is complete
207
+ */
208
+ async function resetRateLimit(key) {
209
+ return defaultRateLimiter.reset(key);
210
+ }
211
+
212
+ //#endregion
213
+ exports.DEFAULT_MAX_REQUESTS = DEFAULT_MAX_REQUESTS;
214
+ exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
215
+ exports.MemoryRateLimitStorage = MemoryRateLimitStorage;
216
+ exports.RateLimiter = RateLimiter;
217
+ exports.createRateLimiter = createRateLimiter;
218
+ exports.defaultRateLimiter = defaultRateLimiter;
219
+ exports.getRemainingRequests = getRemainingRequests;
220
+ exports.getResetTime = getResetTime;
221
+ exports.ratelimit = ratelimit;
222
+ exports.resetRateLimit = resetRateLimit;
223
+ //# sourceMappingURL=ratelimiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ratelimiter.js","names":[],"sources":["../../../src/utils/useful-stuff/ratelimiter.ts"],"sourcesContent":["/**\n * Default timeout interval for rate limiting in milliseconds\n */\nexport const DEFAULT_TIMEOUT = 60000;\n\n/**\n * Default maximum number of requests allowed per interval\n */\nexport const DEFAULT_MAX_REQUESTS = 10;\n\n/**\n * Interface for rate limit storage implementations.\n * Provides methods to store, retrieve, and delete rate limit data.\n */\nexport interface RateLimitStorage {\n /**\n * Retrieves the current request count for a given key\n * @param key - The unique identifier for the rate limit entry\n * @returns Promise resolving to the current request count\n */\n get(key: string): Promise<number>;\n\n /**\n * Sets the request count for a given key\n * @param key - The unique identifier for the rate limit entry\n * @param value - The request count to store\n * @returns Promise that resolves when the value is stored\n */\n set(key: string, value: number): Promise<void>;\n\n /**\n * Deletes the rate limit entry for a given key\n * @param key - The unique identifier for the rate limit entry\n * @returns Promise that resolves when the entry is deleted\n */\n delete(key: string): Promise<void>;\n}\n\n/**\n * Configuration options for rate limiting\n */\nexport interface RateLimitOptions {\n /** Maximum number of requests allowed per interval. Default: 10 */\n maxRequests?: number;\n /** Time interval in milliseconds for the rate limit window. Default: 60000 */\n interval?: number;\n /** Storage implementation for persisting rate limit data. Default: {@link MemoryRateLimitStorage} */\n storage?: RateLimitStorage;\n}\n\n/**\n * In-memory storage implementation for rate limiting.\n * Suitable for single-instance applications.\n */\nexport class MemoryRateLimitStorage implements RateLimitStorage {\n private readonly store = new Map<string, number>();\n\n /**\n * Retrieves the current request count for a given key\n * @param key - The unique identifier for the rate limit entry\n * @returns Promise resolving to the current request count or 0 if not found\n */\n async get(key: string): Promise<number> {\n return this.store.get(key) || 0;\n }\n\n /**\n * Sets the request count for a given key\n * @param key - The unique identifier for the rate limit entry\n * @param value - The request count to store\n * @returns Promise that resolves immediately\n */\n async set(key: string, value: number): Promise<void> {\n this.store.set(key, value);\n }\n\n /**\n * Deletes the rate limit entry for a given key\n * @param key - The unique identifier for the rate limit entry\n * @returns Promise that resolves immediately\n */\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n}\n\n/**\n * Rate limiter implementation that enforces request limits per key.\n * Supports configurable request limits and time intervals.\n */\nexport class RateLimiter {\n private readonly limits: Map<string, number> = new Map();\n private readonly lastReset: Map<string, number> = new Map();\n private readonly resetInterval: number;\n\n /**\n * Creates a new rate limiter instance\n * @param maxRequests - Maximum number of requests allowed per interval (default: 10)\n * @param interval - Time interval in milliseconds for the rate limit window (default: 60000)\n * @param storage - Optional storage implementation (default: MemoryRateLimitStorage)\n */\n public constructor(\n private readonly maxRequests: number = DEFAULT_MAX_REQUESTS,\n private readonly interval: number = DEFAULT_TIMEOUT,\n private storage: RateLimitStorage = new MemoryRateLimitStorage(),\n ) {\n this.resetInterval = interval;\n }\n\n /**\n * Sets the storage implementation for the rate limiter\n * @param storage - The storage implementation to use\n */\n public setStorage(storage: RateLimitStorage) {\n this.storage = storage;\n }\n\n /**\n * Gets the storage implementation for the rate limiter\n * @returns The storage implementation\n */\n public getStorage(): RateLimitStorage {\n return this.storage;\n }\n\n /**\n * Checks if a request is allowed for the given key and increments the counter if allowed\n * @param key - The unique identifier for the rate limit entry\n * @returns Promise resolving to true if the request is allowed, false if rate limited\n */\n public async limit(key: string): Promise<boolean> {\n const now = Date.now();\n const lastReset = this.lastReset.get(key) || 0;\n const timeSinceReset = now - lastReset;\n\n // Reset counter if interval has passed\n if (timeSinceReset > this.resetInterval) {\n await this.storage.delete(key);\n this.lastReset.set(key, now);\n this.limits.set(key, 0);\n }\n\n // Get current count from storage\n const currentCount = await this.storage.get(key);\n\n // Check if limit exceeded\n if (currentCount >= this.maxRequests) {\n return false;\n }\n\n // Increment counter\n const newCount = currentCount + 1;\n await this.storage.set(key, newCount);\n this.limits.set(key, newCount);\n\n return true;\n }\n\n /**\n * Gets the remaining requests allowed for a given key\n * @param key - The unique identifier for the rate limit entry\n * @returns Promise resolving to the number of remaining requests\n */\n public async getRemaining(key: string): Promise<number> {\n const currentCount = await this.storage.get(key);\n return Math.max(0, this.maxRequests - currentCount);\n }\n\n /**\n * Gets the time until the rate limit resets for a given key\n * @param key - The unique identifier for the rate limit entry\n * @returns Promise resolving to the time in milliseconds until reset, or 0 if no limit is active\n */\n public async getResetTime(key: string): Promise<number> {\n const lastReset = this.lastReset.get(key) || 0;\n const now = Date.now();\n const timeSinceReset = now - lastReset;\n\n if (timeSinceReset >= this.resetInterval) {\n return 0;\n }\n\n return this.resetInterval - timeSinceReset;\n }\n\n /**\n * Resets the rate limit for a given key\n * @param key - The unique identifier for the rate limit entry\n * @returns Promise that resolves when the reset is complete\n */\n public async reset(key: string): Promise<void> {\n await this.storage.delete(key);\n this.limits.delete(key);\n this.lastReset.delete(key);\n }\n\n /**\n * Gets the current configuration of the rate limiter\n * @returns Object containing the current maxRequests and interval values\n */\n public getConfig(): Omit<RateLimitOptions, 'storage'> {\n return {\n maxRequests: this.maxRequests,\n interval: this.interval,\n };\n }\n}\n\n/**\n * Default rate limiter instance for global use\n */\nexport const defaultRateLimiter = new RateLimiter();\n\n/**\n * Convenience function to check if a request is allowed for a given key.\n * Uses the default rate limiter instance.\n *\n * @param key - The unique identifier for the rate limit entry\n * @returns Promise resolving to true if the request is allowed, false if rate limited\n *\n * @example\n * ```typescript\n * const allowed = await ratelimit('user:123');\n * // update the default rate limiter config\n * import { defaultRateLimiter } from 'commandkit/ratelimit';\n *\n * // update max allowed requests\n * defaultRateLimiter.setMaxRequests(10);\n *\n * // update the timeout interval\n * defaultRateLimiter.setInterval(30000);\n *\n * // update the storage implementation\n * defaultRateLimiter.setStorage(new RedisStorage());\n * ```\n */\nexport async function ratelimit(key: string): Promise<boolean> {\n return defaultRateLimiter.limit(key);\n}\n\n/**\n * Creates a new rate limiter instance with the specified configuration\n * @param options - Configuration options for the rate limiter\n * @returns New RateLimiter instance\n *\n * @example\n * ```typescript\n * const limiter = createRateLimiter({\n * maxRequests: 5,\n * interval: 30000,\n * storage: new CustomStorage()\n * });\n * ```\n */\nexport function createRateLimiter(options: RateLimitOptions): RateLimiter {\n return new RateLimiter(\n options.maxRequests,\n options.interval,\n options.storage,\n );\n}\n\n/**\n * Gets the remaining requests for a key using the default rate limiter\n * @param key - The unique identifier for the rate limit entry\n * @returns Promise resolving to the number of remaining requests\n */\nexport async function getRemainingRequests(key: string): Promise<number> {\n return defaultRateLimiter.getRemaining(key);\n}\n\n/**\n * Gets the reset time for a key using the default rate limiter\n * @param key - The unique identifier for the rate limit entry\n * @returns Promise resolving to the time in milliseconds until reset\n */\nexport async function getResetTime(key: string): Promise<number> {\n return defaultRateLimiter.getResetTime(key);\n}\n\n/**\n * Resets the rate limit for a key using the default rate limiter\n * @param key - The unique identifier for the rate limit entry\n * @returns Promise that resolves when the reset is complete\n */\nexport async function resetRateLimit(key: string): Promise<void> {\n return defaultRateLimiter.reset(key);\n}\n"],"mappings":";;;;;AAGA,MAAa,kBAAkB;;;;AAK/B,MAAa,uBAAuB;;;;;AA8CpC,IAAa,yBAAb,MAAgE;CAC9D,AAAiB,wBAAQ,IAAI;;;;;;CAO7B,MAAM,IAAI,KAA8B;AACtC,SAAO,KAAK,MAAM,IAAI,IAAI,IAAI;CAChC;;;;;;;CAQA,MAAM,IAAI,KAAa,OAA8B;AACnD,OAAK,MAAM,IAAI,KAAK,MAAM;CAC5B;;;;;;CAOA,MAAM,OAAO,KAA4B;AACvC,OAAK,MAAM,OAAO,IAAI;CACxB;AACF;;;;;AAMA,IAAa,cAAb,MAAyB;CACvB,AAAiB,yBAA8B,IAAI;CACnD,AAAiB,4BAAiC,IAAI;CACtD,AAAiB;;;;;;;CAQjB,AAAO,YACU,cAAsB,sBACtB,WAAmB,iBAC5B,UAA4B,IAAI,0BACxC;EAHiB;EACA;EACT;AAEN,OAAK,gBAAgB;CACvB;;;;;CAMA,AAAO,WAAW,SAA2B;AAC3C,OAAK,UAAU;CACjB;;;;;CAMA,AAAO,aAA+B;AACpC,SAAO,KAAK;CACd;;;;;;CAOA,MAAa,MAAM,KAA+B;EAChD,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,YAAY,KAAK,UAAU,IAAI,IAAI,IAAI;EAC7C,MAAM,iBAAiB,MAAM;AAG7B,MAAI,iBAAiB,KAAK,eAAe;AACvC,SAAM,KAAK,QAAQ,OAAO,IAAI;AAC9B,QAAK,UAAU,IAAI,KAAK,IAAI;AAC5B,QAAK,OAAO,IAAI,KAAK,EAAE;EACzB;EAGA,MAAM,eAAe,MAAM,KAAK,QAAQ,IAAI,IAAI;AAGhD,MAAI,gBAAgB,KAAK,YACvB,QAAO;EAIT,MAAM,WAAW,eAAe;AAChC,QAAM,KAAK,QAAQ,IAAI,KAAK,SAAS;AACrC,OAAK,OAAO,IAAI,KAAK,SAAS;AAE9B,SAAO;CACT;;;;;;CAOA,MAAa,aAAa,KAA8B;EACtD,MAAM,eAAe,MAAM,KAAK,QAAQ,IAAI,IAAI;AAChD,SAAO,KAAK,IAAI,GAAG,KAAK,cAAc,aAAa;CACrD;;;;;;CAOA,MAAa,aAAa,KAA8B;EACtD,MAAM,YAAY,KAAK,UAAU,IAAI,IAAI,IAAI;EAC7C,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,iBAAiB,MAAM;AAE7B,MAAI,kBAAkB,KAAK,cACzB,QAAO;AAGT,SAAO,KAAK,gBAAgB;CAC9B;;;;;;CAOA,MAAa,MAAM,KAA4B;AAC7C,QAAM,KAAK,QAAQ,OAAO,IAAI;AAC9B,OAAK,OAAO,OAAO,IAAI;AACvB,OAAK,UAAU,OAAO,IAAI;CAC5B;;;;;CAMA,AAAO,YAA+C;AACpD,SAAO;GACL,aAAa,KAAK;GAClB,UAAU,KAAK;EAChB;CACH;AACF;;;;AAKA,MAAa,qBAAqB,IAAI;;;;;;;;;;;;;;;;;;;;;;;;AAyBtC,eAAsB,UAAU,KAA+B;AAC7D,QAAO,mBAAmB,MAAM,IAAI;AACtC;;;;;;;;;;;;;;;AAgBA,SAAgB,kBAAkB,SAAwC;AACxE,QAAO,IAAI,YACT,QAAQ,aACR,QAAQ,UACR,QAAQ;AAEZ;;;;;;AAOA,eAAsB,qBAAqB,KAA8B;AACvE,QAAO,mBAAmB,aAAa,IAAI;AAC7C;;;;;;AAOA,eAAsB,aAAa,KAA8B;AAC/D,QAAO,mBAAmB,aAAa,IAAI;AAC7C;;;;;;AAOA,eAAsB,eAAe,KAA4B;AAC/D,QAAO,mBAAmB,MAAM,IAAI;AACtC"}