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

@eazip/react

v0.1.0

Published

React hooks and a download tray for ZIP files and remote URLs in browser apps, with optional Eazip Cloud

Readme

@eazip/react

Zip downloads for React apps — one hook, one component.

import { EazipTray, useEazip } from '@eazip/react';

function Gallery({ selectedFiles }: { selectedFiles: File[] }) {
  const zip = useEazip();
  return (
    <>
      <button onClick={() => zip.download({ files: selectedFiles })}>Download as ZIP</button>
      <EazipTray />
    </>
  );
}

zip.download(...) is fire & forget: it kicks off the export and returns immediately. <EazipTray /> takes it from there — an inline floating tray that shows progress, completion, partial results, failures, and expiry, then gets out of the way. No CSS import, no provider, no configuration required.

Install

npm install @eazip/react

Requires React 18+. Files are zipped in the browser by default (via @eazip/core) — nothing is uploaded.

useEazip()

const zip = useEazip();

zip.download(options);         // start an export, returns a task id
zip.task;                      // current task (state, progress, zips, errors) or null
zip.isBusy;                    // true while an export is processing
zip.cancel();                  // abort the running export
zip.retry();                   // re-run the last export
zip.dismiss();                 // clear the tray
zip.downloadZip(taskId, i);    // download one zip of a multi-zip result
zip.downloadAll();             // download every zip

files accepts File[], a FileList, URL strings, or @eazip/core source objects:

zip.download({
  files: [
    { file: blob, filename: 'notes.txt' },
    { url: 'https://assets.example.com/hero.png' },
  ],
  zipName: 'assets.zip',
});

Errors never reject the call — they land on zip.task and render as a calm, recoverable state in the tray.

<EazipTray />

| Prop | Default | Description | | --- | --- | --- | | placement | 'corner' | 'corner' (bottom-right), 'bar' (bottom-center), 'anchored' (top-right) | | theme | 'auto' | 'light', 'dark', or follow prefers-color-scheme | | accent | '#3056d3' | accent color for progress and highlights | | autoDownload | true | start the download automatically when the zip is ready | | autoHideMs | 20000 | auto-dismiss delay after a started download; 0 disables | | locale | 'en' | 'en' or 'ja' | | messages | — | partial override of any tray copy | | className | — | extra class on the tray root | | zIndex | 9999 | stacking context for the tray | | offset | — | { x, y } pixel shift from the default anchor | | container | document.body | portal target | | onStateChange | — | called on task state transitions |

The tray is invisible until a download starts, expands inline (never a modal), and stays until the file is actually downloaded. It announces state changes politely (role="status"), supports keyboard use, and respects prefers-reduced-motion.

Configuration with EazipProvider (optional)

Everything works without a provider. Add one to share configuration:

import { EazipProvider } from '@eazip/react';

<EazipProvider
  config={{
    strategy: 'cloud',
    publicKey: 'pk_ez_...',
    defaults: { zipName: 'export.zip' },
  }}
>
  <App />
</EazipProvider>;

Large downloads: the cloud strategy

Browser-side zipping is great for a handful of files, but it holds everything in memory and dies with the tab. For hundreds or thousands of files — or multi-gigabyte exports — switch the same API to Eazip Cloud Public Sessions:

zip.download({ strategy: 'cloud', publicKey: 'pk_ez_...', files: urls });

For very large exports, your backend can create the Public Session so the browser never receives the full URL list:

zip.download({
  strategy: 'cloud',
  zipName: 'export.zip',
  filesTotal: 50_000,
  createSession: async ({ signal, zipName, mode }) => {
    const response = await fetch('/api/exports/123/eazip-session', {
      method: 'POST',
      credentials: 'include',
      headers: { 'Content-Type': 'application/json' },
      signal,
      body: JSON.stringify({ zipName, mode }),
    });
    if (!response.ok) throw new Error('Failed to create Eazip session');
    return response.json(); // { sessionId, clientSecret, apiBaseUrl? }
  },
});

With the cloud strategy the zip is built server-side and the tray gains superpowers:

  • exports survive a page reload — the tray restores itself and resumes progress
  • download links stay valid for 24 hours (the tray shows a calm expiry state after)
  • huge exports split into multiple zips automatically, listed in the tray

Create a Public App to get a public key. Cloud sources must be URLs reachable by the Eazip API. Cloud zips default to stream mode (generated on demand at download time — ready sooner); pass mode: 'stored' to keep a built archive instead.

Error handling

@eazip/react re-exports the @eazip/core error classes and types, so advanced flows (Turnstile challenges, custom session handling) need only one import:

import { isEazipError, EazipChallengeRequiredError } from '@eazip/react';

Notes

  • ESM only, React 18+, works in Next.js App Router out of the box ('use client' is baked in).
  • State is kept in a tiny external store; cloud exports persist to localStorage (persist: false opts out).
  • Stable releases remain pre-1.0.0; see the repository changelog for any breaking 0.x changes.

License

MIT