@@ -2,71 +2,44 @@ import {AttemptResult} from "./AttemptResult";
22
33/**
44 * Rate limit
5- * @class
65 */
76export class RateLimit {
87 /**
98 * Rate limit instances
10- * @private
11- * @static
12- * @type {Map<string, RateLimit> }
9+ * @internal
1310 */
14- static #instances = new Map < string , RateLimit > ( ) ;
11+ static readonly #instances = new Map < string , RateLimit > ( ) ;
1512
1613 /**
1714 * Whether this rate limit is deleted
18- * @private
19- * @type {boolean }
15+ * @internal
2016 */
2117 #deleted = false ;
2218
2319 /**
24- * Attempts memory
25- * @private
26- * @type {Map<string, [number, number]> }
20+ * Attempts memory. First number is attempts, second number is timestamp
21+ * @internal
2722 */
28- #attempts = new Map < string , [ number , number ] > ( ) ;
29-
30- /**
31- * Name of the rate limit
32- * @readonly
33- * @type {string }
34- */
35- readonly name : string ;
36- /**
37- * The number of requests allowed per time window
38- * @type {number }
39- */
40- limit : number ;
41- /**
42- * The time window in seconds (e.g. 60)
43- * @type {number }
44- */
45- timeWindow : number ;
23+ readonly #attempts = new Map < string , [ number , number ] > ( ) ;
4624
4725 /**
4826 * Create a new rate limit
49- * @param {string } name - The name of the rate limit
50- * @param {number } limit - The number of requests allowed per time window (e.g. 60)
51- * @param {number } timeWindow - The time window in seconds (e.g. 60)
52- * @returns {RateLimit }
27+ * @param name - The name of the rate limit
28+ * @param limit - The number of requests allowed per time window (e.g. 60)
29+ * @param timeWindow - The time window in seconds (e.g. 60)
5330 * @throws {Error } - If the rate limit already exists
5431 */
55- constructor ( name : string , limit : number , timeWindow : number ) {
32+ public constructor ( public readonly name : string , public readonly limit : number , public readonly timeWindow : number ) {
5633 if ( RateLimit . #instances. has ( name ) ) throw new Error ( `Rate limit with name "${ name } " already exists` ) ;
57- this . name = name ;
58- this . limit = limit ;
59- this . timeWindow = timeWindow ;
6034 RateLimit . #instances. set ( name , this ) ;
6135 }
6236
6337 /**
6438 * Check the attempt state for a source ID without decrementing the remaining attempts
65- * @param {string } source - Unique source identifier (e.g. username, IP, etc.)
66- * @param {function(AttemptResult): void } [callback] - Return data in a callback
67- * @returns {AttemptResult }
39+ * @param source - Unique source identifier (e.g. username, IP, etc.)
40+ * @param [callback] - Return data in a callback
6841 */
69- check ( source : string , callback ?: ( result : AttemptResult ) => void ) : AttemptResult {
42+ public check ( source : string , callback ?: ( result : AttemptResult ) => void ) : AttemptResult {
7043 if ( this . #deleted) throw new Error ( `Rate limit "${ this . name } " has been deleted. Construct a new instance` ) ;
7144 const attempts = this . #attempts. get ( source ) ?? [ 0 , Date . now ( ) ] ;
7245 const remaining = this . limit - attempts [ 0 ] ;
@@ -84,12 +57,11 @@ export class RateLimit {
8457
8558 /**
8659 * Make an attempt with a source ID
87- * @param {string } source - Unique source identifier (e.g. username, IP, etc.)
88- * @param {number } [attempts=1] - The number of attempts to make
89- * @param {function(AttemptResult): void } [callback] - Return data in a callback
90- * @returns {AttemptResult }
60+ * @param source - Unique source identifier (e.g. username, IP, etc.)
61+ * @param [attempts=1] - The number of attempts to make
62+ * @param [callback] - Return data in a callback
9163 */
92- attempt ( source : string , attempts : number = 1 , callback ?: ( result : AttemptResult ) => void ) : AttemptResult {
64+ public attempt ( source : string , attempts : number = 1 , callback ?: ( result : AttemptResult ) => void ) : AttemptResult {
9365 if ( this . #deleted) throw new Error ( `Rate limit "${ this . name } " has been deleted. Construct a new instance` ) ;
9466 const data = this . #attempts. get ( source ) ?? [ 0 , Date . now ( ) ] ;
9567 // if the time window has expired, reset the attempts
@@ -105,22 +77,20 @@ export class RateLimit {
10577
10678 /**
10779 * Reset limit for a source ID. The storage entry will be deleted and a new one will be created on the next attempt.
108- * @param {string } source - Unique source identifier (e.g. username, IP, etc.)
109- * @returns {void }
80+ * @param source - Unique source identifier (e.g. username, IP, etc.)
11081 */
111- reset ( source : string ) : void {
82+ public reset ( source : string ) : void {
11283 if ( this . #deleted) throw new Error ( `Rate limit "${ this . name } " has been deleted. Construct a new instance` ) ;
11384 this . #attempts. delete ( source ) ;
11485 }
11586
11687 /**
11788 * Set the remaining attempts for a source ID.
11889 * > **Warning**: This is not recommended as the remaining attempts depend on the limit of the instance.
119- * @param {string } source - Unique source identifier (e.g. username, IP, etc.)
120- * @param {number } remaining - The number of remaining attempts
121- * @returns {void }
90+ * @param source - Unique source identifier (e.g. username, IP, etc.)
91+ * @param remaining - The number of remaining attempts
12292 */
123- setRemaining ( source : string , remaining : number ) : void {
93+ public setRemaining ( source : string , remaining : number ) : void {
12494 if ( this . #deleted) throw new Error ( `Rate limit "${ this . name } " has been deleted. Construct a new instance` ) ;
12595 const data = this . #attempts. get ( source ) ?? [ 0 , Date . now ( ) ] ;
12696 data [ 0 ] = this . limit - remaining ;
@@ -129,73 +99,63 @@ export class RateLimit {
12999
130100 /**
131101 * Clear rate limit attempts storage. This is equivalent to resetting all rate limits.
132- * @returns {void }
133102 */
134- clear ( ) : void {
103+ public clear ( ) : void {
135104 if ( this . #deleted) throw new Error ( `Rate limit "${ this . name } " has been deleted. Construct a new instance` ) ;
136105 this . #attempts. clear ( ) ;
137106 }
138107
139108 /**
140109 * Delete the rate limit instance. After it is deleted, it should not be used any further without constructing a new instance.
141- * @returns {void }
142110 */
143- delete ( ) : void {
111+ public delete ( ) : void {
144112 this . clear ( ) ;
145113 this . #deleted = true ;
146114 RateLimit . #instances. delete ( this . name ) ;
147115 }
148116
149117 /**
150118 * Get a rate limit instance
151- * @param {string } name - The name of the rate limit
152- * @returns {RateLimit | null }
153- * @static
119+ * @param name - The name of the rate limit
154120 */
155- static get ( name : string ) : RateLimit | null {
121+ public static get ( name : string ) : RateLimit | null {
156122 return RateLimit . #instances. get ( name ) ?? null ;
157123 }
158124
159125 /**
160126 * Check the attempt state for a source ID without decrementing the remaining attempts
161- * @param {string } name - The name of the rate limit
162- * @param {string } source - Unique source identifier (e.g. username, IP, etc.)
163- * @param {function(AttemptResult): void } [callback] - Return data in a callback
164- * @returns {AttemptResult }
127+ * @param name - The name of the rate limit
128+ * @param source - Unique source identifier (e.g. username, IP, etc.)
129+ * @param [callback] - Return data in a callback
165130 * @throws {Error } - If the rate limit does not exist
166- * @static
167131 */
168- static check ( name : string , source : string , callback ?: ( result : AttemptResult ) => void ) : AttemptResult {
132+ public static check ( name : string , source : string , callback ?: ( result : AttemptResult ) => void ) : AttemptResult {
169133 const rateLimit = RateLimit . get ( name ) ;
170134 if ( ! rateLimit ) throw new Error ( `Rate limit with name "${ name } " does not exist` ) ;
171135 return rateLimit . check ( source , callback ) ;
172136 }
173137
174138 /**
175139 * Make an attempt with a source ID
176- * @param {string } name - The name of the rate limit
177- * @param {string } source - Unique source identifier (e.g. username, IP, etc.)
178- * @param {number } [attempts=1] - The number of attempts to make
179- * @param {function(AttemptResult): void } [callback] - Return data in a callback
180- * @returns {AttemptResult }
140+ * @param name - The name of the rate limit
141+ * @param source - Unique source identifier (e.g. username, IP, etc.)
142+ * @param [attempts=1] - The number of attempts to make
143+ * @param [callback] - Return data in a callback
181144 * @throws {Error } - If the rate limit does not exist
182- * @static
183145 */
184- static attempt ( name : string , source : string , attempts : number = 1 , callback ?: ( result : AttemptResult ) => void ) : AttemptResult {
146+ public static attempt ( name : string , source : string , attempts : number = 1 , callback ?: ( result : AttemptResult ) => void ) : AttemptResult {
185147 const rateLimit = RateLimit . get ( name ) ;
186148 if ( ! rateLimit ) throw new Error ( `Rate limit with name "${ name } " does not exist` ) ;
187149 return rateLimit . attempt ( source , attempts , callback ) ;
188150 }
189151
190152 /**
191153 * Reset limit for a source ID. The storage entry will be deleted and a new one will be created on the next attempt.
192- * @param {string } name - The name of the rate limit
193- * @param {string } source - Unique source identifier (e.g. username, IP, etc.)
194- * @returns {void }
154+ * @param name - The name of the rate limit
155+ * @param source - Unique source identifier (e.g. username, IP, etc.)
195156 * @throws {Error } - If the rate limit does not exist
196- * @static
197157 */
198- static reset ( name : string , source : string ) : void {
158+ public static reset ( name : string , source : string ) : void {
199159 const rateLimit = RateLimit . get ( name ) ;
200160 if ( ! rateLimit ) throw new Error ( `Rate limit with name "${ name } " does not exist` ) ;
201161 return rateLimit . reset ( source ) ;
@@ -204,54 +164,46 @@ export class RateLimit {
204164 /**
205165 * Set the remaining attempts for a source ID.
206166 * > **Warning**: This is not recommended as the remaining attempts depend on the limit of the instance.
207- * @param {string } name - The name of the rate limit
208- * @param {string } source - Unique source identifier (e.g. username, IP, etc.)
209- * @param {number } remaining - The number of remaining attempts
210- * @returns {void }
167+ * @param name - The name of the rate limit
168+ * @param source - Unique source identifier (e.g. username, IP, etc.)
169+ * @param remaining - The number of remaining attempts
211170 * @throws {Error } - If the rate limit does not exist
212- * @static
213171 */
214- static setRemaining ( name : string , source : string , remaining : number ) : void {
172+ public static setRemaining ( name : string , source : string , remaining : number ) : void {
215173 const rateLimit = RateLimit . get ( name ) ;
216174 if ( ! rateLimit ) throw new Error ( `Rate limit with name "${ name } " does not exist` ) ;
217175 return rateLimit . setRemaining ( source , remaining ) ;
218176 }
219177
220178 /**
221179 * Clear rate limit attempts storage. This is equivalent to resetting all rate limits.
222- * @param {string } name - The name of the rate limit
223- * @returns {void }
180+ * @param name - The name of the rate limit
224181 * @throws {Error } - If the rate limit does not exist
225- * @static
226182 */
227- static clear ( name : string ) : void {
183+ public static clear ( name : string ) : void {
228184 const rateLimit = RateLimit . get ( name ) ;
229185 if ( ! rateLimit ) throw new Error ( `Rate limit with name "${ name } " does not exist` ) ;
230186 return rateLimit . clear ( ) ;
231187 }
232188
233189 /**
234190 * Delete the rate limit instance. After it is deleted, it should not be used any further without constructing a new instance.
235- * @param {string } name - The name of the rate limit
236- * @returns {void }
191+ * @param name - The name of the rate limit
237192 * @throws {Error } - If the rate limit does not exist
238- * @static
239193 */
240- static delete ( name : string ) : void {
194+ public static delete ( name : string ) : void {
241195 const rateLimit = RateLimit . get ( name ) ;
242196 if ( ! rateLimit ) throw new Error ( `Rate limit with name "${ name } " does not exist` ) ;
243197 return rateLimit . delete ( ) ;
244198 }
245199
246200 /**
247201 * Create a new rate limit
248- * @param {string } name - The name of the rate limit
249- * @param {number } limit - The number of attempts allowed per time window (e.g. 60)
250- * @param {number } timeWindow - The time window in seconds (e.g. 60)
251- * @returns {RateLimit }
252- * @static
202+ * @param name - The name of the rate limit
203+ * @param limit - The number of attempts allowed per time window (e.g. 60)
204+ * @param timeWindow - The time window in seconds (e.g. 60)
253205 */
254- static create ( name : string , limit : number , timeWindow : number ) : RateLimit {
206+ public static create ( name : string , limit : number , timeWindow : number ) : RateLimit {
255207 const existing = RateLimit . get ( name ) ;
256208 if ( existing ) return existing ;
257209 return new RateLimit ( name , limit , timeWindow ) ;
0 commit comments