Random access
Read one entry of a 4 GB archive with three range reads — the central directory is parsed lazily, payloads are zero-copy views. No “extract everything first”.
100 % TypeScript. Zero runtime dependencies. One API across Node ≥ 22, browsers, Deno, Bun and Workers — for modern apps and the agents that operate them.
npm install zipnative
1.0 — stable: the API surface, the 39-code error vocabulary and the deterministic bytes are frozen under semver.
Not a faster deflate — a safer, reproducible, streaming archive engine built for scenarios the incumbents cannot do.
Read one entry of a 4 GB archive with three range reads — the central directory is parsed lazily, payloads are zero-copy views. No “extract everything first”.
Zip-slip, symlinks, duplicate names, decompression bombs, overlapping entries, Zip64 spoofing and EOCD ambiguity are all rejected unless you explicitly opt out. Every parser loop runs under a named, CWE-tagged bound.
Reproducible-build mode with a written contract: identical inputs, identical SHA-256, on every runtime — via a pure-TS deflate encoder whose constants are frozen public API.
Replace, add, remove or rename entries and save without recompressing the untouched 99 % — the append-only model proven in pdfnative's PDF incremental updates.
Create archives in fixed-size chunks with bounded memory, and read unseekable streams forward — data-descriptor entries included, thanks to a resumable pure-TS inflater.
zipnative/worker fans per-entry compression across a real pool (worker_threads and Web Workers) — byte-identical output, graceful degradation, never an infra failure.
Sync-first, no classes, every error carries a stable machine-readable code.
import { openZip, extractZip } from 'zipnative';
const zip = openZip(bytes); // lazy — nothing decompressed
const manifest = zip.readEntry('manifest.json'); // one entry, CRC-verified
const files = extractZip(bytes); // traversal/bombs rejected by default
import { createZip } from 'zipnative';
const zip = createZip({ compression: { deterministic: true } });
zip.add('data.json', payload);
const bytes = zip.toBytes(); // same inputs → same SHA-256, anywhere
import { createZipModifier, openZip } from 'zipnative';
const mod = createZipModifier(openZip(bytes));
mod.replaceEntry('word/document.xml', updated);
const saved = mod.save(); // untouched entries never recompressed
fflate keeps the raw-deflate crown and we do not chase it — zipnative wins on scenarios, not drag races.
| zipnative | fflate | jszip | yauzl/yazl | adm-zip | |
|---|---|---|---|---|---|
| Zero runtime dependencies | ✓ | ✓ | ✗ | ✗ | ✗ |
| Random access (1 entry, no full parse) | ✓ | ✗ | ✗ | yauzl ✓ | ✗ |
| Streaming read + write | ✓ | partial | ✗ | one per lib | ✗ |
| Safe-extract defaults (slip/bomb/ambiguity) | ✓ | DIY | DIY | DIY | historical CVEs |
| Deterministic output (written contract) | ✓ | DIY | ✗ | ✗ | ✗ |
| Modify in place, no recompression | ✓ | ✗ | rewrite-all | ✗ | partial |
| Stable machine-readable error codes | ✓ | ✗ | ✗ | ✗ | ✗ |
| Browser + Node + Deno + Bun + Workers | ✓ | ✓ | ✓ | Node-only | Node-only |
| Raw deflate throughput | good (platform zlib) | best | slow | good | poor |
Measured scenarios, security checks always on — including the one we lose.
Windows 11, Node v22.17, tiny-entry corpus — the worst case for the random-access rows (with megabyte entries the gap becomes orders of magnitude). zipnative numbers include the always-on security checks. Full methodology: bench/RESULTS.md.
Every archive is untrusted input; the default code path is the safe one.
Extraction refuses traversal (../, absolute paths, drive letters,
NTFS streams), symlink entries and bombs; the reader refuses overlapping
entries, parser-differential headers and ambiguous end-of-central-directory
records. Bounds are named, CWE-tagged, documented and caller-configurable —
raising one is always an explicit decision. Every refusal throws a stable
machine-readable error code.
Identical inputs, identical SHA-256 — on any runtime.
compression: { deterministic: true } pins the pure-TS encoder:
the mode for content addressing, caching, signatures and reproducible builds.
The contract is written down and golden-tested; changing the emitted bytes
is a semver-major event.
Machine-readable ground truth at every level — never guessed, always verified.
Stable error codes (errors.json), a structured diagnostics channel, executable recipes, and the mechanically extracted export surface in api.json — plus llms.txt and llms-full.txt for context ingestion, with byte and approximate token budgets for every artefact in llms-index.json so an agent can decide what to fetch before spending the tokens. Developed under a human-in-the-loop AI governance policy.
zipnative is the sibling of pdfnative: the same doctrine — zero dependencies, closure factories, strict layers, sync-first, security by default — applied to the ZIP format. The incremental-update model, the AI governance policy and this documentation pipeline were extracted from pdfnative and hardened here.