maxRequests = $maxRequests; $this->windowSeconds = $windowSeconds; } public function __invoke( ServerRequestInterface $request, callable $next ): Response { $apiKey = $request->getHeaderLine('X-API-KEY'); if (!$apiKey) { return ResponseLib::sendFail( 'Missing API key', 401, ['code' => 'MISSING_API_KEY'] ); } // 🔒 rate-limit por API key (em memória) if (!$this->allowRequest($apiKey)) { return ResponseLib::sendFail( 'Rate limit exceeded', 429, [ 'code' => 'RATE_LIMIT_EXCEEDED', 'retry_after' => $this->windowSeconds ] ); } return $next($request); } /** * In-memory rate-limit control * (per process, per API key) */ private function allowRequest(string $key): bool { $now = time(); if (!isset($this->limits[$key]) || $now > $this->limits[$key]['reset']) { $this->limits[$key] = [ 'count' => 0, 'reset' => $now + $this->windowSeconds ]; } $this->limits[$key]['count']++; return $this->limits[$key]['count'] <= $this->maxRequests; } }