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

@uploadbox/core

v0.7.0

Published

Core utilities for Uploadbox — S3 operations, file validation, builder pattern

Readme

@uploadbox/core

Core utilities for Uploadbox — S3 operations, file validation, and the file-router builder pattern.

npm license

Installation

npm i @uploadbox/core

Quick Start

Define upload routes using the f() builder pattern:

import { f } from "@uploadbox/core";

const router = {
  imageUploader: f({ image: { maxFileSize: "4MB", maxFileCount: 5 } })
    .middleware(async ({ files, auth }) => {
      // API key auth (hosted): auth?.apiKeyId
      // Session auth (self-hosted): auth?.userId
      return { userId: auth?.userId ?? auth?.apiKeyId };
    })
    .onUploadComplete(async ({ file, metadata }) => {
      console.log("Upload complete:", file.url);
      return { fileId: file.key };
    }),

  documentUploader: f({
    pdf: { maxFileSize: "16MB" },
    text: { maxFileSize: "1MB" },
  })
    .middleware(async ({ auth }) => {
      if (!auth) throw new Error("Unauthorized");
      // Resolves userId from session auth or apiKeyId from API key auth
      return { userId: auth.userId ?? auth.apiKeyId };
    })
    .onUploadComplete(async ({ file }) => {
      return { url: file.url };
    }),
};

export type AppRouter = typeof router;

File Route Config

Each route accepts a map of file types with constraints:

f({
  image: {
    maxFileSize: "4MB",       // "B" | "KB" | "MB" | "GB"
    maxFileCount: 10,
    minFileCount: 1,
    acl: "public-read",       // "public-read" | "private"
    contentDisposition: "inline",
    presignedUrlExpiry: 3600, // seconds
    defaultTtlSeconds: 86400,
    maxTtlSeconds: 604800,
  },
})

Supported file types: image, video, audio, pdf, text, blob (any file).

S3 Utilities

Create an S3 Client

import { createS3Client } from "@uploadbox/core";

const s3 = createS3Client({
  bucket: "my-bucket",
  region: "us-east-1",
  accessKeyId: "...",
  secretAccessKey: "...",
  // Optional — for MinIO, R2, Wasabi:
  endpoint: "https://s3.example.com",
  forcePathStyle: true,
});

Or use environment variables (UPLOADBOX_S3_BUCKET, UPLOADBOX_AWS_REGION, etc.) and let createUploadbox() auto-configure.

Presigned URLs

import { generatePresignedPutUrl, generatePresignedGetUrl } from "@uploadbox/core";

const putUrl = await generatePresignedPutUrl(s3, "bucket", "key.png", "image/png", 1024);
const getUrl = await generatePresignedGetUrl(s3, "bucket", "key.png", 3600);

Other S3 Operations

import { headObject, deleteObject, deleteObjects, listObjects } from "@uploadbox/core";

await headObject(s3, "bucket", "key.png");     // verify existence
await deleteObject(s3, "bucket", "key.png");
await deleteObjects(s3, "bucket", ["a.png", "b.png"]);
const { keys, nextToken } = await listObjects(s3, "bucket", "uploads/");

Multipart Uploads

Files larger than 10 MB are automatically split into parts:

import {
  createMultipartUpload,
  generatePresignedPartUrls,
  completeMultipartUpload,
  abortMultipartUpload,
  MULTIPART_THRESHOLD,
  DEFAULT_PART_SIZE,
} from "@uploadbox/core";

const uploadId = await createMultipartUpload(s3, "bucket", "key.mp4", "video/mp4");
const parts = await generatePresignedPartUrls(s3, "bucket", "key.mp4", uploadId, [1, 2, 3]);
// ... upload parts ...
await completeMultipartUpload(s3, "bucket", "key.mp4", uploadId, [
  { partNumber: 1, etag: "..." },
  { partNumber: 2, etag: "..." },
]);

Processing Hooks

Optional post-upload processing via subpath imports. These run server-side after a file is uploaded.

Image Resize

Requires sharp as a peer dependency.

import { createImageResizeHook } from "@uploadbox/core/hooks/image-resize";

const resizeHook = createImageResizeHook({
  maxWidth: 1920,
  maxHeight: 1080,
  quality: 80,
  format: "webp", // "jpeg" | "png" | "webp"
});

Virus Scan

Requires a running ClamAV REST service.

import { createVirusScanHook } from "@uploadbox/core/hooks/virus-scan";

const scanHook = createVirusScanHook({
  clamavUrl: "http://localhost:3310",
  deleteOnDetection: true,
  timeoutMs: 30000,
});

Server-Side Upload

Upload files directly from your server (no presigned URL):

import { serverUpload, serverUploadMany } from "@uploadbox/core";

const result = await serverUpload(s3, config, {
  name: "report.pdf",
  body: buffer,
  contentType: "application/pdf",
  acl: "private",
});

const results = await serverUploadMany(s3, config, files, 3); // concurrency = 3

UploadboxApi

High-level wrapper combining common operations:

import { UploadboxApi } from "@uploadbox/core";

const api = new UploadboxApi(s3, config);

await api.uploadFile({ name: "photo.jpg", body: buffer });
await api.deleteFile("uploads/photo.jpg");
const url = await api.getSignedUrl("uploads/photo.jpg");
const { keys } = await api.listFiles({ prefix: "uploads/" });

Utilities

import { parseFileSize, formatFileSize, validateFiles, generateFileKey } from "@uploadbox/core";

parseFileSize("4MB");          // 4194304
formatFileSize(4194304);       // "4 MB"
generateFileKey("my file.png"); // "my-file-a1b2c3d4e5f6.png"

// Throws UploadboxError if validation fails
validateFiles(files, { image: { maxFileSize: "4MB", maxFileCount: 5 } });

Key Types

| Type | Description | |------|-------------| | FileRouter | Record<string, FileRoute> — your upload route definitions | | UploadboxConfig | S3 config: bucket, region, credentials, endpoint, CDN URL | | UploadedFileData | Completed upload: key, name, size, type, url, acl, metadata | | AuthContext | { userId?, userName?, apiKeyId?, apiKeyName?, projectId? } — session fields for self-hosted, API key fields for hosted | | FileRouteConfig | Per-type constraints: maxFileSize, maxFileCount, acl, etc. | | ProcessingHook | { name, shouldRun, run, timeoutMs? } | | UploadboxError | Structured error with code, statusCode, and static factories |

Related Packages

License

MIT