async function entityTag(entity) {
  const sha1 = crypto.createHash("sha1");

  if (!Buffer.isBuffer(entity)) {
    let byteLength = 0;

    /** @type {Buffer[]} */
    const buffers = [];

    await new Promise((resolve, reject) => {
      entity
        .on("data", (chunk) => {
          sha1.update(chunk);
          buffers.push(/** @type {Buffer} */ (chunk));
          byteLength += /** @type {Buffer} */ (chunk).byteLength;
        })
        .on("end", () => {
          resolve(sha1);
        })
        .on("error", reject);
    });

    return {
      buffer: Buffer.concat(buffers),
      hash: `"${byteLength.toString(16)}-${sha1.digest("base64").slice(0, 27)}"`,
    };
  }

  if (entity.byteLength === 0) {
    // Fast-path empty
    return { hash: '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"' };
  }

  // Compute hash of entity
  const hash = sha1.update(entity).digest("base64").slice(0, 27);

  // Compute length of entity
  const { byteLength } = entity;

  return { hash: `"${byteLength.toString(16)}-${hash}"` };
}
Generate an entity tag.
@param {Buffer | ReadStream} entity entity
@returns {Promise<{ hash: string, buffer?: Buffer }>} etag