npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

elysia-rate-limit

v4.1.0

Published

Rate-limiter for Elysia.js

Downloads

5,899

Readme

Elysia Rate Limit

Lightweight rate limiter plugin for Elysia.js

NPM Version NPM Downloads NPM License

Install

bun add elysia-rate-limit

If you're using Bun v1.0.3 or lower, elysia-rate-limit v2.0.0 or higher will not be compatible. Please use elysia-rate-limit v1.3.0 instead.

Compatibility

As long as you're on the latest version of Bun, and Elysia. Using the latest version of elysia-rate-limit would works just fine. However, please refer to the following table to determine which version to use.

| Plugin version | Requirements | |----------------|------------------------------| | 3.0.0+ | Bun > 1.0.3, Elysia >= 1.0.0 | | 2.0.0 - 2.2.0 | Bun > 1.0.3, Elysia < 1.0.0 | | 1.0.2 - 1.3.0 | Bun <= 1.0.3, Elysia < 1.0.0 |

Usage

Check out full sample at example

import { Elysia } from 'elysia'
import { rateLimit } from 'elysia-rate-limit'

new Elysia().use(rateLimit()).listen(3000)

Configuration

duration

number

Default: 60000

Duration for requests to be remembered in milliseconds. Also used in the Retry-After header when the limit is reached.

max

number

Default: 10

Maximum of request to be allowed during 1 duration timeframe.

errorResponse

string | Response | Error

Default: rate-limit reached

Response to be sent when the rate limit is reached.

If you define a value as a string, then it will be sent as a plain text response with status code 429. If you define a value as a Response object, then it will be sent as is. And if you define a value as an Error object, then it will be thrown as an error.

new Elysia()
  .use(
    rateLimit({
      errorResponse: new Response("rate-limited", {
        status: 429,
        headers: new Headers({
          'Content-Type': 'text/plain',
          'Custom-Header': 'custom',
        }),
      }),
    })
  )
import { HttpStatusEnum } from 'elysia-http-status-code/status'

export class RateLimitError extends Error {
  constructor(
    public message: string = 'rate-limited',
    public detail: string = '',
    public status: number = HttpStatusEnum.HTTP_429_TOO_MANY_REQUESTS // or just 429
  ) {
    super(message)
  }
}

new Elysia()
  .use(
    rateLimit({
      errorResponse: new RateLimitError(),
    })
  )
  // use with error hanlder
  .error({
    rateLimited: RateLimitError,
  })
  .onError({ as: 'global' }, ({ code }) => {
    switch (code) {
      case 'rateLimited':
        return code
        break
    }
  })

scoping

'global' | 'scoped'

Default: 'global'

Sometimes you may want to only apply rate limit plugin to curtain Elysia instance. This option will allow you to choose scope local apply to only current instance and descendant only. But by default, rate limit plugin will apply to all instances that apply the plugin.

Read more : Scope - ElysiaJS | ElysiaJS

generator

<T extends object>(equest: Request, server: Server | null, derived: T) => MaybePromise<string>

Custom key generator to categorize client requests, return as a string. By default, this plugin will categorize client by their IP address via server.requestIP() function.

If you deploy your server behind a proxy (i.e. NGINX, Cloudflare), you may need to implement your own generator to get client's real IP address.

const cloudflareGenerator = (req, server) =>
  // get client ip via cloudflare header first
  req.headers.get('CF-Connecting-IP') ??
  // if not found, fallback to default generator
  server?.requestIP(req)?.address ??
  ''

There's a third argument where you can use derive values from external plugin within key generator as well. Only downsize is you have to definitely those types be yourself, please be sure to test those values before actually defining types manually.

import { ip } from 'elysia-ip'

import type { SocketAddress } from 'bun'
import type { Generator } from 'elysia-rate-limit'

const ipGenerator: Generator<{ ip: SocketAddress }> = (_req, _serv, { ip }) => {
  return ip
}

countFailedRequest

boolean

Default: false

Should this plugin count rate-limit to user when request failed? By default, this plugin will refund request count to a client when onError lifecycle called. (Learn more in Lifecycle)

context

Context

Context for storing requests count for each client, if you want to implement your own Context you can write it to comply with Context protocol

import type { Context } from 'elysia-rate-limit'

export class CustomContext implements Context {
  // implementation here
}

By default, context implementation, caching will be an LRU cache with a maximum of 5,000 entries. If you prefer to use this cache implementation but with larger cache size, you can define a new context with preferred cache size as follows

import { DefaultContext } from 'elysia-rate-limit'

new Elysia().use(
  rateLimit({
    // define max cache size to 10,000
    context: new DefaultContext(10_000),
  })
)

headers

boolean

Default true

Should this plugin automatically set RateLimit-* headers to the response? If you want to disable this feature, you can set this option to false.

skip

(request: Request, key: string): boolean | Promise<boolean>

Default: (): false

A custom function to determine that should this request be counted into rate-limit or not based on information given by Request object (i.e., Skip counting rate-limit on some route) and the key of the given request, by default, this will always return false which means counted everything.

injectServer

() => Server

Default: undefined

A function to inject server instance to the plugin, this is useful when you want to use default key generator in detached Elysia instances. You can check out the example here.

Please use this function as a last resort, as defining this option will make plugin to make an extra function call, which may affect performance.