| Name | Modified | Size | Downloads / Week |
|---|---|---|---|
| Parent folder | |||
| README.md | 2026-09-30 | 5.0 kB | |
| v2.20.0 source code.tar.gz | 2026-09-30 | 4.2 MB | |
| v2.20.0 source code.zip | 2026-09-30 | 4.7 MB | |
| Totals: 3 Items | 8.8 MB | 0 | |
What's Changed in v2.20.0
New features
ZipWriter#appendZip()accepts afilteroption: a function called once per entry of the appended zip file, in central directory order, and the entry is copied when it returns or resolves totrue. The entries left out leave no bytes behind. The duplicate filename check applies to the kept entries only. Together, this edits an existing zip file into a new one without decompressing its data:appendZip(reader, { filter })copies the entries to keep as-is, thenadd()writes the replacements and the additions. With the option, the data is copied entry by entry and the bytes outside the entries, e.g. a self-extracting stub, are not copied. Without it, the zip file is copied as a whole as before. The option also works with split zip file writers
Bug fixes
- An archive carrying a digital signature record, i.e. written with the
signCentralDirectoryoption, failed to open withERR_CENTRAL_DIRECTORY_NOT_FOUNDonce data was prepended to it, e.g. a self-extracting stub: the relocation of the central directory assumed nothing lies between the directory and the end of central directory record. The reader now looks for a signature record ending right before the end of central directory record, and takes the directory to end where that record starts - An end of central directory record holding the Zip64 sentinel in its offset, size or disk number field with no Zip64 locator in front of it is rejected with
ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUNDat every strictness level. It used to be opened with a "prepended data" warning and entries whose data could not be read, since the sentinel was taken for an offset - A central directory record holding the Zip64 sentinel in a size or offset field with no Zip64 extra field resolving it no longer makes the whole archive fail
getEntries()at the"balanced"and"tolerant"levels: the entry is listed, the newWARNING_MISSING_ZIP64_EXTRA_FIELDreason names it onZipReader#warnings, reading its data throwsERR_EXTRAFIELD_ZIP64_NOT_FOUND, and the other entries stay readable. The"strict"level keeps throwingERR_EXTRAFIELD_ZIP64_NOT_FOUNDfromgetEntries(), as every level did before EntryMetaData#lastModDatetakes the value of the NTFS extra field (0x000a, 100 ns) over the value of the extended timestamp field (0x5455, 1 s) when a record carries both, as the type declarations already said forrawLastModDate. The extended timestamp used to win because it was read last, so an entry zip.js itself writes with a sub-second date andlastAccessDate,creationDateorntfsTimestamp: trueread back with the milliseconds dropped
Behaviour changes
- When the offset stored in the end of central directory record points past the central directory actually found, the reader deposits the new
WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSETreason and the"strict"level rejects the archive withERR_AMBIGUOUS_ARCHIVE; the relocation used to be silent at every level. This is the shape of an archive written with absolute offsets for a prefix that is no longer there: when the local file header of the first entry is found at the same shifted position, the entries are now read from the shifted positions instead of failing withERR_LOCAL_FILE_HEADER_NOT_FOUND EntryMetaData#executableisfalsefor directories, as it already was for symbolic links: the execute bits of a directory mean it can be searched, and every directory carries them, so the flag wastruefor every folder written by zip.js.unixModestill holds the bits
Documentation
WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET,WARNING_MISSING_ZIP64_EXTRA_FIELDandZipWriterAppendZipOptionsare documented;ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUNDsays when it is thrown;rawLastModDateandexecutabledescribe the precedence rules above;GetEntriesOptions#filenameValidationstates that the filename reported is the decoded central directory name or the one of a valid Unicode Path extra field, and that the name validated is that final name- The site documents how to read and write Zstandard entries (compression method 93) with
registerCodec(): a codec built on thenode:zlibstreams for Node.js, the platformCompressionStreamclasses on Bun, and a JavaScript decoder such as fzstd elsewhere
Benchmarks
- The ZIP API added to
node:zlibin Node.js 26.8 is measured next to jszip, fflate and archiver in BENCHMARKS.md, and the page was re-run on Node.js 26.10, except its browser encryption table, measured on 2026-09-26. The page now says which version of zip.js each table was measured with
Dependencies
- The transitive development dependencies markdown-it and brace-expansion are updated in the lock file; no runtime dependency changed, zip.js has none
Full Changelog: https://github.com/gildas-lormeau/zip.js/compare/v2.19.0...v2.20.0
Co-Authored-By: Claude Fable 5.1 noreply@anthropic.com