Elysia Plugin

hitlimit provides a first-class plugin for Elysia, the ergonomic web framework for Bun. The plugin integrates seamlessly with Elysia's plugin system and provides type-safe rate limiting.

Installation

Install hitlimit-bun alongside Elysia:

bun add elysia hitlimit-bun

Basic Usage

Add rate limiting to your Elysia application:

app.ts
import { Elysia } from 'elysia'
import { hitlimitPlugin } from '@joint-ops/hitlimit-bun/elysia'

const app = new Elysia()
  .use(hitlimitPlugin({
    limit: 100,
    window: '1m'
  }))
  .get('/', () => 'Hello World!')
  .get('/api/data', () => ({ data: 'protected' }))
  .listen(3000)

console.log('Server running on port 3000')

Route-Specific Limits

Apply different limits to specific routes using guards:

routes.ts
import { Elysia } from 'elysia'
import { hitlimitPlugin } from '@joint-ops/hitlimit-bun/elysia'

const app = new Elysia()
  // Global rate limit
  .use(hitlimitPlugin({ limit: 100, window: '1m' }))

  // Public routes
  .get('/', () => 'Welcome')

  // Stricter limit for auth routes
  .group('/auth', (app) =>
    app
      .use(hitlimitPlugin({ limit: 5, window: '15m', name: 'auth' }))
      .post('/login', ({ body }) => 'Login')
      .post('/register', ({ body }) => 'Register')
  )

  // Higher limit for API routes
  .group('/api', (app) =>
    app
      .use(hitlimitPlugin({ limit: 1000, window: '1m', name: 'api' }))
      .get('/users', () => [])
      .get('/posts', () => [])
  )
  .listen(3000)

Custom Key Extraction

Rate limit by user ID, API key, or other identifiers:

custom-key.ts
const app = new Elysia()
  .use(hitlimitPlugin({
    limit: 100,
    window: '1m',
    key({ request, headers }) {
      // Rate limit by API key
      return headers['x-api-key'] || getClientIP(request)
    }
  }))
  .get('/api', () => 'Protected')

Custom Error Response

Customize the rate limit exceeded response:

custom-response.ts
const app = new Elysia()
  .use(hitlimitPlugin({
    limit: 100,
    window: '1m',
    onRateLimited({ set, reset }) {
      set.status = 429
      set.headers['Retry-After'] = String(reset)

      return {
        error: 'Too many requests',
        message: 'Please slow down',
        retryAfter: reset
      }
    }
  }))
  .get('/', () => 'Hello')

Using Stores

Use SQLite or Redis stores for persistence:

stores.ts
import { Elysia } from 'elysia'
import { hitlimitPlugin, bunSqliteStore } from '@joint-ops/hitlimit-bun/elysia'

const app = new Elysia()
  .use(hitlimitPlugin({
    limit: 100,
    window: '1m',
    store: bunSqliteStore({
      path: './rate-limits.db'
    })
  }))
  .get('/', () => 'Hello World')
  .listen(3000)

Plugin Options

Option Type Description
limit number Maximum requests per window
window string Time window (e.g., '1m', '1h')
key function Custom key extraction function
store Store Storage backend (memory, sqlite, redis)
name string Unique name for scoped limiters
onRateLimited function Custom handler when rate limited

Next Steps