@@ -173,7 +173,7 @@ router.use(
173173 },
174174 }),
175175)
176- ` ` ` `
176+ ` ` `
177177
178178**TypeScript Usage:**
179179
@@ -590,15 +590,127 @@ class CustomStore implements RateLimitStore {
590590}
591591` ` `
592592
593- ` ` ` `
593+ #### Sliding Window Rate Limiter
594+
595+ For more precise rate limiting, use the sliding window implementation that **prevents burst traffic** at any point in time:
596+
597+ ` ` ` javascript
598+ const {createSlidingWindowRateLimit } = require (' 0http-bun/lib/middleware' )
599+
600+ // Basic sliding window rate limiter
601+ router .use (
602+ createSlidingWindowRateLimit ({
603+ windowMs: 60 * 1000 , // 1 minute sliding window
604+ max: 10 , // Max 10 requests per minute
605+ keyGenerator : (req ) => req .headers .get (' x-forwarded-for' ) || ' default' ,
606+ }),
607+ )
608+ ` ` `
609+
610+ **TypeScript Usage:**
611+
612+ ` ` ` typescript
613+ import {createSlidingWindowRateLimit } from ' 0http-bun/lib/middleware'
614+ import type {RateLimitOptions } from ' 0http-bun/lib/middleware'
615+
616+ const slidingOptions: RateLimitOptions = {
617+ windowMs: 60 * 1000 , // 1 minute
618+ max: 10 , // 10 requests max
619+ keyGenerator : (req ) => req .user ? .id || req .headers .get (' x-forwarded-for' ),
620+ handler: (req , hits , max , resetTime ) => {
621+ return Response .json (
622+ {
623+ error: ' Rate limit exceeded' ,
624+ retryAfter: Math .ceil ((resetTime .getTime () - Date .now ()) / 1000 ),
625+ limit: max,
626+ used: hits,
627+ },
628+ {status: 429 },
629+ )
630+ },
631+ }
632+
633+ router .use (createSlidingWindowRateLimit (slidingOptions))
634+ ` ` `
635+
636+ **How Sliding Window Differs from Fixed Window:**
637+
638+ The sliding window approach provides **more accurate and fair rate limiting** by tracking individual request timestamps:
639+
640+ - **Fixed Window**: Divides time into discrete chunks (e.g., 09:00:00-09:00:59, 09:01:00-09:01:59)
641+ - ⚠️ **Problem**: Allows burst traffic at window boundaries (20 requests in 2 seconds)
642+ - **Sliding Window**: Uses a continuous, moving time window from current moment
643+ - ✅ **Advantage**: Prevents bursts at any point in time (true rate limiting)
644+
645+ **Use Cases for Sliding Window:**
646+
647+ ` ` ` javascript
648+ // Financial API - Zero tolerance for payment bursts
649+ router .use (
650+ ' /api/payments/*' ,
651+ createSlidingWindowRateLimit ({
652+ windowMs: 60 * 1000 , // 1 minute
653+ max: 3 , // Only 3 payment attempts per minute
654+ keyGenerator : (req ) => req .user .accountId ,
655+ }),
656+ )
657+
658+ // User Registration - Prevent automated signups
659+ router .use (
660+ ' /api/register' ,
661+ createSlidingWindowRateLimit ({
662+ windowMs: 3600 * 1000 , // 1 hour
663+ max: 3 , // 3 accounts per IP per hour
664+ keyGenerator : (req ) => req .headers .get (' x-forwarded-for' ),
665+ }),
666+ )
667+
668+ // File Upload - Prevent abuse
669+ router .use (
670+ ' /api/upload' ,
671+ createSlidingWindowRateLimit ({
672+ windowMs: 300 * 1000 , // 5 minutes
673+ max: 10 , // 10 uploads per 5 minutes
674+ keyGenerator : (req ) => req .user .id ,
675+ }),
676+ )
677+ ` ` `
678+
679+ **Performance Considerations:**
680+
681+ - **Memory Usage**: Higher than fixed window (stores timestamp arrays)
682+ - **Time Complexity**: O(n) per request where n = requests in window
683+ - **Best For**: Critical APIs, financial transactions, user-facing features
684+ - **Use Fixed Window For**: High-volume APIs where approximate limiting is acceptable
685+
686+ **Advanced Configuration:**
687+
688+ ` ` ` typescript
689+ // Tiered rate limiting based on user level
690+ const createTieredRateLimit = (req ) => {
691+ const userTier = req .user ? .tier || ' free'
692+ const configs = {
693+ free: {windowMs: 60 * 1000 , max: 10 },
694+ premium: {windowMs: 60 * 1000 , max: 100 },
695+ enterprise: {windowMs: 60 * 1000 , max: 1000 },
696+ }
697+ return createSlidingWindowRateLimit (configs[userTier])
698+ }
699+ ` ` `
594700
595701**Rate Limit Headers:**
596702
703+ Both rate limiters send the following headers when ` standardHeaders: true ` :
704+
597705- ` X - RateLimit- Limit` - Request limit
598706- ` X - RateLimit- Remaining` - Remaining requests
599707- ` X - RateLimit- Reset` - Reset time (Unix timestamp)
600708- ` X - RateLimit- Used` - Used requests
601709
710+ **Error Handling:**
711+
712+ Rate limiting middleware allows errors to bubble up as proper HTTP 500 responses. If your ` keyGenerator` function or custom ` store .increment ()` method throws an error, it will not be caught and masked - the error will propagate up the middleware chain for proper error handling.
713+
602714## Creating Custom Middleware
603715
604716### Basic Middleware
@@ -619,7 +731,7 @@ const customMiddleware = (req: ZeroRequest, next: StepFunction) => {
619731}
620732
621733router .use (customMiddleware)
622- ` ` ` `
734+ ` ` `
623735
624736### Async Middleware
625737
0 commit comments