/home/techb158/balavpn.abdallabala.com/src
Edit: /home/techb158/balavpn.abdallabala.com/src/middleware.js (1868B)
import { NextResponse } from "next/server";
const WINDOW_MS = 60_000;
const MAX_PER_WINDOW = 100;
const hits = new Map();
function getClientIp(request) {
return request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()
|| request.headers.get("x-real-ip")
|| "127.0.0.1";
}
function checkRateLimitLocal(key, max = MAX_PER_WINDOW, windowMs = WINDOW_MS) {
const now = Date.now();
if (!hits.has(key)) hits.set(key, []);
const timestamps = hits.get(key).filter(t => now - t < windowMs);
timestamps.push(now);
hits.set(key, timestamps);
return {
allowed: timestamps.length <= max,
remaining: Math.max(0, max - timestamps.length),
reset: Math.ceil(now / 1000) + Math.ceil(windowMs / 1000)
};
}
export function middleware(request) {
const { pathname } = request.nextUrl;
if (!pathname.startsWith("/api/")) return NextResponse.next();
const ip = getClientIp(request);
const useRedis = process.env.REDIS_URL && process.env.COSMIC_REDIS_ENABLED !== 'false';
if (!useRedis) {
const result = checkRateLimitLocal(`rl:${ip}`);
if (!result.allowed) {
return new NextResponse(JSON.stringify({ error: "Too many requests. Try again shortly." }), {
status: 429,
headers: {
"Content-Type": "application/json",
"X-RateLimit-Limit": String(MAX_PER_WINDOW),
"X-RateLimit-Remaining": "0",
"X-RateLimit-Reset": String(result.reset),
"Cache-Control": "no-store"
}
});
}
const response = NextResponse.next();
response.headers.set("X-RateLimit-Limit", String(MAX_PER_WINDOW));
response.headers.set("X-RateLimit-Remaining", String(result.remaining));
response.headers.set("X-RateLimit-Reset", String(result.reset));
return response;
}
return NextResponse.next();
}
export const config = {
matcher: "/api/:path*"
};