This solution is generated by ChatGPT, correctness is not guaranteed.

AI solution for JavaScript Coding Question on BFE.dev
169. LRU - Chrome storage automatic eviction

Here's one possible implementation of the LRUStorage class:

interface OriginData {
  origin: string
  lastUsed: number
  size: number
  persistent: boolean
}

class LRUStorage {
  private originMap: Map<string, OriginData>
  private timestampFn: () => number

  constructor(public capacity: number, getTimestamp: () => number) {
    this.originMap = new Map()
    this.timestampFn = getTimestamp
  }

  private evict(): void {
    let lruOrigin: string | undefined = undefined
    let oldestTimestamp = this.timestampFn()
    for (const [origin, data] of this.originMap) {
      if (!data.persistent && data.lastUsed < oldestTimestamp) {
        lruOrigin = origin
        oldestTimestamp = data.lastUsed
      }
    }
    if (lruOrigin !== undefined) {
      this.originMap.delete(lruOrigin)
    }
  }

  getData(origin: string): OriginData | undefined {
    const data = this.originMap.get(origin)
    if (data !== undefined) {
      data.lastUsed = this.timestampFn()
      return data
    } else {
      return undefined
    }
  }

  setData(origin: string, size: number): boolean {
    if (this.capacity < size) {
      return false
    }
    while (this.originMap.size > 0 && this.getTotalSize() + size > this.capacity) {
      this.evict()
    }
    const data: OriginData = {
      origin,
      lastUsed: this.timestampFn(),
      size,
      persistent: false,
    }
    this.originMap.set(origin, data)
    return true
  }

  makePersistent(origin: string): void {
    const data = this.originMap.get(origin)
    if (data !== undefined) {
      data.persistent = true
    }
  }

  clearData(origin: string): void {
    this.originMap.delete(origin)
  }

  private getTotalSize(): number {
    let totalSize = 0
    for (const data of this.originMap.values()) {
      totalSize += data.size
    }
    return totalSize
  }
}

This implementation uses a Map to store the origin data, with the origin string as the key and an OriginData object as the value. The OriginData interface has fields for the origin string, the timestamp of the last time the data was used (lastUsed), the size of the data in bytes (size), and a flag representing whether the data is "persistent" and can't be evicted (persistent).

The constructor takes a capacity parameter and a function that returns the current timestamp as arguments. The evict method finds and removes the least recently used non-persistent origin data in the map. The getData method returns the OriginData object for a given origin string and updates its lastUsed timestamp. The setData method adds or updates the OriginData object for a given origin string and size, and also evicts non-persistent data until the total size is below the capacity. The makePersistent method sets the persistent flag for a given origin data object. The clearData method removes the origin data object for a given origin string from the map. The getTotalSize method calculates the total size of all the origin data in the map.