npm @zip.js/zip.js 2.25.0

one hour ago

What's Changed in v2.25.0

Bug fixes

  • Concurrent ZipWriter#close() calls now share the same finalization and all resolve to the zip file. Previously the second call rejected with a locked-stream TypeError from getWriter() while the first one succeeded. A call that threw, e.g. on an invalid comment, can still be retried
  • ZipDirectoryEntry#exportFileSystemHandle() now aborts and unlocks the destination file stream when reading an entry fails before its data is written, e.g. on a wrong password or a corrupted entry. Previously the stream opened for that entry was left open and locked
  • ZipDirectoryEntry#addFileSystemEntry() now rejects when reading a nested directory fails, e.g. on a permission error. Previously the error surfaced as an unhandled rejection and the returned promise never settled
  • ZipFileEntry#getData() now accepts a bare WritableStream, as declared, instead of throwing "Cannot read properties of undefined (reading 'getWriter')"; an object exposing a writable property keeps working

Type declarations

  • Reader#readUint8Array(), Writer#writeUint8Array(), Writer#getData() and the init() methods now declare that they may return synchronously, which is what Uint8ArrayReader, Uint8ArrayWriter and Data64URIWriter do. A custom reader or writer implemented synchronously now type-checks, and calling .then() on these methods is no longer accepted by TypeScript since it fails at runtime on the synchronous classes: use await instead. The classes implemented asynchronously, e.g. TextWriter and BlobWriter, keep their promise-only declarations
  • ZipWriterStream#transform() and ZipWriterStream#writable() are now typed on Uint8Array chunks on both sides and no longer take a type parameter: the readable side of transform() is the zipped stream, never the type of the input chunks

Documentation

  • New README section "Reading untrusted zip files", with remarks on FileEntry#getData() and Uint8ArrayWriter: the declared sizes are not verified before an entry is read, so check entry.uncompressedSize against your limit before extracting an entry from an untrusted source. Uint8ArrayWriter allocates its buffer from the declared size, capped at 1032 times compressedSize
  • msDosCompatible: Info-ZIP unzip builds without Unicode support, e.g. the one shipped with macOS, fail to extract entries with non-ASCII names when the MS-DOS platform is declared, whatever the language encoding flag says
  • The ZipWriterStream examples now encode their strings with a TextEncoderStream: the streams piped into the instance must carry Uint8Array chunks
  • A lazily-read Blob from fs.openAsBlob() or Bun.file() must be wrapped in a BlobReader; the two passages saying it could be passed directly to ZipReader were wrong
  • passThrough: "compressed": two encrypted entries holding the same content read identical only when the content was compressed identically; different compressed data does not prove different content
  • useUnicodeFileNames: false: ZipReader decodes the resulting UTF-8 names correctly since it detects valid UTF-8 when the flag is clear; the readers that trust the flag, e.g. Python zipfile and Info-ZIP unzip, do not
  • ZipDirectoryEntry#exportWritable() resolves to the WritableStream instance, not to a Uint8Array as its description said
  • The default appended data size of the "balanced" strictness is 65535 bytes, the opening examples of the API documentation import the npm package @zip.js/zip.js rather than the JSR name, and smaller wording fixes

Build and CI

  • The Chrome 76, Chrome 87 and Firefox 102 test jobs run on windows-2022, because those browsers no longer start on the current windows-latest (Windows Server 2025) image

Full Changelog: v2.24.0...v2.25.0

Co-Authored-By: Claude Fable 5.1 noreply@anthropic.com

Don't miss a new zip.js release

NewReleases is sending notifications on new releases.