Stone.js API
    Preparing search index...

    How rate limiting is configured (stone.rateLimit.*).

    The rule this module exists to serve: throttle the subject, never the address alone. Throttling by address assumes one address is one person. On mobile networks using carrier-grade NAT, the norm across much of the world, hundreds of unrelated subscribers share one public address. A per-address quota then punishes legitimate users at random, and hardest exactly where the audience is largest.

    So the budget belongs to the thing actually being protected: the account, the mailbox, the phone number. The address keeps a much looser bucket whose only job is to stop bulk enumeration from one machine.

    interface RateLimitConfig {
        default?: string;
        global?: RateLimitRule;
        headers?: boolean;
        limiters?: LimiterConfig[];
        principal?: RateLimitSubjectResolver;
        trustedAddressHeaders?: string[];
    }

    Hierarchy (View Summary)

    Index
    default?: string

    The limiter used when a rule names none. Defaults to memory.

    global?: RateLimitRule

    A rule applied to every route that declares none.

    Undeclared by default: a limit nobody asked for is a limit nobody sized, and the first thing it breaks is a legitimate burst.

    headers?: boolean

    Headers named after the caller's remaining budget, when the response can carry them.

    Standard by default (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, and Retry-After on a refusal). Set false to say nothing: a public API may prefer not to publish the shape of its budget.

    limiters?: LimiterConfig[]

    The limiters this application configures.

    How to resolve the authenticated principal, for a rule that says by: 'user'.

    Needed because this module runs before authentication, deliberately: refusing a caller past its budget is worth nothing once the token has been verified and the account loaded. So at that point nothing has resolved a principal yet, unless the application resolved one earlier, and where it lives is the application's business, not this module's.

    Point it at whatever already knows:

    principal: (event) => event.getUser()?.userId
    principal: (event) => decodeToken(event.getHeader('authorization'))?.sub

    The default reads event.getUser?.() and takes its id, sub or userId. When nothing resolves, the rule falls back to the address bucket and says so in the log: correct as a behaviour, unacceptable as a silence.

    trustedAddressHeaders?: string[]

    Which request headers may carry the caller's real address, in order of preference.

    Empty by default, and that default matters: a forwarded header is client-spoofable unless a proxy you trust overwrites it, so reading one by default would hand every caller an unlimited supply of identities. Name the header your own edge guarantees.