// This module's own rate-limit policy, built on core's plumbing. // // `ctx.middleware.rateLimit` is core's `makeLimiter` (MODULE_API.md §2.3, API // 1.1.0): the module states the window, the cap and the message, and core // supplies the `express-rate-limit` instance, its store and the logging that // records a breach. That division is the point. The policy is the module's — // only the module knows what its endpoints cost — but there is one limiter // library in the process and one place a breach is written down. A module that // resolved `express-rate-limit` for itself would get a second store, and a limit // enforced by two independent counters is not the limit either of them states. // // Built lazily, for the reason `core.js` explains: `core.middleware` resolves // `ctx`, so touching it at require time would run before `register()`. The // routers ask for these while they are being built, which is inside // `register()`, and the result is memoised so a limiter is created once and the // counter is not reset by a second call. const core = require('../core') let limiters = null function build() { if (limiters) return limiters limiters = { // The player-vendor market search. The first genuinely expensive PUBLIC // endpoint on the site: every call is a LIKE scan plus a COUNT over the // listings table, which on a large shard is the biggest table there is, and // it is anonymous by default. Generous for a human browsing shops (a typed // search is debounced to one request, and paging is a click), tight enough // that it cannot be used as a cheap way to load the database. // // This lived in core's `middleware/rateLimit.js` and is UO policy, so it // came here with the route it guards. marketLimiter: core.middleware.rateLimit({ windowMs: 60 * 1000, max: 60, label: 'market', message: 'Too many searches. Please slow down.', }), } return limiters } module.exports = { get marketLimiter() { return build().marketLimiter }, }