Skip to content
This repository was archived by the owner on Apr 15, 2025. It is now read-only.

Commit cf8acce

Browse files
author
williamd5
authored
Merge pull request #2 from cloudnode-pro/feature/readme
Create useful readme and document API
2 parents 67a66cb + d782b3f commit cf8acce

File tree

14 files changed

+663
-50
lines changed

14 files changed

+663
-50
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
name: Unit tests
22
'on':
33
pull_request:
4-
types:
5-
- opened
6-
- synchronize
7-
- reopened
8-
schedule:
9-
- cron: '0 6 * * 0'
10-
4+
types: [ opened, synchronize, reopened ]
115
jobs:
126
test:
137
name: 'Node.js v${{ matrix.node }}'

README.md

Lines changed: 253 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,253 @@
1-
# ratelimit
2-
Utility for implementing rate limits
1+
# Rate limiting utility
2+
![version: 1.1.0](https://img.shields.io/badge/version-1.1.0-%233b82f6)
3+
![test: passing](https://img.shields.io/badge/tests-passing-%2316a34a)
4+
![coverage: 100%](https://img.shields.io/badge/coverage-100%25-%2316a34a)
5+
![build: passing](https://img.shields.io/badge/build-passing-%2316a34a)
6+
7+
A relatively simple utility for abstract rate limiting. This library uses memory storage (i.e. does not rely on external database or writing data on your file system). Rate limits are reset if the process is restarted.
8+
9+
# Get started
10+
#### Install package from `npm`
11+
```sh
12+
npm i cldn-ratelimit
13+
```
14+
#### Import in your project
15+
Here is a very simple demo demonstrating very basic limiting of login attempts.
16+
```js
17+
import {RateLimit} from 'cldn-ratelimit';
18+
19+
const rateLimit = new RateLimit("login-attempts", 3, 60); // max 3 requests per 60 seconds
20+
21+
const attemptLogin = (username, password) => {
22+
if (!rateLimit.attempt(username).allow) return "rate-limited";
23+
if (username === "john.doe" && password === "password123") return "success";
24+
return "wrong-password";
25+
}
26+
27+
attemptLogin("john.doe", "wrongpass"); //-> "wrong-password"
28+
attemptLogin("john.doe", "wrongpass2"); //-> "wrong-password"
29+
attemptLogin("john.doe", "wrongpass"); //-> "wrong-password"
30+
attemptLogin("john.doe", "password123"); //-> "rate-limited"
31+
// wait 60 seconds
32+
attemptLogin("john.doe", "password123"); //-> "success"
33+
```
34+
35+
If you want to reset the rate limit after a successful login, call [`rateLimit.reset(username)`](#ratelimitresetsource).
36+
37+
# Documentation
38+
<details open>
39+
<summary>Table of contents</summary>
40+
41+
- [Class: `RateLimit`](#class-ratelimit)
42+
- [Static method: `RateLimit.attempt(name, source, [attempts])`](#static-method-ratelimitattemptname-source-attempts)
43+
- [Static method: `RateLimit.check(name, source)`](#static-method-ratelimitcheckname-source)
44+
- [Static method: `RateLimit.clear(name)`](#static-method-ratelimitclearname)
45+
- [Static method: `RateLimit.create(name, limit, timeWindow)`](#static-method-ratelimitcreatename-limit-timewindow)
46+
- [Static method: `RateLimit.delete(name)`](#static-method-ratelimitdeletename)
47+
- [Static method: `RateLimit.get(name)`](#static-method-ratelimitgetname)
48+
- [Static method: `RateLimit.reset(name, source)`](#static-method-ratelimitresetname-source)
49+
- [Static method: `RateLimit.setRemaining(name, source, remaining)`](#static-method-ratelimitsetremainingname-source-remaining)
50+
- [`new RateLimit(name, limit, timeWindow)`](#new-ratelimitname-limit-timewindow)
51+
- [`rateLimit.attempt(source, [attempts])`](#ratelimitattemptsource-attempts)
52+
- [`rateLimit.check(source)`](#ratelimitchecksource)
53+
- [`rateLimit.clear()`](#ratelimitclear)
54+
- [`rateLimit.delete()`](#ratelimitdelete)
55+
- [`rateLimit.limit`](#ratelimitlimit)
56+
- [`rateLimit.name`](#ratelimitname)
57+
- [`rateLimit.reset(source)`](#ratelimitresetsource)
58+
- [`rateLimit.setRemaining(source, remaining)`](#ratelimitsetremainingsource-remaining)
59+
- [`rateLimit.timeWindow`](#ratelimittimewindow)
60+
- [Interface: `AttemptResult`](#interface-attemptresult)
61+
- [`attemptResult.limit`](#attemptresultlimit)
62+
- [`attemptResult.remaining`](#attemptresultremaining)
63+
- [`attemptResult.reset`](#attemptresultreset)
64+
- [`attemptResult.rateLimit`](#attemptresultratelimit)
65+
- [`attemptResult.allow`](#attemptresultallow)
66+
</details>
67+
68+
<a name="class-ratelimit"></a>
69+
## Class: `RateLimit`
70+
Rate limit
71+
72+
<a name="static-method-ratelimitattemptname-source-attempts"></a>
73+
### Static method: `RateLimit.attempt(name, source, [attempts])`
74+
Make an attempt with a source ID
75+
76+
- `name` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) The name of the rate limit
77+
- `source` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) Unique source identifier (e.g. username, IP, etc.)
78+
- `attempts` [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) The number of attempts to make. Default: `1`
79+
- Returns: [`AttemptResult`](#interface-attemptresult)
80+
- Throws: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) If the rate limit does not exist
81+
82+
<a name="static-method-ratelimitcheckname-source"></a>
83+
### Static method: `RateLimit.check(name, source)`
84+
Check the attempt state for a source ID without decrementing the remaining attempts
85+
86+
- `name` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) The name of the rate limit
87+
- `source` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) Unique source identifier (e.g. username, IP, etc.)
88+
- Returns: [`AttemptResult`](#interface-attemptresult)
89+
- Throws: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) If the rate limit does not exist
90+
91+
<a name="static-method-ratelimitclearname"></a>
92+
### Static method: `RateLimit.clear(name)`
93+
Clear rate limit attempts storage. This is equivalent to resetting all rate limits.
94+
95+
- `name` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) The name of the rate limit
96+
- Returns: [`void`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Undefined_type)
97+
- Throws: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) If the rate limit does not exist
98+
99+
<a name="static-method-ratelimitcreatename-limit-timewindow"></a>
100+
### Static method: `RateLimit.create(name, limit, timeWindow)`
101+
Create a new rate limit
102+
103+
- `name` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) The name of the rate limit
104+
- `limit` [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) The number of attempts allowed per time window (e.g. 60)
105+
- `timeWindow` [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) The time window in seconds (e.g. 60)
106+
- Returns: [`RateLimit`](#class-ratelimit)
107+
108+
<a name="static-method-ratelimitdeletename"></a>
109+
### Static method: `RateLimit.delete(name)`
110+
Delete the rate limit instance. After it is deleted, it should not be used any further without constructing a new instance.
111+
112+
- `name` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) The name of the rate limit
113+
- Returns: [`void`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Undefined_type)
114+
- Throws: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) If the rate limit does not exist
115+
116+
<a name="static-method-ratelimitgetname"></a>
117+
### Static method: `RateLimit.get(name)`
118+
Get a rate limit instance
119+
120+
- `name` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) The name of the rate limit
121+
- Returns: [`RateLimit`](#class-ratelimit) or [`null`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Null_type)
122+
123+
<a name="static-method-ratelimitresetsource"></a>
124+
### Static method: `RateLimit.reset(name, source)`
125+
Reset limit for a source ID. The storage entry will be deleted and a new one will be created on the next attempt.
126+
127+
- `name` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) The name of the rate limit
128+
- `source` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) Unique source identifier (e.g. username, IP, etc.)
129+
- Returns: [`void`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Undefined_type)
130+
- Throws: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) If the rate limit does not exist
131+
132+
<a name="static-method-ratelimitsetremainingname-source-remaining"></a>
133+
### Static method: `RateLimit.setRemaining(name, source, remaining)`
134+
Set the remaining attempts for a source ID.
135+
136+
> **Warning**: This is not recommended as the remaining attempts depend on the limit of the instance.
137+
138+
- `name` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) The name of the rate limit
139+
- `source` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) Unique source identifier (e.g. username, IP, etc.)
140+
- `remaining` [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) The number of remaining attempts
141+
- Returns: [`void`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Undefined_type)
142+
- Throws: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) If the rate limit does not exist
143+
144+
<a name="new-ratelimitname-limit-timewindow"></a>
145+
### `new RateLimit(name, limit, timeWindow)`
146+
Create a new rate limit
147+
148+
- `name` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) The name of the rate limit
149+
- `limit` [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) The number of attempts allowed per time window (e.g. 60)
150+
- `timeWindow` [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) The time window in seconds (e.g. 60)
151+
- Throws: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) If the rate limit already exists
152+
153+
<a name="ratelimitattemptsource-attempts"></a>
154+
### `rateLimit.attempt(source, [attempts])`
155+
Make an attempt with a source ID
156+
157+
- `source` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) Unique source identifier (e.g. username, IP, etc.)
158+
- `attempts` [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) The number of attempts to make. Default: `1`
159+
- Returns: [`AttemptResult`](#interface-attemptresult)
160+
161+
<a name="ratelimitchecksource"></a>
162+
### `rateLimit.check(source)`
163+
Check the attempt state for a source ID without decrementing the remaining attempts
164+
165+
- `source` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) Unique source identifier (e.g. username, IP, etc.)
166+
- Returns: [`AttemptResult`](#interface-attemptresult)
167+
168+
<a name="ratelimitclear"></a>
169+
### `rateLimit.clear()`
170+
Clear rate limit attempts storage. This is equivalent to resetting all rate limits.
171+
172+
- Returns: [`void`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Undefined_type)
173+
174+
<a name="ratelimitdelete"></a>
175+
### `rateLimit.delete()`
176+
Delete the rate limit instance. After it is deleted, it should not be used any further without constructing a new instance.
177+
178+
- Returns: [`void`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Undefined_type)
179+
180+
<a name="ratelimitlimit"></a>
181+
### `rateLimit.limit`
182+
The number of requests allowed per time window
183+
184+
- Type: [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type)
185+
186+
<a name="ratelimitname"></a>
187+
### `rateLimit.name`
188+
Get rate limit name
189+
190+
- Type: [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type)
191+
- Readonly
192+
193+
<a name="ratelimitresetsource"></a>
194+
### `rateLimit.reset(source)`
195+
Reset limit for a source ID. The storage entry will be deleted and a new one will be created on the next attempt.
196+
197+
- `source` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) Unique source identifier (e.g. username, IP, etc.)
198+
- Returns: [`void`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Undefined_type)
199+
200+
<a name="ratelimitsetremainingsource-remaining"></a>
201+
### `rateLimit.setRemaining(source, remaining)`
202+
Set the remaining attempts for a source ID.
203+
204+
> **Warning**: This is not recommended as the remaining attempts depend on the limit of the instance.
205+
206+
- `source` [`string`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) Unique source identifier (e.g. username, IP, etc.)
207+
- `remaining` [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) The number of remaining attempts
208+
- Returns: [`void`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Undefined_type)
209+
210+
<a name="ratelimittimewindow"></a>
211+
### `rateLimit.timeWindow`
212+
The time window in seconds (e.g. 60)
213+
214+
- Type: [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type)
215+
216+
<a name="interface-attemptresult"></a>
217+
## Interface: `AttemptResult`
218+
The result from a rate limit attempt
219+
220+
<a name="attemptresultlimit"></a>
221+
### `attemptResult.limit`
222+
The number of requests this rate limit allows per time window
223+
224+
- Type: [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type)
225+
- Readonly
226+
227+
<a name="attemptresultremaining"></a>
228+
### `attemptResult.remaining`
229+
The number of requests remaining in the current time window
230+
231+
- Type: [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type)
232+
- Readonly
233+
234+
<a name="attemptresultreset"></a>
235+
### `attemptResult.reset`
236+
The number of seconds until the current time window resets
237+
238+
- Type: [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type)
239+
- Readonly
240+
241+
<a name="attemptresultratelimit"></a>
242+
### `attemptResult.rateLimit`
243+
The rate limit that this attempt was made on
244+
245+
- Type: [`RateLimit`](#class-ratelimit)
246+
- Readonly
247+
248+
<a name="attemptresultallow"></a>
249+
### `attemptResult.allow`
250+
Whether this attempt should be allowed to proceed. If false, the attempt is rate limited.
251+
252+
- Type: [`boolean`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type)
253+
- Readonly

0 commit comments

Comments
 (0)