S3 Service
Harpia includes a first-class service for interacting with Amazon S3 (or compatible storage providers like MinIO and DigitalOcean Spaces) using Bun’s built-in S3Client
. The S3Service
provides a convenient API for file uploads, downloads, streaming, deletion, and presigned URLs.
ℹ️ This is powered by Bun’s native S3Client, meaning it does not require any external AWS SDK. When using non-AWS providers (like MinIO or DigitalOcean Spaces), make sure to set a custom endpoint URL.
Quickstart
Here are some common use cases to get started quickly:
// Assume S3Service is already initialized
// Uploadawait s3.send("notes/hello.txt", "Hello, world!", { type: "text/plain" });
// Read as textconst content = await s3.readAsText("notes/hello.txt");
// Read as JSONconst json = await s3.readAsJson<{ title: string }>("data/post.json");
// Deleteawait s3.delete("notes/hello.txt");
// Upload large fileawait s3.sendLargeFile("videos/big.mp4", buffer, { partSize: 5 * 1024 * 1024 });
// Generate presigned URLconst url = s3.generatePresignedUrl("notes/hello.txt", { expiresIn: 3600 });
Configuration
To use the S3Service
, you must configure it with your S3 credentials:
import { S3Service } from "app/services/s3";
const s3 = new S3Service({ bucket: "my-bucket", accessKeyId: process.env.AWS_ACCESS_KEY_ID!, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!, region: "us-east-1", endpoint: "https://s3.amazonaws.com", // optional for AWS});
Uploading a File
await s3.send("uploads/image.png", fileBuffer, { type: "image/png", acl: "public-read",});
Reading Files
As text:
const text = await s3.readAsText("docs/readme.txt");
As JSON:
const json = await s3.readAsJson<{ name: string }>("data/user.json");
As binary:
const buffer = await s3.readAsArrayBuffer("archive.zip");
Partial content:
const excerpt = await s3.readPartial("bigfile.txt", 0, 100);
Deleting Files
await s3.delete("uploads/old-image.jpg");
Uploading Large Files
Use sendLargeFile()
to stream large content in parts:
await s3.sendLargeFile("videos/long.mp4", videoBuffer, { partSize: 10 * 1024 * 1024, // 10MB chunks queueSize: 5, acl: "private",});
Generating a Presigned URL
const url = s3.generatePresignedUrl("uploads/photo.jpg", { expiresIn: 3600, // 1 hour acl: "public-read", method: "GET",});
This URL can be shared with clients to securely access files without exposing sensitive credentials.
File References
The .file(key)
method returns a S3File
reference:
const file = s3.file("docs/manual.pdf");
await file.exists();await file.delete();await file.write("Hello World");
Useful when you need finer control using the underlying Bun S3File
API.
Error Handling
If credentials are missing or invalid, an error with code ERR_S3_MISSING_CREDENTIALS
will be thrown:
try { await s3.send("path", buffer);} catch (error) { if ((error as any).code === "ERR_S3_MISSING_CREDENTIALS") { // Handle credential error }}
When to Use
The S3Service
is a great fit when:
- You want to upload or read files from S3 without external dependencies
- You need to stream large files efficiently
- You require secure access via presigned URLs
- You want native S3 support with excellent performance and simplicity