Heads = async ({ storage, heads, decryptPayloadFn, decryptEntryFn }) => {
  storage = storage || await DefaultStorage()

  const encoder = new TextEncoder()
  const decoder = new TextDecoder()

  const put = async (heads) => {
    heads = findHeads(heads)
    const newHeads = heads.map(e => ({ hash: e.hash, next: e.next }))
    const bytes = encoder.encode(JSON.stringify(newHeads))
    await storage.put('heads', bytes)
  }

  const add = async (head) => {
    const currentHeads = await all()
    if (currentHeads.find(e => Entry.isEqual(e, head))) {
      return
    }
    const newHeads = findHeads([...currentHeads, head])
    await put(newHeads)
    return newHeads
  }

  const remove = async (hash) => {
    const currentHeads = await all()
    const newHeads = currentHeads.filter(e => e.hash !== hash)
    await put(newHeads)
  }

  const iterator = async function * () {
    const bytes = await storage.get('heads')
    const headHashes = bytes ? JSON.parse(decoder.decode(bytes)) : []
    for (const hash of headHashes) {
      yield hash
    }
  }

  const all = async () => {
    const values = []
    for await (const head of iterator()) {
      values.push(head)
    }
    return values
  }

  const clear = async () => {
    await storage.clear()
  }

  const close = async () => {
    await storage.close()
  }

  // Initialize the heads if given as parameter
  if (heads) {
    await put(heads)
  }

  return {
    put,
    set: put,
    add,
    remove,
    iterator,
    all,
    clear,
    close
  }
}
@namespace module:Log~Heads
@memberof module:Log
@description The log's heads.
@private