Clone
export async function rateLimit(request, env) {
  // Get client IP
  const ip = request.headers.get('CF-Connecting-IP') || 
             request.headers.get('X-Forwarded-For') || 
             'unknown';
  
  // Skip rate limiting for health checks
  const url = new URL(request.url);
  if (url.pathname === '/health') {
    return null;
  }
  
  // Simple rate limiting using KV
  if (env.CACHE) {
    const key = `ratelimit:${ip}`;
    const now = Date.now();
    const window = 60000; // 1 minute window
    const limit = 60; // 60 requests per minute
    
    const data = await env.CACHE.get(key, 'json');
    
    if (data) {
      // Reset if window has passed
      if (now - data.start > window) {
        await env.CACHE.put(key, JSON.stringify({
          start: now,
          count: 1
        }), { expirationTtl: 60 });
        return null;
      }
      
      // Check if limit exceeded
      if (data.count >= limit) {
        return new Response(JSON.stringify({ 
          error: 'Too many requests',
          retryAfter: Math.ceil((data.start + window - now) / 1000)
        }), {
          status: 429,
          headers: { 
            'Content-Type': 'application/json',
            'Retry-After': String(Math.ceil((data.start + window - now) / 1000))
          }
        });
      }
      
      // Increment counter
      await env.CACHE.put(key, JSON.stringify({
        ...data,
        count: data.count + 1
      }), { expirationTtl: 60 });
    } else {
      // First request
      await env.CACHE.put(key, JSON.stringify({
        start: now,
        count: 1
      }), { expirationTtl: 60 });
    }
  }
  
  return null;
}