npm package: @jnode/server-ratelimit
Description: Official rate limit for JNS.
Author: JustApple
Latest version: 1.0.0

# `@jnode/server-ratelimit`

Official rate limit package for JNS.

## Installation

```
npm i @jnode/server-ratelimit
```

## Quick start

### Import

```js
const { createServer, routerConstructors: r, handlerConstructors: h } = require('@jnode/server');
const { routerConstructors: rr } = require('@jnode/server-ratelimit');
```

### Start a rate-limited server

```js
const server = createServer(
  // apply rate limit: 5 requests per 5 seconds
  rr.RateLimit(
    // pass: what to do if the request is within limit
    h.Text('Welcome! You are not rate-limited.'),
    // fail: what to do if the request exceeds limit (default is 429)
    h.Text('Too many requests, please try again later.', { statusCode: 429 }),
    // limiter configuration
    'tb: 5, 5s'
  )
);

server.listen(8080);
```

### Advanced configuration

```js
const server = createServer(
  rr.RateLimit(
    h.Text('API accessed.'),
    429,
    // Configuration: 10 reqs / 1 min, GC every 5 mins, 
    // auto GC when > 2000 users, force GC every 2 hours
    'tb: 10, 1m, 5m, 2000, 2h',
    // identify by IP address specifically
    'address',
    { disableRetryHeader: false }
  )
);

server.listen(8080);
```

## How it works?

`@jnode/server-ratelimit` provides a **router** that acts as a gatekeeper.

When a request arrives:

1. It identifies the client (using the `by` parameter, usually by IP address).
2. It checks the **limiter** (currently using a Token Bucket algorithm) to see if the client has tokens available.
3. If tokens are available, it consumes one and returns the `pass` router/handler.
4. If no tokens remain, it returns the `fail` router/handler and optionally sets the `Retry-After` header.

------

# Reference

## Router: `RateLimit(pass[, fail, limiter, by, options])`

- `pass` [router](#class-serverrouter) | [handler-extended](#handler-extended) The router or handler to use if the rate limit has not been reached.
- `fail` [router](#class-serverrouter) | [handler-extended](#handler-extended) The router or handler to use if the rate limit is exceeded. **Default:** `429`.
- `limiter` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) | [\<Function\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function)
  - If string, format is `type: args`. Currently supported type is `tb` (Token Bucket).
  - If function, signature is `(identity) => true | number`. Returns `true` to pass, or a `number` representing seconds until retry to fail.
  - **Default:** `'tb: 5, 5s'`.
- `by` [\<string\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#string_type) | [\<Function\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) How to identify the client.
  - `'auto'`: Uses `ctx.identity.id` if available, otherwise `ctx.identity.address`.
  - `'address'`: Uses `ctx.identity.address`.
  - Custom Function: `(env, ctx) => identityString`.
  - **Default:** `'auto'`.
- `options` [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
  - `disableRetryHeader` [\<boolean\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#boolean_type) If `true`, the `Retry-After` header will not be added to the response on failure. **Default:** `false`.

### Token Bucket (`tb`) string format

The `limiter` string for `tb` follows this comma-separated argument structure:
`'tb: tokens, resetTime, gcTime, autoGC, forceGCTime, gcChunkSize'`

- `tokens`: Number of requests allowed per period.
- `resetTime`: Time duration before tokens refill (e.g., `'5s'`, `'1m'`, `'1h'`).
- `gcTime`: How often to run garbage collection for inactive identities. **Default:** `'10m'`.
- `autoGC`: Max number of tracked identities before triggering GC. **Default:** `1000`.
- `forceGCTime`: Maximum time to wait before forcing GC regardless of `autoGC`. **Default:** `'1h'`.
- `gcChunkSize`: Number of records to process per GC tick (to prevent blocking the event loop). **Default:** `500`.

*Time units supported: `ms`, `s`, `m`, `h`, `d`. If no unit is provided, it defaults to seconds.*

## `identifyFunctions`

- Type: [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)

A map of built-in identification strategies.

- `auto`: `(env, ctx) => ctx.identity.id ?? ctx.identity.address`
- `address`: `(env, ctx) => ctx.identity.address`

## `limiters`

- Type: [\<Object\>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)

A map of available limiter classes.

- `tb`: `TokenBucketLimiter` class.

## Class: `RateLimitRouter`

The class used to create the rate limit router.

### `new RateLimitRouter(pass[, fail, limiter, by, options])`

Same arguments as [`routerConstructors.RateLimit`](#router-ratelimitpass-fail-limiter-by-options).

### `rateLimitRouter.route(env, ctx)`

Performs the rate limit check and returns either the `pass` or `fail` result.