UNPKG

advanced-ussd-builder

Version:

Advanced USSD Menu Builder with persistent state and navigation

2 lines (1 loc) 3.03 kB
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.RateLimitStrategies=exports.RateLimiter=void 0;const events_1=require("events");class RateLimiter extends events_1.EventEmitter{constructor(s={}){super(),this.attempts=new Map,this.maxAttempts=s.maxAttempts||10,this.windowMs=s.windowMs||6e4,this.blockDurationMs=s.blockDurationMs||3e5,this.skipSuccessfulRequests=s.skipSuccessfulRequests||!1,this.cleanupInterval=setInterval(()=>this.cleanup(),6e4)}check(s){const e=Date.now();let t=this.attempts.get(s);if(t||(t={timestamps:[],blocked:!1},this.attempts.set(s,t)),t.blocked&&t.blockExpiry)if(e<t.blockExpiry){const r=Math.ceil((t.blockExpiry-e)/1e3);return this.emit("blocked",{identifier:s,retryAfter:r,blockExpiry:new Date(t.blockExpiry)}),{allowed:!1,remaining:0,resetAt:new Date(t.blockExpiry),retryAfter:r}}else t.blocked=!1,t.blockExpiry=void 0,t.timestamps=[];t.timestamps=t.timestamps.filter(r=>e-r<this.windowMs);const i=this.maxAttempts-t.timestamps.length,a=t.timestamps.length>0?new Date(t.timestamps[0]+this.windowMs):new Date(e+this.windowMs);return t.timestamps.length>=this.maxAttempts?(t.blocked=!0,t.blockExpiry=e+this.blockDurationMs,this.emit("limit-exceeded",{identifier:s,attempts:t.timestamps.length,blockDuration:this.blockDurationMs}),{allowed:!1,remaining:0,resetAt:new Date(t.blockExpiry),retryAfter:Math.ceil(this.blockDurationMs/1e3)}):(t.timestamps.push(e),{allowed:!0,remaining:i-1,resetAt:a})}recordSuccess(s){if(this.skipSuccessfulRequests){const e=this.attempts.get(s);e&&e.timestamps.length>0&&e.timestamps.pop()}}reset(s){this.attempts.delete(s),this.emit("reset",{identifier:s})}resetAll(){this.attempts.clear(),this.emit("reset-all")}getStats(s){const e=this.attempts.get(s);if(!e)return null;const t=Date.now(),i=e.timestamps.filter(a=>t-a<this.windowMs);return{attempts:i.length,blocked:e.blocked&&(!e.blockExpiry||t<e.blockExpiry),blockExpiry:e.blockExpiry?new Date(e.blockExpiry):void 0,remaining:Math.max(0,this.maxAttempts-i.length)}}cleanup(){const s=Date.now(),e=[];for(const[t,i]of this.attempts.entries()){const a=i.timestamps.some(c=>s-c<this.windowMs*2),r=i.blocked&&i.blockExpiry&&s<i.blockExpiry;!a&&!r&&e.push(t)}for(const t of e)this.attempts.delete(t);e.length>0&&this.emit("cleanup",{removed:e.length})}destroy(){this.cleanupInterval&&clearInterval(this.cleanupInterval),this.attempts.clear(),this.removeAllListeners()}}exports.RateLimiter=RateLimiter;class RateLimitStrategies{static createApiLimiter(){return new RateLimiter({maxAttempts:100,windowMs:6e4,blockDurationMs:3e5})}static createAuthLimiter(){return new RateLimiter({maxAttempts:5,windowMs:3e5,blockDurationMs:9e5,skipSuccessfulRequests:!0})}static createPinLimiter(){return new RateLimiter({maxAttempts:3,windowMs:3e5,blockDurationMs:36e5,skipSuccessfulRequests:!0})}static createTransactionLimiter(){return new RateLimiter({maxAttempts:10,windowMs:36e5,blockDurationMs:36e5})}static createCustomLimiter(s){return new RateLimiter(s)}}exports.RateLimitStrategies=RateLimitStrategies;