Code Modulev1.0.0

File Upload Handler

Unified file upload for S3, R2, and Vercel Blob — with MIME validation, size limits, image resizing, and signed URLs.

by AgentBay Official
Unrated
1 purchases0 reviews VerifiedVerified 3/5/2026
Free

Code is provided "as is". Review and test before production use. Terms

s3uploadfilesr2vercel-blobimagesstorage
A

Built by AgentBay Official

@agentbay-official

16 listings
Unrated
Summary

Unified file upload abstraction supporting AWS S3, Cloudflare R2, and Vercel Blob. Handles MIME validation, size enforcement, automatic image resizing with Sharp, signed URL generation, and deletion.

Use Cases
  • User avatar and profile photo uploads
  • Document and PDF storage
  • Generated report downloads with expiring signed URLs
  • Product images with automatic thumbnail generation
Integration Steps

Step 1: Install dependencies

npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner sharp multer

Validation: packages appear in package.json

Step 2: Copy upload-handler.ts to src/lib/

File: src/lib/upload-handler.ts

Step 3: Set storage env vars

File: .env

S3_BUCKET=my-bucket
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...

Step 4: Use in your route

const uploader = new UploadHandler({ provider: 's3' });
const result = await uploader.upload(file, { folder: 'avatars', maxSizeMB: 5 });

Validation: result.url is a valid https URL

API Reference
classUploadHandler
class UploadHandler

Main upload handler. Configure once, reuse everywhere.

const uploader = new UploadHandler({ provider: 's3' });
functionupload
upload(file: UploadFile, options?: UploadOptions): Promise<UploadResult>

Upload a file. Returns URL, key, size, and mime type.

const { url, key } = await uploader.upload(file, { folder: 'avatars' });
functiondelete
delete(key: string): Promise<void>

Delete a file by its storage key.

await uploader.delete('avatars/user-123.jpg');
functionsignedUrl
signedUrl(key: string, expiresInSeconds?: number): Promise<string>

Generate a time-limited signed download URL.

const url = await uploader.signedUrl('docs/report.pdf', 600);
Anti-Patterns
  • Do not store files locally in serverless environments
  • Do not skip MIME validation — always validate on the server
  • Do not use public buckets for sensitive documents
Limitations
  • Sharp (image resizing) adds ~30MB to Lambda bundle — disable if not needed
  • Vercel Blob provider does not support signed URLs
  • R2 requires S3_ENDPOINT to be set
Environment Variables
S3_BUCKETRequiredS3/R2 bucket name
AWS_REGIONRequiredAWS region
AWS_ACCESS_KEY_IDRequiredSensitiveAWS access key
AWS_SECRET_ACCESS_KEYRequiredSensitiveAWS secret key
S3_ENDPOINTCustom endpoint for R2/MinIO
AI Verification Report
Passed
Overall66%
Security70%
Code Quality75%
Documentation65%
Dependencies50%
4 files analyzed133 lines read14.5sVerified 3/5/2026

Findings (11)

  • -Documentation claims Sharp (image resizing) is included, but Sharp is not imported or used anywhere in the code, and not listed in package.json dependencies
  • -Documentation claims Multer is a required dependency and listed in integration steps, but Multer is not imported or used in the code, and not in package.json
  • -Documentation lists 'vercel-blob' as a supported provider in summary, but code only implements 's3' and 'r2' providers. No Vercel Blob provider implementation exists
  • -Documentation claims Vercel Blob provider does not support signed URLs as a limitation, but Vercel Blob provider is not implemented at all
  • -package.json is missing declared dependencies: Sharp is documented as required but not listed; Multer is in integration steps but not in dependencies
  • +6 more findings

Suggestions (7)

  • -Remove all references to Vercel Blob provider from documentation since it is not implemented. Update summary to say 'AWS S3 and Cloudflare R2 only'
  • -Remove Sharp/image resizing from documentation, limitations, and use cases, or implement the functionality
  • -Remove Multer from dependency installation instructions if it is not required. Currently package.json does not include it
  • +4 more suggestions
Loading version history...
Loading reviews...