All files / proxy/utils cache.ts

100% Statements 18/18
83.33% Branches 5/6
100% Functions 7/7
100% Lines 18/18

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 5912x             12x         12x     16x 16x       53x 53x 19x     34x 7x 7x     27x       21x   21x             7x       1x       12x       37x      
import { isNonNegativeInteger } from './validation'
 
interface CacheItem<T> {
  value: T
  expiresAt: number
}
 
export class TTLCache<K, V> {
  private cache: Map<K, CacheItem<V>>
  private readonly ttlMs: number
 
  // Default TTL is 5 minutes
  private static readonly DEFAULT_TTL_MS = 300_000
 
  constructor(ttlMs: number) {
    this.cache = new Map()
    this.ttlMs = TTLCache.isValidTTL(ttlMs) ? ttlMs : TTLCache.DEFAULT_TTL_MS
  }
 
  get(key: K): V | undefined {
    const item = this.cache.get(key)
    if (item === undefined) {
      return undefined
    }
 
    if (Date.now() >= item.expiresAt) {
      this.cache.delete(key)
      return undefined
    }
 
    return item.value
  }
 
  set(key: K, value: V, customTtlMs?: number): void {
    const ttlMsToUse = TTLCache.isValidTTL(customTtlMs) ? customTtlMs : this.ttlMs
 
    this.cache.set(key, {
      value,
      expiresAt: Date.now() + ttlMsToUse,
    })
  }
 
  has(key: K): boolean {
    return this.get(key) !== undefined
  }
 
  delete(key: K): void {
    this.cache.delete(key)
  }
 
  clear(): void {
    this.cache.clear()
  }
 
  static isValidTTL(value?: number): value is number {
    return isNonNegativeInteger(value)
  }
}