import { type FileHandle, open } from "node:fs/promises"; import { orderBy } from "natural-orderby"; import { ZipReader, Reader, type Entry } from "@zip.js/zip.js"; class FileReader extends Reader { private fd: FileHandle; private offset: number; constructor(fd: FileHandle) { super(fd); this.fd = fd; this.offset = 0; } async init(): Promise { this.offset = 0; this.size = (await this.fd.stat()).size; } close(): void { this.fd.close(); } async readUint8Array(index: number, length: number): Promise { const buffer = new Uint8Array(length); const buf = await this.fd.read(buffer, 0, length, index); if (buf.bytesRead !== length) { console.error(`read error: ${buf.bytesRead} !== ${length}`); throw new Error("read error"); } return buffer; } } export async function readZip(path: string): Promise<{ reader: ZipReader handle: FileHandle }> { const fd = await open(path); const reader = new ZipReader(new FileReader(fd), { useCompressionStream: true, preventClose: false, }); return { reader, handle: fd }; } export async function entriesByNaturalOrder(zip: ZipReader) { // console.log(zip); const entries = await zip.getEntries(); // console.log(entries.map((v) => v.filename)); const ret = orderBy(entries, (v) => v.filename); return ret; } export async function createReadableStreamFromZip(_zip: ZipReader, entry: Entry): Promise { if (entry.getData === undefined) { throw new Error("entry.getData is undefined"); } const stream = new TransformStream(); entry.getData(stream.writable); return stream.readable; }