ProvenPin Install

yazl to yauzl stream zip roundtrip: working versions (tested 2026-10-16)

Build a zip in memory with yazl.ZipFile from buffers and strings, pipe its outputEntryData stream into a buffer, then read every entry back with yauzl.fromBuffer using lazyEntries and promise-wrapped callbacks.

passed2 passed · 0 failed2026-10-16 02:19 UTC
Status
passed
Last passed
2026-10-16 02:19 UTC
Tests
2 / 2
Language
TypeScript
Runtime
node v22.23.3
pinned versions4
yazl@3.3.1yauzl@3.4.0@types/node@26.6.5tsx@4.23.15
run it
npm install --no-audit --no-fund --ignore-scripts=false
npm test
test environment
node v22.23.3
linux 6.17.0-1022-azure
x64
runner: github-actions 38839686104

The code

Exactly the files that passed. Your agent can pull them with get_recipe("yazl-yauzl-stream-zip") (install), or see them on GitHub.

package.json
{
  "name": "yazl-yauzl-stream-zip",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --import tsx --test test/*.test.ts"
  },
  "dependencies": {
    "yazl": "3.3.1",
    "yauzl": "3.4.0"
  },
  "devDependencies": {
    "@types/node": "26.6.5",
    "tsx": "4.23.15"
  }
}
src/zip.ts
import yazl from "yazl";
import yauzl from "yauzl";

export type EntryInput = { name: string; data: Buffer | string };

export function createZip(entries: EntryInput[]): Promise<Buffer> {
  return new Promise((resolve, reject) => {
    const zipfile = new yazl.ZipFile();
    const chunks: Buffer[] = [];

    zipfile.outputStream.on("data", (chunk: Buffer) => chunks.push(chunk));
    zipfile.outputStream.on("error", reject);
    zipfile.outputStream.on("end", () => resolve(Buffer.concat(chunks)));

    for (const entry of entries) {
      const data =
        typeof entry.data === "string" ? Buffer.from(entry.data, "utf8") : entry.data;
      zipfile.addBuffer(data, entry.name);
    }

    zipfile.end();
  });
}

export function readZip(buffer: Buffer): Promise<Map<string, Buffer>> {
  return new Promise((resolve, reject) => {
    yauzl.fromBuffer(buffer, { lazyEntries: true }, (err, zipfile) => {
      if (err || !zipfile) {
        reject(err ?? new Error("failed to open zip"));
        return;
      }

      const entries = new Map<string, Buffer>();
      zipfile.on("error", reject);
      zipfile.on("end", () => resolve(entries));

      zipfile.on("entry", (entry) => {
        if (entry.fileName.endsWith("/")) {
          zipfile.readEntry();
          return;
        }

        zipfile.openReadStream(entry, (streamErr, readStream) => {
          if (streamErr || !readStream) {
            reject(streamErr ?? new Error("failed to open read stream"));
            return;
          }

          const chunks: Buffer[] = [];
          readStream.on("data", (chunk: Buffer) => chunks.push(chunk));
          readStream.on("error", reject);
          readStream.on("end", () => {
            entries.set(entry.fileName, Buffer.concat(chunks));
            zipfile.readEntry();
          });
        });
      });

      zipfile.readEntry();
    });
  });
}
test/zip.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import { createZip, readZip } from "../src/zip.ts";

test("roundtrips buffers and strings through yazl and yauzl", async () => {
  const archive = await createZip([
    { name: "hello.txt", data: "hello world" },
    { name: "bytes.bin", data: Buffer.from([1, 2, 3, 4]) },
  ]);

  assert.ok(Buffer.isBuffer(archive));

  const entries = await readZip(archive);
  assert.equal(entries.get("hello.txt")?.toString("utf8"), "hello world");
  assert.deepEqual([...entries.get("bytes.bin")!], [1, 2, 3, 4]);
});

test("reads many lazily listed entries", async () => {
  const inputs = Array.from({ length: 5 }, (_, i) => ({
    name: `file-${i}.txt`,
    data: `content-${i}`,
  }));

  const archive = await createZip(inputs);
  const entries = await readZip(archive);

  assert.equal(entries.size, 5);
  assert.equal(entries.get("file-4.txt")?.toString("utf8"), "content-4");
});

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.