const { RateLimiter, RateLimitStore } = require('edge-utils/rate-limiting');
// Create rate limiter
const rateLimiter = new RateLimiter({
limit: 100,
window: 60000,
algorithm: 'sliding-window',
keyGenerator: 'ip',
store: new RateLimitStore({ type: 'memory' })
});
// Rate limiting middleware
const rateLimitingMiddleware = async (request, context) => {
const result = await rateLimiter.check(request);
if (!result.allowed) {
// Create rate limit exceeded response
const response = new Response('Rate limit exceeded', {
status: 429,
headers: {
'Content-Type': 'application/json',
'X-RateLimit-Limit': result.limit.toString(),
'X-RateLimit-Remaining': result.remaining.toString(),
'X-RateLimit-Reset': result.resetTime.toString(),
'Retry-After': Math.ceil((result.resetTime - Date.now()) / 1000).toString()
}
});
// Add rate limit info to response body
const rateLimitInfo = {
error: 'rate_limit_exceeded',
limit: result.limit,
remaining: result.remaining,
resetTime: result.resetTime,
resetIn: Math.ceil((result.resetTime - Date.now()) / 1000)
};
response.headers.set('Content-Type', 'application/json');
return new Response(JSON.stringify(rateLimitInfo), {
status: 429,
headers: response.headers
});
}
// Add rate limit headers to successful requests
context.rateLimit = result;
return context.next();
};
// Headers middleware (adds rate limit headers to all responses)
const rateLimitHeadersMiddleware = async (request, context) => {
const response = await context.next();
if (context.rateLimit) {
response.headers.set('X-RateLimit-Limit', context.rateLimit.limit.toString());
response.headers.set('X-RateLimit-Remaining', context.rateLimit.remaining.toString());
response.headers.set('X-RateLimit-Reset', context.rateLimit.resetTime.toString());
}
return response;
};
// Apply middleware
const handler = applyMiddleware([
rateLimitingMiddleware,
rateLimitHeadersMiddleware
], baseHandler);