packages/chat-next-api/src/rateLimit.ts

import type { NextRequest } from 'next/server';

export type RateLimitResult = { success: boolean; limit?: number; remaining?: number; reset?: number; window?: string; reason?: string; headers?: HeadersInit; status?: number; };

export type RateLimitChecker = (identifier: string) => Promise; export type RateLimitIdentifier = (req: NextRequest) => string | null;

type RateLimitEnforcerOptions = { identify: RateLimitIdentifier; limit: RateLimitChecker; buildHeaders?: (result: RateLimitResult) => HeadersInit; failClosedMessage?: string; };

/**

  • Build a Next.js-friendly rate limit enforcer from a generic limiter + identifier extractor.
  • The limiter stays app-configurable (e.g., Upstash, API Gateway, in-memory) and this helper
  • just normalizes the response shape expected by createNextChatHandler. */ export function createRateLimitEnforcer(options: RateLimitEnforcerOptions) { const failClosedMessage = options.failClosedMessage ?? 'Rate limiter unavailable';

return async function enforce(req: NextRequest): Promise { const identifier = options.identify(req); if (!identifier) { return { success: false, reason: 'Unable to identify client', status: 400, }; }

try {
  const result = await options.limit(identifier);
  const headers = options.buildHeaders ? options.buildHeaders(result) : result.headers;
  return headers ? { ...result, headers } : result;
} catch (error) {
  console.warn('[chat-next-api] rate limit check failed, failing closed', error);
  return {
    success: false,
    reason: failClosedMessage,
    status: 503,
  };
}

}; }