2022-01-09 15:20:59 +00:00
// source/memory-store.ts
var calculateNextResetTime = ( windowMs ) => {
const resetTime = new Date ( ) ;
resetTime . setMilliseconds ( resetTime . getMilliseconds ( ) + windowMs ) ;
return resetTime ;
} ;
var MemoryStore = class {
init ( options ) {
this . windowMs = options . windowMs ;
this . resetTime = calculateNextResetTime ( this . windowMs ) ;
this . hits = { } ;
const interval = setInterval ( async ( ) => {
await this . resetAll ( ) ;
} , this . windowMs ) ;
if ( interval . unref ) {
interval . unref ( ) ;
}
}
async increment ( key ) {
const totalHits = ( this . hits [ key ] ? ? 0 ) + 1 ;
this . hits [ key ] = totalHits ;
return {
totalHits ,
resetTime : this . resetTime
} ;
}
async decrement ( key ) {
const current = this . hits [ key ] ;
if ( current ) {
this . hits [ key ] = current - 1 ;
}
}
async resetKey ( key ) {
delete this . hits [ key ] ;
}
async resetAll ( ) {
this . hits = { } ;
this . resetTime = calculateNextResetTime ( this . windowMs ) ;
}
} ;
// source/lib.ts
var isLegacyStore = ( store ) => typeof store . incr === "function" && typeof store . increment !== "function" ;
var promisifyStore = ( passedStore ) => {
if ( ! isLegacyStore ( passedStore ) ) {
return passedStore ;
}
const legacyStore = passedStore ;
class PromisifiedStore {
async increment ( key ) {
return new Promise ( ( resolve , reject ) => {
legacyStore . incr ( key , ( error , totalHits , resetTime ) => {
if ( error )
reject ( error ) ;
resolve ( { totalHits , resetTime } ) ;
} ) ;
} ) ;
}
async decrement ( key ) {
return Promise . resolve ( legacyStore . decrement ( key ) ) ;
}
async resetKey ( key ) {
return Promise . resolve ( legacyStore . resetKey ( key ) ) ;
}
async resetAll ( ) {
if ( typeof legacyStore . resetAll === "function" )
return Promise . resolve ( legacyStore . resetAll ( ) ) ;
}
}
return new PromisifiedStore ( ) ;
} ;
var parseOptions = ( passedOptions ) => {
const options = {
windowMs : 60 * 1e3 ,
store : new MemoryStore ( ) ,
max : 5 ,
message : "Too many requests, please try again later." ,
statusCode : 429 ,
legacyHeaders : passedOptions . headers ? ? true ,
standardHeaders : passedOptions . draft _polli _ratelimit _headers ? ? false ,
requestPropertyName : "rateLimit" ,
skipFailedRequests : false ,
skipSuccessfulRequests : false ,
requestWasSuccessful : ( _request , response ) => response . statusCode < 400 ,
skip : ( _request , _response ) => false ,
keyGenerator : ( request , _response ) => {
if ( ! request . ip ) {
console . error ( "WARN | `express-rate-limit` | `request.ip` is undefined. You can avoid this by providing a custom `keyGenerator` function, but it may be indicative of a larger issue." ) ;
}
return request . ip ;
} ,
handler : ( _request , response , _next , _optionsUsed ) => {
response . status ( options . statusCode ) . send ( options . message ) ;
} ,
onLimitReached : ( _request , _response , _optionsUsed ) => {
} ,
... passedOptions
} ;
if ( typeof options . store . incr !== "function" && typeof options . store . increment !== "function" || typeof options . store . decrement !== "function" || typeof options . store . resetKey !== "function" || typeof options . store . resetAll !== "undefined" && typeof options . store . resetAll !== "function" || typeof options . store . init !== "undefined" && typeof options . store . init !== "function" ) {
throw new TypeError ( "An invalid store was passed. Please ensure that the store is a class that implements the `Store` interface." ) ;
}
options . store = promisifyStore ( options . store ) ;
return options ;
} ;
var handleAsyncErrors = ( fn ) => async ( request , response , next ) => {
try {
await Promise . resolve ( fn ( request , response , next ) ) . catch ( next ) ;
} catch ( error ) {
next ( error ) ;
}
} ;
var rateLimit = ( passedOptions ) => {
const options = parseOptions ( passedOptions ? ? { } ) ;
if ( typeof options . store . init === "function" )
options . store . init ( options ) ;
const middleware = handleAsyncErrors ( async ( request , response , next ) => {
const skip = await options . skip ( request , response ) ;
if ( skip ) {
next ( ) ;
return ;
}
const augmentedRequest = request ;
const key = await options . keyGenerator ( request , response ) ;
const { totalHits , resetTime } = await options . store . increment ( key ) ;
const retrieveQuota = typeof options . max === "function" ? options . max ( request , response ) : options . max ;
const maxHits = await retrieveQuota ;
augmentedRequest [ options . requestPropertyName ] = {
limit : maxHits ,
current : totalHits ,
remaining : Math . max ( maxHits - totalHits , 0 ) ,
resetTime
} ;
if ( options . legacyHeaders && ! response . headersSent ) {
response . setHeader ( "X-RateLimit-Limit" , maxHits ) ;
response . setHeader ( "X-RateLimit-Remaining" , augmentedRequest [ options . requestPropertyName ] . remaining ) ;
if ( resetTime instanceof Date ) {
response . setHeader ( "Date" , new Date ( ) . toUTCString ( ) ) ;
response . setHeader ( "X-RateLimit-Reset" , Math . ceil ( resetTime . getTime ( ) / 1e3 ) ) ;
}
}
if ( options . standardHeaders && ! response . headersSent ) {
response . setHeader ( "RateLimit-Limit" , maxHits ) ;
response . setHeader ( "RateLimit-Remaining" , augmentedRequest [ options . requestPropertyName ] . remaining ) ;
if ( resetTime ) {
const deltaSeconds = Math . ceil ( ( resetTime . getTime ( ) - Date . now ( ) ) / 1e3 ) ;
response . setHeader ( "RateLimit-Reset" , Math . max ( 0 , deltaSeconds ) ) ;
}
}
if ( options . skipFailedRequests || options . skipSuccessfulRequests ) {
let decremented = false ;
const decrementKey = async ( ) => {
if ( ! decremented ) {
await options . store . decrement ( key ) ;
decremented = true ;
}
} ;
if ( options . skipFailedRequests ) {
response . on ( "finish" , async ( ) => {
if ( ! options . requestWasSuccessful ( request , response ) )
await decrementKey ( ) ;
} ) ;
response . on ( "close" , async ( ) => {
if ( ! response . writableEnded )
await decrementKey ( ) ;
} ) ;
response . on ( "error" , async ( ) => {
await decrementKey ( ) ;
} ) ;
}
if ( options . skipSuccessfulRequests ) {
response . on ( "finish" , async ( ) => {
if ( options . requestWasSuccessful ( request , response ) )
await decrementKey ( ) ;
} ) ;
}
}
if ( maxHits && totalHits === maxHits + 1 ) {
options . onLimitReached ( request , response , options ) ;
}
if ( maxHits && totalHits > maxHits ) {
if ( ( options . legacyHeaders || options . standardHeaders ) && ! response . headersSent ) {
response . setHeader ( "Retry-After" , Math . ceil ( options . windowMs / 1e3 ) ) ;
}
options . handler ( request , response , next , options ) ;
return ;
}
next ( ) ;
} ) ;
middleware . resetKey = options . store . resetKey . bind ( options . store ) ;
return middleware ;
} ;
var lib _default = rateLimit ;
export {
2022-01-18 16:39:42 +00:00
lib _default as default ,
lib _default as rateLimit
2022-01-09 15:20:59 +00:00
} ;