or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-unzip

Streaming cross-platform unzip library for Node.js compatible with fstream and fs.ReadStream

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/unzip@0.1.x

To install, run

npx @tessl/cli install tessl/npm-unzip@0.1.0

index.mddocs/

Unzip

Unzip is a streaming cross-platform unzip library for Node.js that provides simple APIs for parsing and extracting zip files. It offers compatibility with fstream and fs.ReadStream interfaces without compiled dependencies, using Node.js's built-in zlib support for inflation.

Package Information

  • Package Name: unzip
  • Package Type: npm
  • Language: JavaScript (Node.js)
  • Installation: npm install unzip

Core Imports

const unzip = require('unzip');
// Or destructured
const { Parse, Extract } = require('unzip');

ES6 modules (if supported by your Node.js version):

import unzip from 'unzip';
import { Parse, Extract } from 'unzip';

Basic Usage

Extract to Directory

const fs = require('fs');
const unzip = require('unzip');

// Extract entire zip archive to a directory
fs.createReadStream('path/to/archive.zip')
  .pipe(unzip.Extract({ path: 'output/path' }));

Parse and Process Entries

const fs = require('fs');
const unzip = require('unzip');

// Parse zip file and process individual entries
fs.createReadStream('path/to/archive.zip')
  .pipe(unzip.Parse())
  .on('entry', function (entry) {
    const fileName = entry.path;
    const type = entry.type; // 'Directory' or 'File'
    const size = entry.size;
    
    if (fileName === "target-file.txt") {
      entry.pipe(fs.createWriteStream('output.txt'));
    } else {
      entry.autodrain(); // Important: drain unused entries
    }
  });

Architecture

Unzip is built around three core components:

  • Parse: Transform stream that parses zip archive structure and emits entry events
  • Extract: Writable stream that extracts entire archives to directories using fstream
  • Entry: PassThrough stream representing individual zip entries (files/directories)

The library uses a streaming approach for memory efficiency, processing zip files without loading entire contents into memory.

Capabilities

Zip Archive Parsing

Parse zip files and access individual entries with streaming support.

/**
 * Creates a streaming zip parser (can be called with or without 'new')
 * @param {Object} opts - Configuration options
 * @param {boolean} opts.verbose - Enable verbose logging (default: false)
 * @returns {Parse} Transform stream for parsing zip archives
 */
function Parse(opts);

/**
 * Factory method equivalent to new Parse(opts) - preferred way to create instances
 * @param {Object} opts - Configuration options
 * @returns {Parse} Transform stream instance
 */
Parse.create = function(opts);

/**
 * Enhanced pipe method with fstream compatibility
 * Automatically calls dest.add(entry) for each entry if destination has an add method
 * @param {Object} dest - Destination stream or fstream Writer
 * @param {Object} opts - Standard pipe options
 * @returns {Object} The destination stream
 */
Parse.prototype.pipe = function(dest, opts);

/**
 * Enhanced event listener registration that tracks 'entry' listeners
 * When entry listeners are added, the parser will emit entry events and provide entry streams
 * @param {string} type - Event type ('entry', 'error', 'close', etc.)
 * @param {Function} listener - Event handler function
 * @returns {Parse} This Parse instance for chaining
 */
Parse.prototype.addListener = function(type, listener);
Parse.prototype.on = function(type, listener); // Alias for addListener

The Parse stream emits the following events:

  • 'entry' - Emitted for each zip entry (file/directory)
  • 'error' - Emitted on parsing errors
  • 'close' - Emitted when parsing completes
  • 'end' - Emitted when stream ends
  • 'finish' - Emitted when stream finishes

Directory Extraction

Extract entire zip archives to filesystem directories.

/**
 * Creates a writable stream for extracting zip archives to directories (can be called with or without 'new')
 * @param {Object} opts - Configuration options
 * @param {string} opts.path - Target extraction directory (required)
 * @param {boolean} opts.verbose - Enable verbose logging (default: false)
 * @returns {Extract} Writable stream for zip extraction
 */
function Extract(opts);

The Extract stream emits the following events:

  • 'error' - Emitted on extraction errors
  • 'close' - Emitted when extraction completes
  • 'pipe' - Emitted when piped to
  • 'finish' - Emitted when stream finishes

Zip Entry Processing

Individual zip entries are represented as Entry streams.

/**
 * PassThrough stream representing a zip entry
 * Note: Entry instances are created internally by Parse, not directly by users
 * @constructor
 */
function Entry();

/**
 * Automatically drain entry content to prevent memory issues
 * Call this for entries you don't intend to process
 */
Entry.prototype.autodrain = function();

Entry objects have the following properties (set by Parse during processing):

  • path (string) - Entry file path within the zip archive
  • type (string) - Entry type: 'File' or 'Directory' (determined by compressed size and path ending)
  • size (number) - Entry uncompressed size (available after processing, may be undefined during parsing)
  • props (object) - Additional entry properties including a copy of the path

Types

/**
 * Parse stream class (extends Node.js Transform stream)
 */
class Parse {
  constructor(opts);
  
  // Enhanced pipe method with automatic fstream compatibility
  // Calls dest.add(entry) for each entry if destination has add method
  pipe(dest, opts);
  
  // Enhanced event listener methods that track 'entry' listeners
  // When entry listeners are registered, parser provides entry streams
  addListener(type, listener);
  on(type, listener); // Alias for addListener
  
  // Standard Transform stream methods available
  write(chunk, encoding, callback);
  end();
  // ... other Transform stream methods
}

/**
 * Extract stream class (extends Node.js Writable stream)
 */
class Extract {
  constructor(opts);
  
  // Standard Writable stream methods available
  write(chunk, encoding, callback);
  end();
  // ... other Writable stream methods
}

/**
 * Entry stream class (extends Node.js PassThrough stream)
 */
class Entry {
  constructor();
  autodrain();
  
  // Properties set by Parse during zip processing
  path: string;
  type: 'File' | 'Directory';
  size: number;
  props: object;
  
  // Standard PassThrough stream methods available
  pipe(destination, options);
  read(size);
  write(chunk, encoding, callback);
  // ... other stream methods
}

/**
 * Configuration options for Parse
 */
interface ParseOptions {
  verbose?: boolean;
}

/**
 * Configuration options for Extract
 */
interface ExtractOptions {
  path: string;
  verbose?: boolean;
}

Error Handling

The library emits errors for various conditions:

  • Invalid zip signatures: Throws errors with signature details (e.g., "invalid signature: 0x12345678")
  • Stream errors: Propagated through 'error' events on Parse and Extract streams
  • Compression errors: zlib inflation errors are propagated through the error event chain
const parser = unzip.Parse();
parser.on('error', function(err) {
  console.error('Parse error:', err.message);
});

const extractor = unzip.Extract({ path: './output' });
extractor.on('error', function(err) {
  console.error('Extract error:', err.message);
});

Advanced Usage

Pipe to fstream Writer

const fs = require('fs');
const fstream = require('fstream');
const unzip = require('unzip');

const readStream = fs.createReadStream('archive.zip');
const writeStream = fstream.Writer('output/path');

readStream
  .pipe(unzip.Parse())
  .pipe(writeStream);

Selective File Extraction

fs.createReadStream('archive.zip')
  .pipe(unzip.Parse())
  .on('entry', function (entry) {
    if (entry.path.endsWith('.txt')) {
      // Extract only text files
      entry.pipe(fs.createWriteStream(`output/${entry.path}`));
    } else {
      // Skip other files
      entry.autodrain();
    }
  });

Memory Management

Important: Always call entry.autodrain() for entries you don't process to prevent memory leaks:

fs.createReadStream('large-archive.zip')
  .pipe(unzip.Parse())
  .on('entry', function (entry) {
    if (entry.type === 'Directory') {
      // Skip directories
      entry.autodrain();
    } else if (entry.size > 1000000) {
      // Skip large files
      entry.autodrain();
    } else {
      // Process small files
      entry.pipe(fs.createWriteStream(entry.path));
    }
  });

Enhanced Parse Class Features

Automatic fstream Compatibility

The Parse class automatically detects when piped to fstream destinations and calls dest.add(entry) for each zip entry:

// Enhanced pipe method detects fstream Writers and calls add() automatically
fs.createReadStream("archive.zip")
  .pipe(unzip.Parse())
  .pipe(fstream.Writer("output/path")); // Automatically calls writeStream.add(entry)

Entry Listener Optimization

The Parse class optimizes behavior based on whether entry listeners are registered:

// Without entry listeners - entries are not processed into streams (memory efficient)
fs.createReadStream("archive.zip")
  .pipe(unzip.Parse())
  .pipe(fstream.Writer("output"));

// With entry listeners - entries become readable streams
fs.createReadStream("archive.zip")
  .pipe(unzip.Parse())
  .on("entry", function(entry) {
    // Entry is now a readable stream with available properties
    console.log("Processing:", entry.path, "Type:", entry.type);
    if (entry.size) console.log("Size:", entry.size);
    entry.autodrain(); // Important: drain if not processing
  });