npm / @zip.js/zip.js
@zip.js/zip.js
What changed in @zip.js/zip.js 2, from its official release notes, upgrade guides and advisories. Sources checked 2026-11-15.
102 breaking6 security5 deprecations102 new APIs and options9 performance18 behavior and defaults1 tooling142 fixes and other
See which of these apply to your code, ranked, in your agent:
npx @unstale/cli init@zip.js/zip.js 2385 changes
Breaking changes 102
The method is now typed on
Uint8Arraychunks on both sides and no longer takes a type parameter; its readable side is the zipped stream.The method is now typed on
Uint8Arraychunks on both sides and no longer takes a type parameter.Data descriptors are skipped when the local header can carry the CRC-32 and sizes, including specified cases involving passThrough, bufferedWrite, and dataDescriptor: false; explicit dataDescriptor: true and other listed cases retain them.
The WorkerConfiguration option is removed; configure() silently ignores it, but TypeScript reports it as unknown.
Validates each kept entry's local file header and bounds before writing; throws ERR_LOCAL_FILE_HEADER_NOT_FOUND or ERR_OVERLAPPING_ENTRY and leaves the current zip unchanged on failure.
Refuses to copy an entry with an unresolved Zip64 sentinel unless the filter excludes it, and throws before writing.
Rejects entries whose declared data extent ends past the central directory, at every strictness level.
An end of central directory record with a Zip64 sentinel but no preceding Zip64 locator is rejected at every strictness level.
EntryMetaData#executable is now false for directories; unixMode continues to hold the directory's execute bits.
When both timestamps are present, EntryMetaData#lastModDate now takes the NTFS extra field value over the extended timestamp value, preserving sub-second dates.
A central directory offset past the directory actually found now produces a warning, is rejected in strict mode, and can cause entries to be read from shifted positions when their local headers are found there.
When both New Unix and type 2 fields contain ids, the New Unix field now takes precedence for the ids reported, while extraFieldUnix.uid and extraFieldUnix.gid still report the type 2 values.
Validation now checks the final filename after a valid Unicode Path extra field replaces the decoded central directory name; unsafe names fail with ERR_UNSAFE_FILENAME at strict and balanced levels.
Entry streams are no longer transferred to web workers; the option remains accepted but is ignored and is deprecated in the type declarations.
Central directory Zip64 fields with missing required data or sentinel values without a Zip64 extra field now fail during entry listing, so invalid entries are not listed.
Disagreement between records is rejected under default strictness; tolerant handling and unsupported-encryption checks now use the central directory record.
A ZIP entry whose compressedSize extends beyond its deflate stream now fails on every codec instead of silently dropping the extra bytes.
Corrupted deflated entries now reject with this error regardless of the inflater, preserving the codec error as cause; errors from reading or decrypting data still reach the caller unchanged.
With checkCrc32 enabled, data shorter than the stored uncompressed size now fails with ERR_INVALID_CRC32 instead of ERR_INVALID_UNCOMPRESSED_SIZE.
The WebAssembly and pure-JS codecs now throw TypeError when constructed with an unknown format instead of treating it as deflate.
On hosts whose DecompressionStream lacks deflate-raw, corrupted entries now fail with ERR_INVALID_CRC32 even when CRC checking is disabled.
When disabled, a fallback codec constructor error now fails the entry instead of silently serving it through the native gzip codec.
Balanced validation rejects parent path components delimited by backslashes and names starting with a single backslash; strict validation also rejects names containing NUL.
Names without the UTF-8 flag are decoded as UTF-8 when their bytes are valid and no explicit encoding option is set; explicit options and valid Info-ZIP Unicode Path fields retain precedence.
The import methods declare an array of every ZipFileEntry and ZipDirectoryEntry created by the import, including directories created for path components, instead of a one-element tuple.
A stream cancelled or aborted while an entry is written or read rejects with the caller's reason, including undefined, instead of a TypeError.
Reports an entry failure with a falsy reason instead of returning a truncated archive without throwing.
When combined with passThrough: true, this option now verifies the password and stops after the first block instead of accepting every password and streaming the whole entry.
Values returned by ZipWriter#add() now report the language encoding flag actually written and agree with values read back from the archive.
HttpReader now throws ERR_HTTP_STATUS for every status outside 2xx instead of accepting statuses below 400.
The flag is now set only when an encoded filename or comment contains a byte outside printable ASCII; archives written by zip.js may differ byte for byte.
Now refuses the "compressed" passThrough value at the top level, preventing raw deflated bytes from being written into extracted files.
passThrough is typed as boolean rather than boolean | "compressed", matching the filesystem API's runtime behavior.
Writing a split zip file into a USDZ file now throws ERR_UNSUPPORTED_SPLIT_USDZ rather than silently breaking the required 64-byte alignment.
Throws ERR_INVALID_READER when the second argument is not a Reader, ReadableStream, or object exposing a readable property, instead of silently writing an empty entry.
Now holds the distinct value "Invalid authentication code" instead of aliasing ERR_INVALID_SIGNATURE, so code can identify AES authentication failures.
Now holds the distinct value "Invalid CRC32" instead of aliasing ERR_INVALID_SIGNATURE, so code can identify CRC-32 check failures.
Removed; code comparing an error message to this constant must compare to the constant naming the check that failed.
Removed from entry properties and writer options; use externalFileAttributes instead.
Removed from entry properties and writer options; use internalFileAttributes instead.
Names passed to filesystem add methods are split into path components, creating implicit directories rather than storing slashes in an entry name.
A new error identifies an import refused because of a duplicate entry, replacing ERR_ENTRY_EXISTS for that case.
Size prediction now reads each entry's keepOrder option; when the size is undetermined, the export throws ERR_UNDETERMINED_SIZE.
Preserves leading and trailing whitespace in entry names instead of silently trimming it; Windows filesystems cannot represent a trailing space or dot in a name.
Waits for pending add() and appendZip() calls and throws the first unreported error, with all errors on entryErrors. After catching an error, calling close() again finalizes the zip without failed entries.
Read entries derive directory status from a trailing slash in the filename alone, even when the entry declares an uncompressed size.
Forwards dataDescriptor and rawLastModDate when exporting ZipCrypto pass-through entries, and throws ERR_ZIP_CRYPTO_LAST_MOD_DATE if the date is overridden.
Dates before 1980 are clamped to the MS-DOS epoch instead of underflowing the date field.
Entries stored without compression or encryption now use field value 10 instead of 20.
Copies entries from an existing zip into the current zip at any position, including between add() calls and repeatedly; the copied central directory is rebuilt and entries are relocated.
Aborts its writable when an entry fails so the readable errors instead of hanging.
Reading an archive that declares a 64-bit value above Number.MAX_SAFE_INTEGER now throws ERR_UNSUPPORTED_UINT64 instead of silently rounding it.
Folders and empty stored entries are written without a data descriptor by default; descriptors remain when dataDescriptor is explicitly set or for encrypted entries.
The size prediction now throws ERR_UNDETERMINED_SIZE when zip64 size depends on entry write order, avoiding predictions that differ from the exported archive.
Writing an entry with this option now throws ERR_INVALID_EXTRAFIELD_DATA if alignment padding would make the extra field exceed 64KB.
The callback now receives only the encrypted central directory, excluding any digital signature record.
Adds an error constant thrown when writing an entry with passThrough without specifying compressionMethod.
Writing an entry with passThrough now requires compressionMethod, which declares the existing compression method written into the headers.
The level option is ignored for entries written with passThrough; it continues to apply to other entries in the archive.
Invalid non-positive or non-integer values now fall back to 65536; values below 64 are still raised to 64. Applies to global configuration and Reader#createReadable().
An entry comment must be a string; other types throw ERR_INVALID_ENTRY_COMMENT_TYPE.
Options that expect a function now throw ERR_INVALID_FUNCTION_OPTION for non-function values; falsy values still select the default.
Now counts as Unix metadata, selects the Unix platform and takes precedence over MS-DOS metadata options; it means mode 0o755.
Must be a Map with integer keys from 0 to 65535 and Uint8Array values; invalid maps, keys or values now throw specific errors.
Throws ERR_ENTRY_DATA_OUT_OF_BOUNDS when declared entry data extends past the zip file; reads past the source now end the stream instead of stalling.
Must be a Date instance; other values throw ERR_INVALID_DATE.
Must be a Date instance; other values, including milliseconds, throw ERR_INVALID_DATE.
configure() and setDefaultConfiguration() require an integer greater than 0 or throw ERR_INVALID_MAX_WORKERS, preventing ZipWriter#add() deadlocks.
An array now throws ERR_INVALID_MSDOS_DATA instead of being accepted as an object.
Non-integer values now throw ERR_INVALID_MSDOS_ATTRIBUTES; numeric strings are accepted.
Pass-through data values such as compressionMethod and uncompressedSize now take precedence over options passed when adding an entry.
Reader-side password values are now checked and non-string values throw ERR_INVALID_PASSWORD_TYPE.
Reader-side rawPassword values are now checked and invalid types throw ERR_INVALID_PASSWORD_TYPE.
For ZipDirectoryEntry export and size methods, readerOptions must be an object or throws ERR_INVALID_READER_OPTIONS.
Must expose addEventListener() and a boolean aborted property or throws ERR_INVALID_SIGNAL; duck-typed and cross-realm signals remain supported.
TextWriter now decodes CP437 through the shared decoder; new TextWriter("cp437") no longer falls back to UTF-8.
Removed as an undocumented internal method; use the typed data-adding methods instead.
Directories implied by imported entry names remain navigable but are no longer written back on export unless present in the source or created with addDirectory().
Filesystem entries without an explicit modification date are dated when added, making repeated exports of an unchanged tree stable; date-source precedence is also updated.
Removed; use ZipFS#move() instead.
Options passed when adding an entry are copied, so later mutation or reuse of the options object no longer changes previously added entries.
Removed as an undocumented internal method; the typed addText(), addBlob(), addUint8Array(), addData64URI(), addHttpContent(), addReadable(), addFile(), addFileSystemEntry() and addFileSystemHandle() methods cover its functionality.
An array of readers now denotes the disks of a split zip file, and SplitDataReader is accepted. Disks are read in order and entries relocated; concatenate byte ranges yourself if they belong to one archive.
An explicit value passed to getEntries() or getData() now takes precedence over inherited strictness; strictness still takes precedence when both are passed to the same call.
The default balanced setting now compares the local header’s general purpose bit flag, compression method, CRC-32 checksum, and sizes against the central directory when getData() reads the entry.
The platform byte is forced to Unix or MS-DOS according to the entry’s metadata; only the lower byte of the supplied value survives.
Throws ERR_INVALID_COMMENT_TYPE when the supplied comment is not a Uint8Array, rather than failing later inside the writer.
Filesystem API now ignores reader options that withhold entry content, so imported entries return data.
Added as an error constant and is thrown when pass-through data is written with a password, because copied data cannot be encrypted.
The entry property is now false for symbolic links.
Filesystem export options now override imported-entry metadata; source metadata comes first, followed by export options, copied-as-is descriptions, and entry options.
Filesystem exports now call onstart and onend once for the whole archive, with total entry size and bytes written; use onentryprogress for per-entry notifications.
Now honored only when the caller owns the writable through WritableWriter; ignored by other filesystem export methods so their exports can resolve.
Filesystem export methods now write entries in the same order regardless of bufferedWrite; exports with bufferedWrite set to false may have a different entry order than in previous versions.
Errors are now rethrown unmodified instead of being wrapped, and entryName identifies the handle or entry that failed.
Reading archives now rejects entry names containing a .. path component or starting with /, a drive letter, or \\. Set filenameValidation to tolerant to restore the previous behavior.
When importing an archive, empty and . path components are ignored, so names such as a//b.txt and ./cur.txt no longer create entries with empty or . names.
Invalid option values now throw instead of silently falling back; invalid level, password, rawPassword, strictness, filenameValidation, maxAppendedDataSize, encryptionStrength, uid, gid, and unixMode values are rejected.
When set to strict, the option now also rejects empty and . path components, such as a//b.txt and ./cur.txt.
When reading an entry fails, the writer's writable is now aborted with the error instead of being closed successfully.
For AES-encrypted entries returned by ZipWriter#add(), the deprecated signature property is now undefined rather than exposing the raw authentication code as a Uint8Array.
Entries protected with PKWARE strong encryption are now always rejected with ERR_UNSUPPORTED_ENCRYPTION, even when their compression method is also unsupported.
Security 6
Each entry now owns copies of rawFilename, rawExtraField, and rawComment, so retaining an Entry no longer pins the whole central directory or exposes the reader's buffer through those fields.
Output allocation is clamped to the maximum data the compressed content can decode to, preventing oversized allocation based on an untrusted declared uncompressed size.
New option in ZipReader and getEntries() that rejects entry names that do not map safely to a file path. It accepts strict, balanced, and tolerant, and defaults to strictness.
ZipReader exposes the directory length to help locate signed data and verify it.
ZipReader exposes the directory offset to help locate signed data and verify it.
Adds an option controlling verification of authentication codes for AES-encrypted entries; it is enabled by default.
Deprecations 5
Remains available as a deprecated alias.
The TypeScript FS type is deprecated and retained as an alias of ZipFS.
The namespace is deprecated in favor of top-level exports; it continues to work without a runtime warning.
This option is deprecated and replaced by CompressionStreamFallback.
This option is deprecated and replaced by DecompressionStreamFallback.
New APIs and options 102
addFileSystemEntry() accepts a filter that receives each discovered handle and its path, allowing directories or files to be excluded without walking them.
addFileSystemHandle() accepts a filter that receives each discovered handle and its path, allowing directories or files to be excluded without walking them.
Export methods accept a filter to exclude entries and directory subtrees; excluded entries are not read or counted by progress callbacks.
exportFileSystemHandle() accepts a filter with the same semantics as zip exports.
getExportedSize() accepts a filter to exclude ZipEntry objects from the exported-size calculation.
Import methods on ZipFS and ZipDirectoryEntry accept a filter that can inspect entry data and exclude entries before the duplicates policy.
Adds reader options for the source zip, allowing filenames to be validated, decoded, or read with a password when copying entries.
This error is now exported by the core builds when appendZip receives a value that is neither an object nor unset for readerOptions.
The callback receives the existing entry with the same filename as a second argument, enabling duplicate filename policies.
ZipWriter#appendZip() accepts a filter called once per appended entry; kept entries are copied without decompressing their data, enabling edits that replace or add entries.
Adds a zip64 property indicating whether a data descriptor read with checkOverlappingEntry stores sizes as 8-byte values.
A new exported constant identifies codec allocation failures when reading or writing entries; code matching the former allocation failed message should catch this constant instead.
Export errors caused by unreadable entry data now carry the entry name relative to the exported directory.
Accepts candidate passwords for imported entries; candidates are tried in order, including passwords that already decrypted another entry in the archive.
Requests a password when candidates are exhausted or absent; the function may return a promise, and returning undefined or null makes the entry fail.
When enabled, entry data in the fetched final 64 KB is served from that response, avoiding extra range requests for entries in the cached tail.
Fallback codec classes can declare that construction must wait until a worker or other required module is ready; the library falls back to the native codec if the module fails to load.
Fallback codec classes can declare supported formats through this static flag, which the library reads instead of probing by constructing the class.
Selects whether the local-header filename is compared independently of whether a difference throws, allowing mismatches to be reported as warnings.
Codec errors expose the number of bytes that reached the writer before failure, allowing callers to salvage an archive using the correct output position.
The new value "compressed" passes through the compression stage while still running encryption: reading decrypts without inflating, and writing encrypts without deflating.
Accepts a ZipWriter instance, adds entries to it, and leaves the archive open so callers can add entries, export more trees, and close it themselves.
The new entry option takes an entry read from another archive and derives the values needed to copy it, avoiding corruption from forwarding an incomplete subset of metadata.
A new error is available for invalid duplicates option values.
Filesystem import methods accept a duplicates option with throw, keep-first, or keep-last policies; the default remains throw.
A new type describes filesystem directory-entry import options.
Adds a warning distinguishing concatenated archives, where the data before the archive holds its own central directory, from a self-extracting stub.
Registered compression codecs receive the known source size, allowing codecs to use it as a pledged source size and include content size in the compressed frame.
Returns snapshots of registered codec definitions that cannot alter the registry.
Reports compression methods supported in the current environment and configuration, including separate compression and decompression support.
A constant exposes the library version at runtime and matches the version declared in package.json.
Checks whether data looks like a zip file by locating the archive structure without parsing entries; strictness and maxAppendedDataSize control tolerated appended data.
The entry-level property is set by getData() and collects local file header observations.
Reports deduplicated non-fatal archive-level anomalies noticed while reading; the property is replaced on each getEntries() call.
Adds an option to write an extra field only in the central directory record.
Adds an error constant for the ZipCrypto last-modification-date failure case.
Exposes the byte offset of entry data, usable with Reader#createReadable to serve ranged requests into an uncompressed entry.
Sets an entry's raw MS-DOS date and time directly, which is needed when passThrough copies ZipCrypto entries.
Adds an error constant for unsupported 64-bit values.
Exported interface types the second argument of codec stream constructors and documents which members apply to each class.
Now declared; resolves relative workerURI, wasmURI and codecURI values and defaults to the URL of the zip.js module.
Now declared and updated as bytes are written, allowing custom writers to track their current output size.
Now available as a top-level runtime export.
Exported as a top-level runtime value, so entry instanceof zip.ZipEntry works.
Adds a filesystem-entry options property, paired with setOptions().
Adds filesystem-entry options after creation; options are merged, undefined values remove options, and applicable options take effect when the archive is exported.
Now available as a top-level runtime export; use zip.ZipFileEntry instead of zip.fs.ZipFileEntry.
Exported at the top level; replace new zip.fs.FS() with new zip.ZipFS().
Adds a reader option to compare an entry’s local file header with its central directory record when getData() is called, independently of strictness.
Adds compressionMethod, the entry’s real compression method, alongside originalCompressionMethod.
Adds version, filename, and comment members to the typed Unicode extra field record.
Adds an error constant for invalid comment types.
Adds an interface describing the data descriptor record, including its checksum, sizes, and optional-signature flag.
Exposes the data descriptor record after entry content when checkOverlappingEntry or checkOverlappingEntryOnly is set.
Exposes the filename stored in the local file header; it is defined when strictness is "strict" or checkLocalDirectory is true.
Accepts arrays of Reader, ReadableReader, or ReadableStream instances; stream-only elements are buffered when the reader is initialized.
Added as an error constant.
Added as an error constant for cases where an export's size cannot be determined before writing.
Now accepts readerOptions; set its password to export entries from an encrypted zip file, since the export password encrypts written entries instead.
Added to ZipDirectoryEntry and FS instances to return the exact size an export would write without writing it; throws ERR_UNDETERMINED_SIZE when the size cannot be predicted.
Added to filesystem export methods to set the zip file comment; the comment option continues to set each entry's comment.
Now accepts a ZipReader instance as well as zip data, allowing callers to retain the reader and access its populated archive metadata after import.
Added to filesystem export methods to report each written entry, complementing onprogress, which reports bytes.
Filesystem export readerOptions now accepts passThrough, writing imported zip entries as-is while entries added to the filesystem are compressed as usual.
Now declared in filesystem API export options, matching the option already forwarded to ZipWriter.
Added to entries and is true for symbolic links. The link target is entry content and is not validated, so it must be checked before use.
Adds a constant exposing the message of the DOMException thrown when an export is aborted on browsers that discard the abort reason.
Adds a method on ZipDirectoryEntry and FS instances that returns a snapshot array of a directory's children, optionally including all descendants.
The hook now receives the text type, filename or comment, as its last argument; hooks declaring fewer parameters keep working.
New EntryError property listing additional failures from concurrent exports; failures raised deeper in the tree are flattened into the list.
New EntryError property identifying the name of the entry that failed during export, relative to the exported entry.
New error constant for invalid filenameValidation values.
New error constant for invalid level values.
New error constant for invalid maxAppendedDataSize values.
New error constant for password values of an invalid type.
New error constant for invalid strictness values.
New EntryError property listing files completely written before an export failure, distinguishing them from files that are missing or empty.
New option in ZipReader and getEntries() that can replace each decoded entry name before validation; the filesystem API inherits it from ZipReaderConstructorOptions.
ZipReader accepts a function to decrypt encrypted central directory records; without it, reading such files throws ERR_ENCRYPTED_CENTRAL_DIRECTORY. zip.js does not implement decryption.
ZipReader exposes the digital signature record written between the central directory and the end of central directory record.
The decryptCentralDirectory function receives encryption metadata in a DirectoryEncryptionInfo object.
ZipWriter#close() accepts a function that receives raw central directory records and returns a digital signature record; zip.js stores the signature but does not compute it.
User-facing error message constants are exported so applications can compare error.message with constants instead of hardcoding messages.
Adds the fallback implementation option used when useCompressionStream is false or the Compression Streams API is unavailable.
Adds a worker factory that takes precedence over workerURI and supports bundler-detectable worker construction.
Exposes a function for custom worker scripts to register alternative compression implementations and an initialization hook.
Adds an entry point with the full API but without embedded web worker code or a deflate implementation.
Adds an entry point exposing initWorker() for writing custom worker scripts.
Entries expose the PKWARE Unix extra field, and Unix extra fields populate date and ownership properties.
Entries expose the Info-ZIP Unix type 1 extra field, and Unix extra fields populate date and ownership properties.
ZipWriter#add() can write extra field records only in the local file header, helping reproduce entries written that way by some tools.
Adds CRC-32 verification in ZipReader and getData(), replacing deprecated checkSignature; also verifies CRC-32 for AES-encrypted entries using AE-1.
Adds the crc32 option for adding entries with passThrough set to true, replacing the deprecated signature option.
Adds the crc32 property on entries, replacing the deprecated signature property; it is undefined when the zip file does not store the CRC-32 value.
Adds an error constant for authentication-code verification failures, replacing the deprecated ERR_INVALID_SIGNATURE constant; the constants share a string value for backward compatibility until the next minor version.
Adds an error constant for CRC-32 verification failures, replacing the deprecated ERR_INVALID_SIGNATURE constant; the constants share a string value for backward compatibility until the next minor version.
New entry point uses external worker and WebAssembly files instead of embedding them, reducing main-bundle payloads and avoiding blob: restrictions under strict Content Security Policies.
New smaller external composition excludes the filesystem API as well as the MIME type table.
New smaller external composition excludes the MIME type table.
New entry point exposes getMimeType() with the full MIME type table for use from any build.
Compression codecs registered with registerCodec now receive the entry's compressionMethod value.
Decompression codecs registered with registerCodec now receive the entry's compressionMethod, rawBitFlag, and uncompressedSize, enabling codecs that cannot be decoded from the stream alone.
Performance 9
With CRC checking enabled, the WebAssembly codec and native DecompressionStream verify CRC-32 while inflating, removing the separate JavaScript-thread pass for those codecs.
The WebAssembly deflate codec reads CRC-32 from the gzip trailer, avoiding a separate JavaScript-thread pass; the native gzip-wrapping route reuses its trailer CRC-32 instead of making a second pass.
The overlap check compares an entry with its two neighbours by offset instead of every earlier entry, avoiding quadratic work when reading archives with the check enabled.
The overlap-only check no longer opens entry data, avoiding unnecessary range requests for whole compressed payloads on HttpRangeReader.
The wrapper copies each produced chunk directly out of module memory rather than through a 64 KB staging buffer allocated per stream.
AES encryption and decryption run faster on every build, with the JavaScript engine unrolling AES rounds and SHA-1 steps and the WebAssembly builds receiving the same kernel treatment.
Built from Chromium's fork of zlib, reading 20% faster and writing 6 to 8% faster with unchanged compressed output.
Reads the source archive once instead of buffering readers with readUint8Array() into a Blob for a second read.
Filesystem exports now keep a running total rather than summing progress across every entry on each tick, removing quadratic progress-tracking cost.
Behavior and default changes 18
For a ReadableStream or reader without a size, uncompressedSize specifies the expected size and affects entry layout; written sizes remain measured, and invalid values throw ERR_INVALID_UNCOMPRESSED_SIZE_OPTION.
The default chunk size increases from 64 KiB to 256 KiB, reducing pipeline messages at the cost of more memory per entry in progress; applications can retain the previous value with configure().
When a file claims a node holding a directory, "keep-last" replaces the directory and drops entries below it, while "keep-first" keeps them and ignores the file.
The builds run the AES engine as a linked kernel and fall back to the JavaScript engine when the module cannot load, including under a Content Security Policy without 'wasm-unsafe-eval'.
Rename splits names into path components and moves the entry accordingly.
An interrupted copy sets hasCorruptedEntries on the writer and keeps offsets of entries written afterward consistent.
Configuration is read when used, so configure() calls made after constructing a reader or writer but before its first operation are now honored.
Accepts a reader that only provides a ReadableStream by buffering the stream once before reading and piping the archive.
Now cancels the constructor's ReadableStream if nothing has been read; it leaves the stream alone after entries are read and does not affect caller-owned Reader instances.
The backend is now in a separate self-registering module; custom builds that do not import it omit web worker plumbing and run codecs inline. Standard entry points remain unaffected.
The embedded JavaScript deflate engine targets ES2019, allowing WebAssembly and native builds to work on Chromium 76 instead of requiring Chromium 80.
Codecs registered with registerCodec() now run inline when a worker cannot import the codec module, so disabling useWebWorkers is no longer needed on affected browsers.
Filesystem API export methods now forward internal file attributes, uid/gid values, and custom extra field records of imported entries.
Entries returned by getEntries() now include the parsed rawLastAccessDate and extraFieldUSDZ properties.
Entries are stored uncompressed instead of failing when zip.js cannot compress data, such as when the Compression Streams API is unavailable and the WebAssembly module cannot load.
The gzip fallback can read AES-encrypted entries and computes the trailer from decompressed data, allowing archives with a corrupted CRC-32 to be read when checkSignature is not set.
The minimum requirements for core builds are lowered to Chrome 80, Node.js 18, and Deno 1.19.
When deflate-raw and the WebAssembly module are unavailable, zip.js wraps raw deflate data in gzip and uses CompressionStream("gzip") and DecompressionStream("gzip"); AES-encrypted and Deflate64 entries are unsupported with this fallback.
Tooling 1
The dynamic import used to load codecs registered with codecURI is excluded from webpack and Vite static analysis, fixing a bundling warning.
Fixes and other changes 142
Reader and writer methods and
init()methods now declare synchronous returns where applicable; useawaitrather than.then()for methods that may return synchronously.Rejects when reading a nested directory fails, so the returned promise settles instead of leaving an unhandled rejection.
When reading an entry fails before its data is written, the destination file stream is aborted and unlocked.
Accepts a bare
WritableStreamas declared; an object exposing awritableproperty continues to work.Concurrent calls now share the same finalization and all resolve to the zip file; a call that throws can still be retried.
The reader checks following central directory records to determine the offset shift, allowing entries to be read when the first record cannot settle the question.
An entry before the start of the zip file after an offset shift is no longer reported with this warning.
The source zip is closed if the filter callback throws.
Entries passed to the filter callback are no longer modified after the callback returns.
The type declaration now accepts the EntryMetaData returned by add().
Passing null options uses the default options instead of causing a TypeError when entries are read.
Copies each kept entry only through the exact end of its data or data descriptor, dropping bytes outside kept entries, including stubs, removed-entry data, and padding.
Preserves the copied entry's general purpose bit flag in the rebuilt central directory, including bits zip.js does not set itself.
Completes every filter call before copying any data.
Reconciles an offset past the file with the directory found before the end record, reporting WARNING_MISMATCHED_CENTRAL_DIRECTORY_OFFSET; strict mode still rejects the archive. Zip64 end records are also searched near the locator and within its allowed range.
Checks the first entry's local file header before shifting entries, preventing a damaged offset from moving entries away from their headers and diagnosing prepended data correctly.
When checkOverlappingEntry is set, compares data descriptor CRC-32 and sizes with the central directory record; checkLocalDirectory determines whether mismatches are errors or warnings. Zeroed local-header fields without the descriptor flag are tolerated.
Does not treat entry data containing the archive extra data signature as an encrypted central directory; the record is only searched for at the start of the central directory.
Keeps the central directory value when present; otherwise the local file header remains the source instead of overwriting a central value after reading entry data.
Empty archives behind prepended data now receive WARNING_PREPENDED_DATA, and their prefix is extracted as for non-empty archives.
Options passed to getEntries reach entries and are applied by entry.getData() after its own options but before ZipReader constructor options.
Options passed to getEntriesGenerator reach entries and are applied by entry.getData() after its own options but before ZipReader constructor options.
A copy failure after bytes have been written marks the ZipWriter as having corrupted entries and marks the error with corruptedEntry; a failure before writing leaves the writer clean.
Parses a central directory record through its end before reporting a missing Zip64 extra field, preserving its other fields; an unresolved local-header offset sentinel no longer causes a false prepended-data report.
The reader now opens archives with a digital signature record when data is prepended, such as a self-extracting stub.
At balanced and tolerant levels, entries with unresolved Zip64 size or offset fields remain listed, while reading their data throws ERR_EXTRAFIELD_ZIP64_NOT_FOUND; other entries stay readable.
The callback now receives the final filename after a valid Unicode Path extra field replaces the decoded central directory name, allowing it to repair that name.
With the unix setting, the type 2 extra field stores uid and gid in the local file header and writes a zero-size tag in the central directory; readers see the ids after reading entry data.
Exports continue to re-emit imported ids in a New Unix extra field unless unixExtraFieldType is set on the export.
add() no longer accesses a reader's readable getter when the reader implements readUint8Array(), avoiding a discarded stream pull and wasted remote range request.
With checkOverlappingEntry set, the reported data descriptor layout is now chosen by matching its sizes to the central directory, using CRC-32 to break ties when available.
With this option set, data descriptors are read using a layout that agrees with the central directory, fixing reads of entries past 4 GB with 4-byte descriptor sizes.
Stray or too-short AES extra fields are ignored and reported as malformed warnings; unencrypted entries use their declared compression method, while encrypted-record conflicts remain errors.
Errors raised in workers preserve the cause's
codeproperty across structured cloning.The encrypted flag now follows the central directory record; tolerant readers decrypt entries even when the local header clears the bit and report the mismatch.
Malformed Zip64 extra fields in local file headers are reported as warnings and entries are read using sizes from the central directory; local-size mismatches still follow strictness rules.
The gzip trailer is now written after the inflater returns, avoiding intermittent ERR_INVALID_CRC32 failures for valid AES entries on older hosts using the fallback route.
When password candidates are exhausted or requestPassword gives up, this error carries the last candidate's error as cause; failures unrelated to a wrong password now reach the caller unchanged.
Aborting a signal during getData() or add() now rejects the operation with the signal reason even if input consumption has finished but output is still in progress.
Export errors now preserve their own cause, such as the codec error behind
ERR_INVALID_COMPRESSED_DATA, instead of replacing it with an object holding the entry.Export errors caused by unreadable entry data now carry the entry as
entry.An empty
Uint8Arraynow means no raw password, like an empty password string, avoiding a read that waits forever or writing an entry that cannot be read back.Aborted codec reads and writes now release WebAssembly buffers and zlib state in browsers, preventing heap exhaustion and later allocation failures.
Custom Readers whose readUint8Array returns a Node.js Buffer can read archives again; the end-of-central-directory record is no longer read from the wrong bytes.
Queued requests run in-process when all worker slots are busy, and terminateWorkers() resolves only after those requests finish.
Every call made while a codec runs is resolved when the codec ends; a later call no longer replaces an earlier call's resolver and leaves its promise unsettled.
HttpReader and HttpRangeReader fetch the whole tail needed for the end-of-central-directory scan with the size request, allowing archives with comments to list entries in one request; mismatched response ranges are no longer treated as requested ranges.
For two directory records claiming the same node, "keep-last" replaces the held record and keeps entries already imported below it; a record for an implicitly created node is not a collision.
Now waits for codecs running without a web worker, preventing WebAssembly builds from resetting the module while a codec is running.
Folders and empty entries no longer carry a data descriptor, making pass-through re-exports byte-identical to their source.
With a codec running in a worker, bytes written by a failed entry are counted after the aborted pipe settles, so following entries are recorded at the correct offsets and the archive is not malformed.
The caller's abort or cancellation reason now reaches the caller unchanged with or without a worker; custom error classes and attached properties are preserved, and the reason is annotated with outputSize when possible.
Rejection reasons crossing a codec worker retain their class and value; DOMException remains a DOMException, and non-object reasons return unchanged.
Entries added after a mid-write failure are recorded at the right offsets regardless of the failure reason, avoiding archives that strict readers reject.
Reasons that cannot carry an outputSize annotation no longer fail during annotation, allowing the promise to reject and preventing terminateWorkers() from hanging.
Failures on the main thread during worker-protocol codec tasks now carry outputSize, so the writer advances by the bytes that actually reached it.
No longer causes FileEntry#arrayBuffer() and ZipReaderStream to hang forever.
readerOptions.passThrough is typed as boolean rather than boolean | "compressed", matching the filesystem API's runtime behavior.
Copies made with entry now preserve the source entry's deflate level bits, language encoding flag, and Unix extra field type.
BlobReader now falls back to slice() and arrayBuffer() when its Blob-like source does not expose stream().
A signal already aborted when getData() is called now rejects the call with signal.reason, or an AbortError with message ERR_ABORTED when no reason exists.
Chunks now expose EntryMetaData#warnings and EntryMetaData#localDirectory deposited on their entry while its data is read.
A signal already aborted when add() is called now rejects the call with signal.reason, or an AbortError with message ERR_ABORTED when no reason exists; rejection happens before a buffered entry’s temporary stream is created.
The entry returned by ZipWriter#add() now reports the date the archive actually stores, including extended or NTFS timestamps.
The central directory drops ZIP64 layout when entry sizes fit in 32 bits, and archives retaining ZIP64 layout end with a ZIP64 end of central directory record, fixing compatibility with macOS extractors.
Size prediction no longer fails for filesystems with implicit directories; explicit directory entries with children still throw ERR_UNDETERMINED_SIZE.
Concurrent add() calls compress concurrently again: the first entry is written directly to the file and the others are buffered.
A Reader that declares its size no longer causes add() to read forever when it returns the requested number of bytes.
The stream advances by the number of bytes actually returned, so short chunks in the middle of data no longer cause the rest of a chunk to be skipped.
The compress direction checks the codec status before using the produced-byte count, preventing failed deflate operations from silently dropping the rest of an entry.
Failures inside the WebAssembly codec are reported as the underlying error instead of surfacing as RangeError: offset is out of bounds.
No longer refused when a match at least as long as the WebAssembly codec's 64KB output buffer starts on its boundary, preventing dropped chunk data and decode failures.
No longer corrupts data when a match wraps around the end of the sliding window and ends inside it, preventing incorrect decompressed bytes.
A failed import rolls back entries created before the error and restores the ZipFS content that existed before the import.
ZipFS#find no longer throws a TypeError when a path component is a file entry rather than a directory.
Renaming an entry to its existing name is no longer rejected as a collision with itself.
Replace methods update entry size, and replaceReadable reports an undetermined size instead of an unsupported prediction.
Replace methods clear an imported entry's pass-through state because the bytes copied verbatim are no longer present.
Fixes decoding names of entries not marked as UTF-8 when the build is parsed as a non-UTF-8 charset.
Size prediction now accounts for the write order and alignment padding when a flat tree mixes files and directories exported with the usdz option.
Size prediction no longer throws ERR_UNDETERMINED_SIZE for an empty archive or one containing a single entry when write order is not guaranteed.
The option now keeps entries in the physical order of their add() calls, including when readers initialize at different speeds.
The build now exports the full core API, including configure(), registerCodec(), reader and writer classes, and constants.
Unclaimed bytes between the last central directory record and the end record are detected; strictness rejects them at the strict level and lower levels report a warning.
Reading archives with a multiple of 65,536 entries and no zip64 record now returns all entries by detecting count wrap and walking central directory records, except when strictness checks reject ambiguous archives.
Duplicate filenames are detected before an entry waits for a worker slot, preventing concurrent add() calls with the same name from both being accepted when the worker pool is saturated.
ZipCrypto entries copied with passThrough can be read back with their password; the raw date is preserved and dataDescriptor is not forced for pass-through ZipCrypto data.
The spanning signature for split zip files is written while holding the writer lock, avoiding failures or misplaced signatures with buffered or interleaved writes.
End-of-central-directory records now declare the number of entries stored on the last disk rather than the total; the count is 0 when the record starts on a fresh disk.
These extra fields are applied only when their version is 1, as required by the zip specification.
The zip64 decision for a split-archive record now accounts for actual record and comment length when predicting disk rollover near 65,535 disks.
When only uid or gid is set, the missing id is now stored as 0 rather than declared with a zero-length field.
Rebuilt central directory records now preserve source entries’ zip64 layout, avoiding duplicate zip64 fields and matching direct-write output.
The writer now closes a split-archive disk before writing the signature record, keeping the record within a single segment.
ZipReader now finds the digital signature when a split archive's central directory starts on an earlier disk than its end of central directory record.
The size prediction now accounts for the offset option when determining zip64 fields, avoiding underestimates for offsets at or above 4GB.
The central directory now accounts for the writer's initial offset when pointing to prepended entries, allowing those entries to be read back.
The compression method is no longer truncated to one byte, so encrypted entries using registered methods above 255 announce the correct method and readers select the correct codec.
Reading encrypted central directories now trusts the declared offset when the encryption header declares the directory size or the bytes at the offset look encrypted.
Reading entries with local file headers masked by PKWARE strong encryption no longer throws ERR_AMBIGUOUS_ARCHIVE.
Published bundles no longer set the level bits on entries written with the default compression level, matching archives written from the sources.
The extensible data sector is now included in the record length, correcting the computed central directory end and derived offsets.
The digital signature is now defined for archives whose central directory is encrypted.
Split zip file signatures PK\x07\x08 and PK00 are no longer reported as prepended data, preventing false ambiguity errors in strictness and checkAmbiguity modes.
No longer copies the prepended archive's central directory as dead bytes; only the data region is copied before entries are rewritten.
An empty Info-ZIP Unix type 2 extra field no longer prevents IDs from being read from a neighboring Info-ZIP New Unix extra field.
Validates that the globalComment option is a Uint8Array, using the same check as ZipWriter#close().
Unix group IDs stored only in the local file header are populated when entry data is read and are available on localDirectory.
EntryMetaData now populates rawCreationDate from the NTFS extra field.
EntryMetaData now populates rawLastAccessDate from the NTFS extra field.
Unix user IDs stored only in the local file header are populated when entry data is read and are available on localDirectory.
The entry returned by ZipWriter#add() now reports the upper half of the written externalFileAttributes, including the selected Unix mode and file type.
A worker that fails to load now falls back to the main scope, including when its error arrives before the pool sends its first message.
Returned entries now include rawBitFlag, filenameLength, extraFieldLength, and unixExternalUpper, which were previously dropped.
Returned entries now define the same members as ZipReader#getEntries() entries, including boolean properties and deprecated attribute aliases.
Now applies entry options to directories it creates as well as to files.
Now stores text size in bytes rather than UTF-16 code units, correcting getExportedSize for non-ASCII text.
Filesystem reader options now map this setting to checkOverlappingEntry, so the overlap check runs while content is still read.
Now counts bytes written, fixing progress that previously used compressed entry sizes against the archive's uncompressed size and omitted non-imported entries.
The deprecated option works again as an alias for externalFileAttributes.
Now honors the requested MIME type, including when a filesystem entry contains a Blob.
Dates are now read as signed timestamps, correcting dates before 1970 that were previously interpreted as dates in 2106.
The deprecated option works again as an alias for internalFileAttributes.
Progress is now reported for filesystem entries not imported from a zip file.
Now ignored for entries with no content, allowing a ZipWriter configured for pass-through to write directories.
Reading a data range no longer emits empty chunks, including the extra read previously issued for entries of unknown size.
Writing an entry with unixMode now stamps the file type in external file attributes unless the mode already carries a type.
Writing names ending with a slash no longer combines the file type with the type already in unixMode, which could corrupt directory or symbolic-link types.
When concurrent export fails on browsers that discard abort reasons, the original failure is reported instead of the sibling-entry cancellation.
Aborting through the signal option on browsers that discard abort reasons now rejects with a DOMException named AbortError instead of undefined or a plain Error.
With concurrent set to true, the export now collects every failure instead of reporting only the first one.
When a module worker cannot start, zip.js now retries an external worker script as a classic worker instead of silently falling back to inline workers.
Temporary file name generation now works when crypto.randomUUID is unavailable.
Reading and writing data now works with polyfilled global stream classes, including when the environment lacks TransformStream.
AES-encrypted entries with passThrough and a provided crc32 are written as AE-1 with CRC-32 in the headers; copying a read AE-1 entry no longer loses its CRC-32.
The last modification date is truncated to whole seconds before odd seconds are rounded up, so sub-second fractions no longer round the DOS date up.
Dates outside the NTFS extra field's representable range are clamped to its bounds instead of silently overflowing to an arbitrary value.
The gzip fallback now rejects archives with an invalid uncompressed size in the central directory using ERR_INVALID_UNCOMPRESSED_SIZE, rather than a misleading error.
A WebAssembly module load failure now reports an explicit "WASM module not loaded" error with the original error as cause, rather than a later codec TypeError.
A failed WebAssembly module load is retried on the next use instead of being cached for the whole session.
Streams passed to zip.js are normalized across Streams API implementations, fixing TypeError exceptions and hangs when global stream classes are overridden by a polyfill.
Reading these files no longer depends on Array.prototype.at, avoiding the higher minimum browser versions previously required.