import { deflateRawSync } from "node:zlib"; type ZipEntry = Readonly<{ bytes: Uint8Array; path: string }>; function crc32(bytes: Uint8Array): number { let crc = 0xffffffff; for (const byte of bytes) { crc ^= byte; for (let bit = 0; bit < 8; bit += 1) { crc = (crc >>> 1) ^ ((crc & 1) === 1 ? 0xedb88320 : 0); } } return (crc ^ 0xffffffff) >>> 0; } export function createZip(entries: readonly ZipEntry[], compress = false): Uint8Array { const localParts: Buffer[] = []; const centralParts: Buffer[] = []; let localOffset = 0; for (const entry of entries) { const name = Buffer.from(entry.path, "utf8"); const source = Buffer.from(entry.bytes); const payload = compress ? deflateRawSync(source) : source; const method = compress ? 8 : 0; const checksum = crc32(source); const local = Buffer.alloc(30); local.writeUInt32LE(0x04034b50, 0); local.writeUInt16LE(20, 4); local.writeUInt16LE(method, 8); local.writeUInt32LE(checksum, 14); local.writeUInt32LE(payload.byteLength, 18); local.writeUInt32LE(source.byteLength, 22); local.writeUInt16LE(name.byteLength, 26); localParts.push(local, name, payload); const central = Buffer.alloc(46); central.writeUInt32LE(0x02014b50, 0); central.writeUInt16LE(20, 4); central.writeUInt16LE(20, 6); central.writeUInt16LE(method, 10); central.writeUInt32LE(checksum, 16); central.writeUInt32LE(payload.byteLength, 20); central.writeUInt32LE(source.byteLength, 24); central.writeUInt16LE(name.byteLength, 28); central.writeUInt32LE(localOffset, 42); centralParts.push(central, name); localOffset += local.byteLength + name.byteLength + payload.byteLength; } const centralDirectory = Buffer.concat(centralParts); const end = Buffer.alloc(22); end.writeUInt32LE(0x06054b50, 0); end.writeUInt16LE(entries.length, 8); end.writeUInt16LE(entries.length, 10); end.writeUInt32LE(centralDirectory.byteLength, 12); end.writeUInt32LE(localOffset, 16); return Buffer.concat([...localParts, centralDirectory, end]); }