wasm_br 0.12.1

esm modules for brotli compression and/or decompression, with sync and async (worker) versions
Documentation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
<style>
  *{margin:0;padding:0;box-sizing:border-box}
  html{height:100%;font:3vmin monospace;background:#222;color:#eee}
  body{min-height:100%;padding:1rem;display:grid;place-items:center}
  main{display:flex;flex-direction:column}
  main>div{height:2rem}
  .ok{color:green}
  .ko{color:red}
</style>
</head>
<body>
<main>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</main>
</body>
<script type="module">
const mod=import('./brotli_worker.mjs');
const divs=[...document.querySelectorAll('main>div')];
divs[0].textContent='Fetching data...';
const original=new Uint8Array(await(await fetch('./brotli.wasm.br')).arrayBuffer());
divs[0].textContent+=`done (${original.byteLength})`;
divs[1].textContent='Encrypting data...';
const iv=crypto.getRandomValues(new Uint8Array(12));
const key=await crypto.subtle.generateKey({name:'AES-GCM',length:256},true,['encrypt','decrypt']);
const encrypted=new Uint8Array(await crypto.subtle.encrypt({name:'AES-GCM',iv},key,original));
divs[1].textContent+='done';
divs[2].textContent='Initializing compressor...';
const {br,unbr}=await mod;
divs[2].textContent+='done';
divs[3].textContent='Compressing best quality...';
const compressedBest=await br(encrypted,11);
divs[3].textContent+=`done (${compressedBest.byteLength} B)`;
divs[4].textContent='Decompressing...';
const decompressedBest=await unbr(compressedBest);
divs[4].textContent+=`done (${decompressedBest.byteLength} B)`;
divs[5].textContent='Decrypting...';
const decryptedBest=new Uint8Array(await crypto.subtle.decrypt({name:'AES-GCM',iv},key,decompressedBest));
divs[5].textContent+=`done`;
divs[6].textContent='Comparing...';
const lenBest=decryptedBest.byteLength;
let sameBest=lenBest===original.byteLength;
if(sameBest){
  for(let i=0;i<lenBest;++i){
    if(decryptedBest[i]!==original[i]){
      console.log(i);
      sameBest=false;
      break;
    }
  }
}
divs[6].innerHTML+=sameBest?'<span class="ok">identical</span>':'<span class="ko">not identical</span>';
divs[7].textContent='Compressing fast...';
const compressedFast=await br(encrypted,1);
divs[7].textContent+=`done (${compressedFast.byteLength} B)`;
divs[8].textContent='Decompressing...';
const decompressedFast=await unbr(compressedFast);
divs[8].textContent+=`done (${decompressedFast.byteLength} B)`;
divs[9].textContent='Decrypting...';
const decryptedFast=new Uint8Array(await crypto.subtle.decrypt({name:'AES-GCM',iv},key,decompressedFast));
divs[9].textContent+=`done`;
divs[10].textContent='Comparing...';
const lenFast=decryptedFast.byteLength;
let sameFast=lenFast===original.byteLength;
if(sameFast){
  for(let i=0;i<lenFast;++i){
    if(decryptedFast[i]!==original[i]){
      console.log(i);
      sameFast=false;
      break;
    }
  }
}
divs[10].innerHTML+=sameFast?'<span class="ok">identical</span>':'<span class="ko">not identical</span>';
</script>
</html>