Skip to content

Commit ed7c91f

Browse files
committed
docs: add docblocks
1 parent 7d35687 commit ed7c91f

File tree

11 files changed

+587
-133
lines changed

11 files changed

+587
-133
lines changed

src/define_config.ts

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,23 @@ import type {
2626
} from './types.ts'
2727

2828
/**
29-
* Helper to define limiter config. This function exports a
30-
* config provider and hence you cannot access raw config
31-
* directly.
29+
* Defines the limiter configuration for your AdonisJS application.
30+
* This function returns a config provider that resolves store configurations lazily.
3231
*
33-
* Therefore use the "limiterManager.config" property to access
34-
* raw config.
32+
* To access the resolved config at runtime, use the `limiterManager.config` property.
33+
*
34+
* @param config - Configuration object with default store and stores collection
35+
*
36+
* @example
37+
* ```ts
38+
* export default defineConfig({
39+
* default: 'redis',
40+
* stores: {
41+
* redis: stores.redis({}),
42+
* memory: stores.memory({})
43+
* }
44+
* })
45+
* ```
3546
*/
3647
export function defineConfig<
3748
KnownStores extends Record<
@@ -107,12 +118,34 @@ export function defineConfig<
107118
}
108119

109120
/**
110-
* Config helpers to instantiate limiter stores inside
111-
* an AdonisJS application
121+
* Store configuration helpers to instantiate limiter stores in your AdonisJS application.
122+
* Each helper returns a factory function that creates store instances with consumption options.
123+
*
124+
* @example
125+
* ```ts
126+
* export default defineConfig({
127+
* default: 'redis',
128+
* stores: {
129+
* redis: stores.redis({ connectionName: 'main' }),
130+
* database: stores.database({ tableName: 'rate_limits' }),
131+
* memory: stores.memory({})
132+
* }
133+
* })
134+
* ```
112135
*/
113136
export const stores: {
114137
/**
115-
* Configure redis limiter store
138+
* Configures a Redis-backed limiter store.
139+
*
140+
* @param config - Redis store configuration
141+
*
142+
* @example
143+
* ```ts
144+
* stores.redis({
145+
* connectionName: 'main',
146+
* keyPrefix: 'limiter'
147+
* })
148+
* ```
116149
*/
117150
redis: (
118151
config: Omit<LimiterRedisStoreConfig, keyof LimiterConsumptionOptions> & {
@@ -121,7 +154,17 @@ export const stores: {
121154
) => ConfigProvider<LimiterManagerStoreFactory>
122155

123156
/**
124-
* Configure database limiter store
157+
* Configures a database-backed limiter store. Supports PostgreSQL, MySQL, and SQLite.
158+
*
159+
* @param config - Database store configuration
160+
*
161+
* @example
162+
* ```ts
163+
* stores.database({
164+
* tableName: 'rate_limits',
165+
* connectionName: 'postgres'
166+
* })
167+
* ```
125168
*/
126169
database: (
127170
config: Omit<LimiterDatabaseStoreConfig, keyof LimiterConsumptionOptions> & {
@@ -130,7 +173,16 @@ export const stores: {
130173
) => ConfigProvider<LimiterManagerStoreFactory>
131174

132175
/**
133-
* Configure memory limiter store
176+
* Configures an in-memory limiter store. Useful for testing or single-instance applications.
177+
*
178+
* @param config - Memory store configuration
179+
*
180+
* @example
181+
* ```ts
182+
* stores.memory({
183+
* keyPrefix: 'limiter'
184+
* })
185+
* ```
134186
*/
135187
memory: (
136188
config: Omit<LimiterMemoryStoreConfig, keyof LimiterConsumptionOptions>

src/errors.ts

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ import type { LimiterResponse } from './response.ts'
1515

1616
/**
1717
* Throttle exception is raised when the user has exceeded
18-
* the number of requests allowed during a given duration
18+
* the number of requests allowed during a given duration.
19+
*
20+
* The exception automatically sets appropriate HTTP headers and
21+
* formats the response based on the request's Accept header.
1922
*/
2023
export class ThrottleException extends Exception {
2124
message = 'Too many requests'
@@ -53,7 +56,8 @@ export class ThrottleException extends Exception {
5356
}
5457

5558
/**
56-
* Returns the default headers for the response
59+
* Returns the default rate limit headers that will be sent in the HTTP response.
60+
* Includes limit information, remaining requests, retry-after time, and reset time.
5761
*/
5862
getDefaultHeaders(): { [K: string]: any } {
5963
return {
@@ -66,8 +70,9 @@ export class ThrottleException extends Exception {
6670

6771
/**
6872
* Returns the message to be sent in the HTTP response.
69-
* Feel free to override this method and return a custom
70-
* response.
73+
* Supports i18n translations when the i18n package is available.
74+
*
75+
* @param ctx - The HTTP context
7176
*/
7277
getResponseMessage(ctx: HttpContext) {
7378
/**
@@ -87,40 +92,80 @@ export class ThrottleException extends Exception {
8792
}
8893

8994
/**
90-
* Update the default error message
95+
* Updates the default error message.
96+
*
97+
* @param message - The new error message
98+
*
99+
* @example
100+
* ```ts
101+
* throw new ThrottleException(response)
102+
* .setMessage('Rate limit exceeded. Please try again later.')
103+
* ```
91104
*/
92105
setMessage(message: string): this {
93106
this.message = message
94107
return this
95108
}
96109

97110
/**
98-
* Update the default error status code
111+
* Updates the default error status code.
112+
*
113+
* @param status - The HTTP status code
114+
*
115+
* @example
116+
* ```ts
117+
* throw new ThrottleException(response)
118+
* .setStatus(503)
119+
* ```
99120
*/
100121
setStatus(status: number): this {
101122
this.status = status
102123
return this
103124
}
104125

105126
/**
106-
* Define custom response headers. Existing headers will
107-
* be removed
127+
* Defines custom response headers. This will replace the default headers.
128+
*
129+
* @param headers - Custom headers to set
130+
*
131+
* @example
132+
* ```ts
133+
* throw new ThrottleException(response)
134+
* .setHeaders({
135+
* 'X-Custom-Header': 'value',
136+
* 'Retry-After': 60
137+
* })
138+
* ```
108139
*/
109140
setHeaders(headers: { [name: string]: any }): this {
110141
this.headers = headers
111142
return this
112143
}
113144

114145
/**
115-
* Define the translation identifier for the throttle response
146+
* Defines the i18n translation identifier for the throttle response message.
147+
*
148+
* @param identifier - The translation key
149+
* @param data - Optional translation data
150+
*
151+
* @example
152+
* ```ts
153+
* throw new ThrottleException(response)
154+
* .t('errors.rate_limit_exceeded', { minutes: 5 })
155+
* ```
116156
*/
117157
t(identifier: string, data?: Record<string, any>) {
118158
this.translation = { identifier, data }
119159
return this
120160
}
121161

122162
/**
123-
* Converts the throttle exception to an HTTP response
163+
* Converts the throttle exception to an HTTP response.
164+
* Automatically sets appropriate headers and formats the response
165+
* based on the Accept header (HTML, JSON, or JSON:API).
166+
*
167+
* @param error - The throttle exception instance
168+
* @param ctx - The HTTP context
124169
*/
125170
async handle(error: ThrottleException, ctx: HttpContext) {
126171
const status = error.status

src/http_limiter.ts

Lines changed: 80 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ import { E_TOO_MANY_REQUESTS, type ThrottleException } from './errors.ts'
1717
import type { LimiterConsumptionOptions, LimiterManagerStoreFactory } from './types.ts'
1818

1919
/**
20-
* HttpLimiter is a special type of limiter instance created specifically
21-
* for HTTP requests. It exposes a single method to throttle the request
22-
* using the request ip address or the pre-defined unique key.
20+
* HTTP rate limiter with a fluent API for configuring rate limiting on HTTP requests.
21+
* Automatically uses the request IP address as the key unless a custom key is specified.
2322
*/
2423
export class HttpLimiter<KnownStores extends Record<string, LimiterManagerStoreFactory>> {
2524
/**
@@ -56,62 +55,116 @@ export class HttpLimiter<KnownStores extends Record<string, LimiterManagerStoreF
5655
}
5756

5857
/**
59-
* Specify the store you want to use during
60-
* the request
58+
* Specifies which store to use for this rate limiter.
59+
*
60+
* @param store - Name of the configured store
61+
*
62+
* @example
63+
* ```ts
64+
* limiter
65+
* .allowRequests(100)
66+
* .every('1 hour')
67+
* .store('redis')
68+
* ```
6169
*/
6270
store(store: keyof KnownStores) {
6371
this.#store = store
6472
return this
6573
}
6674

6775
/**
68-
* Specify the number of requests to allow
76+
* Sets the number of requests to allow during the specified duration.
77+
*
78+
* @param requests - Maximum number of requests
79+
*
80+
* @example
81+
* ```ts
82+
* limiter.allowRequests(100)
83+
* ```
6984
*/
7085
allowRequests(requests: number) {
7186
this.#options.requests = requests
7287
return this
7388
}
7489

7590
/**
76-
* Specify the duration in seconds or a time expression
77-
* for which the requests to allow.
91+
* Sets the duration window for the rate limit.
7892
*
79-
* For example: allowRequests(10).every('1 minute')
93+
* @param duration - Duration in seconds or time expression (e.g., '1 minute', '1 hour')
94+
*
95+
* @example
96+
* ```ts
97+
* limiter.allowRequests(100).every('1 hour')
98+
* limiter.allowRequests(10).every(60) // 60 seconds
99+
* ```
80100
*/
81101
every(duration: number | string) {
82102
this.#options.duration = duration
83103
return this
84104
}
85105

86106
/**
87-
* Specify a custom unique key to identify the user.
88-
* Defaults to: request.ip()
107+
* Sets a custom key to uniquely identify the requester.
108+
* By default, the request IP address is used.
109+
*
110+
* @param key - Custom identifier (e.g., user ID, API key)
111+
*
112+
* @example
113+
* ```ts
114+
* limiter
115+
* .allowRequests(100)
116+
* .every('1 hour')
117+
* .usingKey(ctx.auth.user.id)
118+
* ```
89119
*/
90120
usingKey(key: string | number) {
91121
this.#key = key
92122
return this
93123
}
94124

95125
/**
96-
* Register a callback function to modify the ThrottleException.
126+
* Registers a callback to customize the ThrottleException before it's thrown.
127+
* Useful for setting custom error messages or translations.
128+
*
129+
* @param callback - Function to modify the exception
130+
*
131+
* @example
132+
* ```ts
133+
* limiter
134+
* .allowRequests(100)
135+
* .every('1 hour')
136+
* .limitExceeded((error) => {
137+
* error.setMessage('Too many requests. Please slow down!')
138+
* error.t('errors.rate_limit_exceeded')
139+
* })
140+
* ```
97141
*/
98142
limitExceeded(callback: (error: ThrottleException) => void) {
99143
this.#exceptionModifier = callback
100144
return this
101145
}
102146

103147
/**
104-
* Define the block duration. The key will be blocked for the
105-
* specified duration after all the requests have been
106-
* exhausted
148+
* Sets the block duration to penalize users who exceed the rate limit.
149+
* The key will be blocked for this duration after exhausting all requests.
150+
*
151+
* @param duration - Block duration in seconds or time expression
152+
*
153+
* @example
154+
* ```ts
155+
* limiter
156+
* .allowRequests(100)
157+
* .every('1 hour')
158+
* .blockFor('15 mins')
159+
* ```
107160
*/
108161
blockFor(duration: number | string): this {
109162
this.#options.blockDuration = duration
110163
return this
111164
}
112165

113166
/**
114-
* JSON representation of the HTTP limiter
167+
* Returns a JSON representation of the HTTP limiter configuration.
115168
*/
116169
toJSON() {
117170
return {
@@ -121,9 +174,17 @@ export class HttpLimiter<KnownStores extends Record<string, LimiterManagerStoreF
121174
}
122175

123176
/**
124-
* Throttle request using the pre-defined options. Returns
125-
* LimiterResponse when request is allowed or throws
126-
* an exception.
177+
* Throttles the HTTP request using the configured options.
178+
* Throws a ThrottleException if the rate limit is exceeded.
179+
*
180+
* @param prefix - Key prefix to namespace the limiter
181+
* @param ctx - HTTP context
182+
*
183+
* @example
184+
* ```ts
185+
* const response = await httpLimiter.throttle('api', ctx)
186+
* console.log(`Remaining: ${response.remaining}`)
187+
* ```
127188
*/
128189
async throttle(prefix: string, ctx: HttpContext): Promise<LimiterResponse> {
129190
if (!this.#options.requests || !this.#options.duration) {

0 commit comments

Comments
 (0)