AnasSarkiz/muse-voice-remote

Muse Voice Remote — bare ESP32-S3R8, 155 TOP JLCPCB parts with real supplier CAD, native 3D assembly and GLB exports. Revised 17 mm case allocation; 0.30 mm via drill /0.45 mm pad. Checked prototype PCB; mechanical, RF and MUSE qualification pending.

Version
1.3.2
License
unset
Stars
0

scripts/chunk-assets.ts

import {readFile,writeFile,mkdir,rm,readdir} from "node:fs/promises"
import {createHash} from "node:crypto"
import {dirname,join,basename} from "node:path"

const hash=(bytes:Uint8Array)=>createHash("sha256").update(bytes).digest("hex")
export async function writeAssetChunks(files:string[],manifestFile:string){
  const root=dirname(manifestFile),directory=join(root,"asset-parts")
  await mkdir(directory,{recursive:true})
  const assets:Record<string,{bytes:number;sha256:string;parts:{path:string;bytes:number;sha256:string}[]}>= {}
  for(const file of files){
    const bytes=await readFile(file),name=basename(file),parts=[]
    for(const old of await readdir(directory))
      if(old.startsWith(`${name}.part`)&&old.endsWith(".bin"))await rm(join(directory,old))
    for(let start=0,n=0;start<bytes.length;start+=2*1024*1024,n++){
      const chunk=bytes.subarray(start,Math.min(start+2*1024*1024,bytes.length))
      const path=`asset-parts/${name}.part${String(n).padStart(3,"0")}.bin`
      await writeFile(join(root,path),chunk)
      parts.push({path,bytes:chunk.length,sha256:hash(chunk)})
    }
    const reassembled=Buffer.concat(await Promise.all(parts.map(p=>readFile(join(root,p.path)))))
    if(!reassembled.equals(bytes))throw Error(`Asset round trip failed: ${name}`)
    assets[name]={bytes:bytes.length,sha256:hash(bytes),parts}
  }
  const result={format:"sha256-verified-byte-parts-v1",chunk_bytes:2*1024*1024,assets}
  await writeFile(manifestFile,JSON.stringify(result,null,2)+"\n")
  return result
}