OptionalburstRequests allowed in a burst. Defaults to ceil(ratePerSecond), min 1.
OptionalmaxCap on how many JIDs are tracked at once, so a flood of distinct senders cannot grow the map without bound. When full, the least recently seen entry is dropped — which at worst gives that sender a fresh bucket, never an error. Default 10 000.
OptionalnowInjectable clock in milliseconds, for tests.
OptionalonCalled for each refused request, for logging and metrics.
Sustained requests per second, per bare JID. May be fractional.
Per-requester rate limiting: a token bucket keyed by bare JID, wrapping a handler.
Why a handler wrapper rather than an
authorizehook, which is where the roadmap put it:AuthorizeFncan only say yes or no, and the server turns a no intoforbidden. A throttled client should be told to slow down, not that it is not allowed — so this returns a real 429 withRetry-After, which a client can act on. It costs no more: the server hands the handler an unread body stream, so refusing here still avoids both the origin call and reading the request.Keyed on the bare JID because resources are cheap to mint: limiting
alice@example.org/laptopseparately from/phonewould let one account multiply its own quota at will.Browser-safe: the only ambient dependency is a clock, and that is injectable.