/**
 * Rate limit hooks for @beignet/core/server
 */
import type { RateLimitScope } from "../../contracts/index.js";
import type { ActivityActor, RateLimitPort } from "../../ports/index.js";
import { type TrustedProxyClientIpSource, type TrustedProxyConfig } from "../trusted-proxy.js";
import type { HttpRequestLike, ServerHook } from "../types.js";
/**
 * Ports required by rate-limit hooks.
 */
export type RateLimitPorts = {
    rateLimit: RateLimitPort;
};
/**
 * Minimal context shape required for user-scoped rate limits.
 */
export type CtxWithRateLimit = {
    ports: RateLimitPorts;
    actor?: ActivityActor;
};
type EarlyRateLimitScope = Exclude<RateLimitScope, "user">;
/**
 * Strategy for resolving the client IP used by `ip`-scoped limits.
 *
 * - `"none"`: do not trust request headers for IP resolution. Every request
 *   shares one `ip:unknown` bucket; this is the explicit opt-out for apps
 *   that declare `ip` scopes without a trusted client-IP source.
 * - `"x-forwarded-for-last"`: the last `x-forwarded-for` entry. Use this only
 *   when the app is always behind a trusted reverse proxy that appends the
 *   socket address.
 * - `"x-forwarded-for-first"`: the first `x-forwarded-for` entry. This value
 *   is client-controlled, so only use it when a trusted edge normalizes the
 *   header before it reaches the app.
 * - `"x-real-ip"` and `"cf-connecting-ip"`: dedicated platform headers.
 * - A function receives the raw request and returns the client IP, for
 *   platform-specific resolution.
 */
export type RateLimitIpSource = "none" | TrustedProxyClientIpSource;
/**
 * Options for `createRateLimitHooks(...)`.
 */
export interface RateLimitOptions<Ctx> {
    /**
     * Build a rate-limit key after context exists.
     *
     * This is used for user-scoped limits and any late key strategy.
     */
    key?: (args: {
        ctx: Ctx;
        req: HttpRequestLike;
        scope: RateLimitScope;
    }) => string;
    /**
     * Build a rate-limit key before request parsing and context creation.
     *
     * This is used for global and IP-scoped limits.
     */
    earlyKey?: (args: {
        req: HttpRequestLike;
        scope: EarlyRateLimitScope;
    }) => string;
    /**
     * Resolve the client IP for `ip`-scoped limits.
     *
     * There is no default: when any contract declares an `ip`-scoped rate limit
     * and neither the server-level `trustedProxy.clientIp`,
     * this hook's `trustedProxy.clientIp`, `ipSource`, nor a custom `earlyKey`
     * is configured, the hook fails at startup. Prefer the server-level policy
     * for production proxy headers; keep these hook-local options for an
     * intentional override or custom keying.
     */
    ipSource?: RateLimitIpSource;
    /**
     * Hook-local trusted-proxy policy used to resolve client IPs when
     * `ipSource` is not set. This overrides the server-level policy.
     *
     * Configure this only when the app is always behind a platform or reverse
     * proxy that strips or normalizes forwarding headers. For `ip`-scoped rate
     * limits, set `trustedProxy.clientIp` to the header source written by that
     * trusted edge.
     */
    trustedProxy?: TrustedProxyConfig;
}
/**
 * Create metadata-driven rate-limit hooks.
 *
 * The hook reads `contract.metadata.rateLimit`. Global and IP-scoped limits run
 * in `onRequest` before context creation; user-scoped limits run in
 * `beforeHandle` after route hooks have resolved identity and `ctx.actor` is
 * available. Exceeded limits throw the framework `TooManyRequests` app error
 * with `scope`, `retryAfterSeconds`, and `resetAt` details, and the 429
 * response carries a `Retry-After` header when the limiter reports a reset
 * time. The bucket key is
 * never sent to clients; denials emit a `rateLimit.denied` instrumentation
 * event that carries the key for operators.
 *
 * `ip`-scoped limits require an explicit `trustedProxy.clientIp`, `ipSource`,
 * or custom `earlyKey`: the hook's `validate` phase fails `createServer(...)`
 * startup when a registered contract declares an `ip` scope without one,
 * instead of silently collapsing all clients into a shared `ip:unknown` bucket.
 * Contracts added later through `server.route(...)` are not visible to
 * `validate`, so enforcing an `ip`-scoped limit without a client-IP source
 * throws the same configuration error at request time as a backstop. Pass
 * `ipSource: "none"` to explicitly opt in to the shared `ip:unknown` bucket.
 *
 * @param options - Optional key builders and client-IP source.
 * @returns A server hook backed by `ctx.ports.rateLimit`.
 */
export declare function createRateLimitHooks<Ctx extends CtxWithRateLimit>(options?: RateLimitOptions<Ctx>): ServerHook<Ctx, RateLimitPorts>;
export {};
//# sourceMappingURL=rate-limit.d.ts.map