rate_limiter.ts

In-memory sliding window rate limiter.

Tracks failed attempts per key (typically IP address) using a sliding time window. No external dependencies — state resets on server restart.

Declarations
#

10 declarations

view source

create_rate_limiter
#

rate_limiter.ts view source

(options?: Partial<RateLimiterOptions> | undefined): RateLimiter

Create a RateLimiter with sensible defaults for per-IP login protection.

options?

override individual options; unset fields use DEFAULT_LOGIN_IP_RATE_LIMIT

type Partial<RateLimiterOptions> | undefined
optional

returns

RateLimiter

DEFAULT_ACTION_ACCOUNT_RATE_LIMIT
#

rate_limiter.ts view source

RateLimiterOptions

Default options for per-actor action-dispatcher rate limiting: 1200 attempts per 15 minutes. Shared by the HTTP RPC and WebSocket action dispatchers. Permissive — sustained ~80/min is well above any human admin workflow; an oracle probing 10k addresses still finishes in ~2 hours, slow enough to surface in audit. Tighten downstream.

DEFAULT_ACTION_IP_RATE_LIMIT
#

rate_limiter.ts view source

RateLimiterOptions

Default options for per-IP action-dispatcher rate limiting: 600 attempts per 15 minutes. Shared by the HTTP RPC and WebSocket action dispatchers (one budget per action, not per transport). Permissive — catches runaway scripts and egregious oracle probes, but well above human or normal automation pace. Tighten downstream for stricter deployments.

DEFAULT_LOGIN_ACCOUNT_RATE_LIMIT
#

DEFAULT_LOGIN_IP_RATE_LIMIT
#

DEFAULT_RATE_LIMITER_MAX_KEYS
#

rate_limiter.ts view source

100000

Default tracked-key cap: bounds worst-case memory under key-enumeration attacks (an attacker rotating source IPs cannot grow the backing map indefinitely between cleanup ticks). Tuned to comfortably fit real traffic for a single-instance deployment while capping memory at a few MB in the worst case.

rate_limit_exceeded_response
#

rate_limiter.ts view source

(c: Context<any, any, {}>, retry_after: number): Response

Build a 429 rate-limit-exceeded JSON response with Retry-After header.

c

Hono context

type Context<any, any, {}>

retry_after

seconds until the client should retry

type number

returns

Response

a 429 Response

RateLimiter
#

rate_limiter.ts view source

In-memory sliding window rate limiter.

Stores an array of timestamps per key. On check/record, timestamps outside the window are pruned. retry_after reports seconds until the oldest active timestamp expires.

The backing store is an LruMap when options.max_keys is a positive number (default DEFAULT_RATE_LIMITER_MAX_KEYS) and a plain Map when max_keys is null. The LruMap path bounds memory under key-enumeration attack at the cost of a slight per-op overhead and the LRU trade-off described on RateLimiterOptions.max_keys.

Parameters that accept RateLimiter | null (e.g. ip_rate_limiter, login_account_rate_limiter) silently disable rate limiting when null is passed — no checks are performed and all requests are allowed through.

options

type RateLimiterOptions

readonly

constructor

type new (options: RateLimiterOptions): RateLimiter

options

check

Check whether key is allowed without recording an attempt.

Prunes timestamps that fell outside the window as a side effect (and removes the key entirely when none remain), so the backing map stays bounded even under read-only traffic.

type (key: string, now?: number): RateLimitResult

key

rate limit key (e.g. IP address)

type string
now

current timestamp in ms (defaults to Date.now())

type number
default Date.now()

record

Record a failed attempt for key and return the updated result.

type (key: string, now?: number): RateLimitResult

key

rate limit key (e.g. IP address)

type string
now

current timestamp in ms (defaults to Date.now())

type number
default Date.now()

reset

Clear all attempts for key (e.g. after successful login).

type (key: string): void

key
type string
returns void

cleanup

Remove entries whose timestamps are all outside the window.

type (now?: number): void

now

current timestamp in ms (defaults to Date.now())

type number
default Date.now()
returns void

dispose

Stop the cleanup timer. Safe to call multiple times.

type (): void

returns void

RateLimiterOptions
#

rate_limiter.ts view source

RateLimiterOptions

Configuration for a rate limiter instance.

max_attempts

Maximum allowed attempts within the window.

type number

window_ms

Sliding window duration in milliseconds.

type number

cleanup_interval_ms

Interval for pruning stale entries (0 disables the timer).

type number

max_keys

Maximum tracked keys. When exceeded, the least-recently-used key is evicted — bounds memory under key-enumeration attacks. Default: DEFAULT_RATE_LIMITER_MAX_KEYS (100_000). Pass null to disable the cap (falls back to an unbounded Map — only recommended when the key set is known to be closed, e.g. a per-account limiter keyed to a bounded-size account table).

LRU trade-off: every check / record call marks the key as most-recently-used, so keys under active attack stay fresh and won't be evicted. A slow-burn attacker spread across many low-volume keys can, however, drop out of the table and reset their budget — set max_keys high enough to fit the expected legitimate key set and this stays theoretical.

type number | null

RateLimitResult
#

rate_limiter.ts view source

RateLimitResult

Result of a rate limit check or record operation.

allowed

Whether the request is allowed.

type boolean

remaining

Remaining attempts before blocking.

type number

retry_after

Seconds until the oldest active attempt expires (0 if allowed).

type number

Depends on
#

Imported by
#