UNPKG

@joaquimserafim/ttl-lru-cache

Version:

A TypeScript cache implementation focused on time-based expiration with automatic cleanup and TTL support

2 lines 4 kB
var p=()=>performance.now(),u=o=>Number.isInteger(o)&&o>0,h=o=>o===1/0||u(o),l=class o{constructor(e={}){this.expirations=Object.create(null);this.data=new Map;this.expirationMap=new Map;this.removeKeys=(e,t="evict")=>{let n=[];for(let i of e)n.push([i,this.data.get(i)]),this.data.delete(i),this.expirationMap.delete(i);for(let[i,s]of n)this.handleRemoval(s,i,t);};let{max:t=1/0,ttl:n,updateAgeOnGet:i=false,checkAgeOnGet:s=false,noUpdateTTL:r=false,onRemove:a,skipRemoveOnSet:c=false}=e;if(n!==void 0&&!h(n))throw new TypeError("ttl must be positive integer or Infinity if set");if(!h(t))throw new TypeError("max must be positive integer or Infinity");if(this.ttl=n,this.max=t,this.updateAgeOnGet=!!i,this.checkAgeOnGet=!!s,this.noUpdateTTL=!!r,this.skipRemoveOnSet=!!c,a!==void 0){if(typeof a!="function")throw new TypeError("onRemove must be a function, received "+typeof a);this.handleRemoval=a;}}handleRemoval(e,t,n){}setTimer(e,t){if(this.timerExpiration!==void 0&&this.timerExpiration<e)return;this.timer&&clearTimeout(this.timer);let n=setTimeout(()=>{this.timer=void 0,this.timerExpiration=void 0,this.purgeStale();for(let i in this.expirations){let s=Number(i);this.setTimer(s,s-p());break}},t);typeof n.unref=="function"&&n.unref(),this.timerExpiration=e,this.timer=n;}cancelTimer(){this.timer&&(clearTimeout(this.timer),this.timerExpiration=void 0,this.timer=void 0);}clear(){let e=this.handleRemoval!==o.prototype.handleRemoval?[...this]:[];this.data.clear(),this.expirationMap.clear(),this.cancelTimer(),this.expirations=Object.create(null);for(let[t,n]of e)this.handleRemoval(n,t,"delete");}setTTL(e,t=this.ttl){let n=this.expirationMap.get(e);if(n!==void 0){let i=this.expirations[n];!i||i.length<=1?delete this.expirations[n]:this.expirations[n]=i.filter(s=>s!==e);}if(t!==1/0){let i=Math.floor(p()+t);this.expirationMap.set(e,i),this.expirations[i]||(this.expirations[i]=[],this.setTimer(i,t)),this.expirations[i].push(e);}else this.expirationMap.set(e,1/0);}set(e,t,n={}){let{ttl:i=this.ttl,noUpdateTTL:s=this.noUpdateTTL,skipRemoveOnSet:r=this.skipRemoveOnSet}=n;if(!h(i))throw new TypeError("ttl must be positive integer or Infinity");if(this.expirationMap.has(e)){s||this.setTTL(e,i);let a=this.data.get(e);a!==t&&(this.data.set(e,t),r||this.handleRemoval(a,e,"set"));}else this.setTTL(e,i),this.data.set(e,t);for(;this.size>this.max;)this.purgeToCapacity();return this}has(e){return this.data.has(e)}getRemainingTTL(e){let t=this.expirationMap.get(e);return t===1/0?1/0:t!==void 0?Math.max(0,Math.ceil(t-p())):0}get(e,t={}){let{updateAgeOnGet:n=this.updateAgeOnGet,ttl:i=this.ttl,checkAgeOnGet:s=this.checkAgeOnGet}=t,r=this.data.get(e);if(s&&this.getRemainingTTL(e)===0){this.delete(e);return}return n&&this.setTTL(e,i),r}delete(e){let t=this.expirationMap.get(e);if(t!==void 0){let n=this.data.get(e);this.data.delete(e),this.expirationMap.delete(e);let i=this.expirations[t];return i&&(i.length<=1?delete this.expirations[t]:this.expirations[t]=i.filter(s=>s!==e)),this.handleRemoval(n,e,"delete"),this.size===0&&this.cancelTimer(),true}return false}get size(){return this.data.size}purgeToCapacity(){for(let e in this.expirations){let t=this.expirations[e];if(this.size-t.length>=this.max)delete this.expirations[e],this.removeKeys(t,"evict");else {let n=this.size-this.max,i=t.splice(0,n);this.removeKeys(i,"evict");return}}}purgeStale(){let e=Math.ceil(p());for(let t in this.expirations){if(t==="Infinity"||Number(t)>e)return;let n=[...this.expirations[t]||[]];delete this.expirations[t],this.removeKeys(n,"stale");}this.size===0&&this.cancelTimer();}*entries(){for(let e in this.expirations)for(let t of this.expirations[e])yield [t,this.data.get(t)];}*keys(){for(let e in this.expirations)for(let t of this.expirations[e])yield t;}*values(){for(let e in this.expirations)for(let t of this.expirations[e])yield this.data.get(t);}[Symbol.iterator](){return this.entries()}};export{l as TTLCache};//# sourceMappingURL=index.mjs.map //# sourceMappingURL=index.mjs.map