@uploadbox/core
v0.7.0
Published
Core utilities for Uploadbox — S3 operations, file validation, builder pattern
Maintainers
Readme
@uploadbox/core
Core utilities for Uploadbox — S3 operations, file validation, and the file-router builder pattern.
Installation
npm i @uploadbox/coreQuick 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 = 3UploadboxApi
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
@uploadbox/nextjs— Next.js route handler adapter@uploadbox/react— React components and hooks
License
MIT
