npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@diegoaltoworks/zipper

v1.0.6

Published

An isomorphic TypeScript package for downloading and zipping files in browser and Node.js

Downloads

44

Readme

Zipper

An isomorphic TypeScript package for downloading multiple files and combining them into a ZIP archive. Works in both browser and Node.js environments!

By Diego Alto | GitHub | NPM | Documentation | Live Demo

Features

  • Isomorphic: Works in both browser and Node.js environments
  • 📦 TypeScript Support: Full type definitions included
  • 🚀 Concurrent Downloads: Download multiple files in parallel
  • 📊 Progress Tracking: Built-in progress callbacks
  • 🛡️ Error Handling: Robust error handling with optional error callbacks
  • 🌐 Modern Dependencies: Uses standard npm packages (JSZip, File-Saver)
  • 🔧 Flexible: Continue on errors or fail fast
  • ⚙️ Customizable: Custom fetch options, timeouts, and ZIP filename

Installation

npm install @diegoaltoworks/zipper

That's it! File-saver is included automatically for browser support.

Environment Support

  • Browser: Auto-triggers ZIP download
  • Node.js: Returns Buffer for server-side use
  • Next.js: Works in both Client Components and API Routes
  • Express: Perfect for server-side ZIP generation

Usage

Browser Example (Auto-Download)

import { downloadZipFile, type FileInput } from '@diegoaltoworks/zipper';

const files: FileInput[] = [
  { url: '/api/documents/report1.pdf', name: 'Report 1.pdf' },
  { url: '/api/documents/report2.pdf', name: 'Report 2.pdf' },
];

await downloadZipFile(files, { zipFilename: 'reports.zip' });
// ✓ Triggers browser download automatically

Node.js Example (Get Buffer)

import { createZipFile } from '@diegoaltoworks/zipper';
import { writeFile } from 'fs/promises';

const files = [
  { url: 'https://example.com/file1.pdf', name: 'Document A.pdf' },
  { url: 'https://example.com/file2.pdf', name: 'Document B.pdf' }
];

const buffer = await createZipFile(files);
// ✓ Returns Buffer in Node.js

await writeFile('output.zip', buffer);

Alternative: Use Default Export

import zipper from '@diegoaltoworks/zipper';

// Same as downloadZipFile
await zipper(files, { zipFilename: 'download.zip' });

Next.js API Route Example

// app/api/download/route.ts
import { NextResponse } from 'next/server';
import { createZipFile } from '@diegoaltoworks/zipper';

export async function GET() {
  const buffer = await createZipFile([
    { url: 'https://example.com/file1.pdf', name: 'file1.pdf' },
    { url: 'https://example.com/file2.pdf', name: 'file2.pdf' }
  ]);

  return new NextResponse(buffer, {
    headers: {
      'Content-Type': 'application/zip',
      'Content-Disposition': 'attachment; filename="download.zip"'
    }
  });
}

With Options

import { downloadZipFile, type FileInput, type DownloadOptions } from '@diegoaltoworks/zipper';

const files: FileInput[] = [
  { url: 'https://example.com/file1.pdf', name: 'Document A.pdf' },
  { url: 'https://example.com/file2.pdf', name: 'Document B.pdf' }
];

const options: DownloadOptions = {
  zipFilename: 'my-documents.zip',

  onProgress: (current, total) => {
    console.log(`Downloaded ${current} of ${total} files`);
    // Update your UI progress indicator here
  },

  onError: (error, file) => {
    console.error(`Failed to download ${file.name}:`, error.message);
    // Handle individual file errors
  },

  continueOnError: true, // Continue downloading even if some files fail

  timeout: 30000, // 30 second timeout per file

  fetchOptions: {
    headers: {
      'Authorization': 'Bearer your-token-here'
    }
  }
};

await downloadZipFile(files, options);

React Example

import { useState } from 'react';
import { downloadZipFile, type FileInput } from '@diegoaltoworks/zipper';

function DownloadButton() {
  const [progress, setProgress] = useState('');
  const [isDownloading, setIsDownloading] = useState(false);

  const handleDownload = async () => {
    setIsDownloading(true);

    const files: FileInput[] = [
      { url: '/api/file1.pdf', name: 'file1.pdf' },
      { url: '/api/file2.pdf', name: 'file2.pdf' }
    ];

    try {
      await downloadZipFile(files, {
        zipFilename: 'files.zip',
        onProgress: (current, total) => {
          setProgress(`${current}/${total}`);
        }
      });

      setProgress('Complete!');
    } catch (error) {
      console.error('Download failed:', error);
    } finally {
      setIsDownloading(false);
    }
  };

  return (
    <div>
      <button onClick={handleDownload} disabled={isDownloading}>
        {isDownloading ? `Downloading... ${progress}` : 'Download ZIP'}
      </button>
    </div>
  );
}

API Reference

createZipFile(files, options?)

Downloads multiple files and creates a ZIP archive (works in both browser and Node.js).

Parameters

  • files FileInput[] - Array of files to download

    • url string - The URL to fetch the file from
    • name string - The filename to use in the ZIP archive
  • options? DownloadOptions - Optional configuration

    • onProgress? (current: number, total: number) => void - Progress callback
    • onError? (error: Error, file: FileInput) => void - Error callback
    • continueOnError? boolean - Continue on errors (default: true)
    • timeout? number - Request timeout in milliseconds (default: 30000)
    • fetchOptions? RequestInit - Additional fetch options (headers, etc.)

Returns

  • Promise<Buffer> in Node.js
  • Promise<Blob> in browser

Throws

  • Throws an error if no files are provided
  • Throws an error if all downloads fail
  • Throws an error if continueOnError is false and any download fails

downloadZipFile(files, options?)

Downloads multiple files, creates a ZIP, and triggers browser download.

Parameters

  • files FileInput[] - Array of files to download
  • options? DownloadOptions - Optional configuration
    • zipFilename? string - Name of the ZIP file (default: 'download.zip')
    • All options from createZipFile are also supported

Returns

Promise<void> - Resolves when download is triggered

Throws

  • Same errors as createZipFile
  • Throws an error if browser is not supported

Type Definitions

interface FileInput {
  url: string;
  name: string;
}

interface DownloadOptions {
  zipFilename?: string;
  onProgress?: (current: number, total: number) => void;
  onError?: (error: Error, file: FileInput) => void;
  continueOnError?: boolean;
  timeout?: number;
  fetchOptions?: RequestInit;
}

Demo & Documentation

Live Demo Application

Try the full-stack demo application at zipper-demo.vercel.app featuring:

  • Interactive file selection and downloads
  • Server-side ZIP generation with Next.js API routes
  • Real-time progress tracking
  • Error handling demonstrations
  • Mobile-responsive UI

Source code: github.com/diegoaltoworks/zipper-demo

Interactive Documentation

Browse examples and code samples at diegoaltoworks.github.io/zipper

The documentation site (docs/ directory) includes:

  • Browser usage examples with live demos
  • Server-side usage patterns
  • Code playground for experimentation
  • Multiple file type demonstrations
  • 100+ test files for testing (PDFs, PNGs, text files)

To run the docs locally:

cd docs
npm install
npm run dev

Development

Setup

npm install

Build

npm run build

Outputs ESM and CJS modules to dist/:

  • dist/index.esm.js - ES module
  • dist/index.cjs.js - CommonJS module
  • dist/index.d.ts - TypeScript definitions

Test

npm test              # Run tests
npm run test:watch    # Watch mode
npm run test:coverage # Coverage report

Lint

npm run lint          # Check for issues
npm run lint:fix      # Auto-fix issues
npm run format        # Format with Prettier

Type Check

npm run type-check

Browser Compatibility

This package works in all modern browsers that support:

  • Fetch API
  • Blob
  • Promise
  • AbortController

For older browser support, you may need polyfills.

License

MIT

Credits

Built with:

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.