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

@stack-upload-orchestrator/node

v0.1.2

Published

Node.js upload handler — multipart parsing, validation, chunked uploads, Express adapter

Readme

@stack-upload-orchestrator/node

Node.js upload handler — multipart parsing, validation, chunked uploads, and an Express adapter.

Installation

npm install @stack-upload-orchestrator/node

Quick start

import http from 'node:http';
import { handleUpload } from '@stack-upload-orchestrator/node';
import { LocalStorage } from '@stack-upload-orchestrator/storage-local';

const storage = new LocalStorage({ destination: './uploads' });

http.createServer(async (req, res) => {
  if (req.method === 'POST' && req.url === '/upload') {
    const files = await handleUpload(req, {
      storage,
      validation: { maxFileSize: '10MB', allowedTypes: ['image/*'] },
    });
    res.end(JSON.stringify({ files }));
  }
}).listen(3000);

handleUpload

handleUpload(req: IncomingMessage, options: UploadHandlerOptions): Promise<UploadResult[]>

Parses a multipart request using busboy, validates each file, streams it through the storage adapter, and resolves with the results.

UploadHandlerOptions

| Option | Type | Description | |---|---|---| | storage | NodeStorageAdapter | Where to persist files (required) | | validation | ValidationOptions | Size, type, extension, and count rules | | onBeforeUpload | (meta) => Promise<void> | Hook called before each file is stored. Throw to reject. | | onUploadComplete | (result, meta) => Promise<void> | Hook called after each file is stored successfully. | | onError | (error, meta) => void | Called when a single file fails. |

Express adapter

import express from 'express';
import { expressUpload } from '@stack-upload-orchestrator/node';
import { LocalStorage } from '@stack-upload-orchestrator/storage-local';

const app = express();
const storage = new LocalStorage({ destination: './uploads' });

app.post(
  '/upload',
  expressUpload({
    storage,
    validation: { maxFileSize: '50MB' },
  }),
  (req, res) => {
    res.json({ files: req.uploadedFiles });
  },
);

The middleware attaches results to req.uploadedFiles: UploadResult[].

Chunked uploads

For large files, split the upload into chunks on the client and reassemble on the server.

Server

import { handleChunkUpload, MemoryChunkStore } from '@stack-upload-orchestrator/node';
import { LocalStorage } from '@stack-upload-orchestrator/storage-local';

const store = new MemoryChunkStore();
const storage = new LocalStorage({ destination: './uploads' });

// POST /upload/chunk
const result = await handleChunkUpload(req, {
  store,
  storage,
  validation: { maxFileSize: '500MB' },
});

if (result.done) {
  console.log('File assembled:', result.file);
}

HandleChunkOptions

| Option | Type | Description | |---|---|---| | store | MemoryChunkStore | Tracks in-progress chunk sessions | | storage | NodeStorageAdapter | Storage adapter used when all chunks arrive | | validation | ValidationOptions | Applied to the final assembled file |

The request must include these headers or form fields:

| Field | Description | |---|---| | x-chunk-index | Zero-based chunk index | | x-chunk-total | Total number of chunks | | x-file-name | Original filename | | x-file-size | Total file size in bytes | | x-upload-id | Unique ID for this upload session |

MemoryChunkStore

Keeps chunk data in memory. Suitable for single-server deployments. For multi-instance setups, implement the ChunkStore interface backed by Redis or a shared filesystem.

const store = new MemoryChunkStore();

NodeStorageAdapter interface

import type { NodeStorageAdapter } from '@stack-upload-orchestrator/node';

const adapter: NodeStorageAdapter = {
  async upload(stream: Readable, meta: NodeFileMetadata): Promise<UploadResult> {
    // stream the file somewhere and return the result
  },
  async delete(fileId: string): Promise<void> { /* optional */ },
};

License

MIT