@ahhaohho/s3-upload-sdk
v1.0.1
Published
S3 + CloudFront presigned URL SDK for AhhaOhho platform
Maintainers
Readme
@ahhaohho/s3-upload-sdk
S3 + CloudFront presigned URL SDK for AhhaOhho platform. This SDK allows clients to upload files directly to S3 using presigned URLs and get CloudFront URLs for the uploaded files.
Features
- 🚀 Direct upload to S3 using presigned URLs
- ☁️ CloudFront URL support for fast content delivery
- 📦 TypeScript support with full type definitions
- 📊 Upload progress tracking
- 🔄 Multiple file upload support
- ✅ File validation (size, type)
- 🔐 Authorization token support
Installation
npm install @ahhaohho/s3-upload-sdkUsage
Basic Usage
import { S3UploadClient } from '@ahhaohho/s3-upload-sdk';
// Initialize the client
const uploadClient = new S3UploadClient({
apiBaseUrl: 'https://api.ahhaohho.com',
authToken: 'your-auth-token', // Optional
});
// Upload a file
const fileInput = document.getElementById('fileInput') as HTMLInputElement;
const file = fileInput.files[0];
try {
const result = await uploadClient.upload({
file: file,
folder: 'announcements', // Folder in S3
onProgress: (progress) => {
console.log(`Upload progress: ${progress}%`);
},
});
console.log('File uploaded successfully!');
console.log('CloudFront URL:', result.url);
console.log('S3 Key:', result.key);
console.log('File size:', result.size, 'bytes');
} catch (error) {
console.error('Upload failed:', error);
}Upload with Custom Filename
const result = await uploadClient.upload({
file: file,
folder: 'profiles',
filename: 'user-avatar', // Will be: user-avatar-1234567890-abc123.jpg
contentType: 'image/jpeg',
});Upload Multiple Files
const files = Array.from(fileInput.files);
const results = await uploadClient.uploadMultiple(
files.map((file) => ({
file,
folder: 'announcements',
}))
);
const urls = results.map((r) => r.url);
console.log('All files uploaded:', urls);File Validation
const validation = uploadClient.validateFile(
file,
5, // Max 5MB
['image/jpeg', 'image/png', 'image/gif'] // Allowed types
);
if (!validation.valid) {
alert(validation.error);
return;
}
// Proceed with upload
const result = await uploadClient.upload({
file,
folder: 'announcements',
});Update Auth Token
// Update token after login
uploadClient.setAuthToken(newToken);React Example
import React, { useState } from 'react';
import { S3UploadClient } from '@ahhaohho/s3-upload-sdk';
const uploadClient = new S3UploadClient({
apiBaseUrl: process.env.REACT_APP_API_URL,
});
function ImageUploader() {
const [uploading, setUploading] = useState(false);
const [progress, setProgress] = useState(0);
const [imageUrl, setImageUrl] = useState('');
const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
// Validate file
const validation = uploadClient.validateFile(file, 10, [
'image/jpeg',
'image/jpg',
'image/png',
'image/gif',
]);
if (!validation.valid) {
alert(validation.error);
return;
}
try {
setUploading(true);
setProgress(0);
const result = await uploadClient.upload({
file,
folder: 'announcements',
onProgress: (p) => setProgress(p),
});
setImageUrl(result.url);
alert('Upload successful!');
} catch (error) {
console.error('Upload failed:', error);
alert('Upload failed');
} finally {
setUploading(false);
}
};
return (
<div>
<input
type="file"
accept="image/*"
onChange={handleUpload}
disabled={uploading}
/>
{uploading && <div>Upload progress: {progress}%</div>}
{imageUrl && <img src={imageUrl} alt="Uploaded" />}
</div>
);
}
export default ImageUploader;Vue Example
<template>
<div>
<input
type="file"
accept="image/*"
@change="handleUpload"
:disabled="uploading"
/>
<div v-if="uploading">Upload progress: {{ progress }}%</div>
<img v-if="imageUrl" :src="imageUrl" alt="Uploaded" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { S3UploadClient } from '@ahhaohho/s3-upload-sdk';
const uploadClient = new S3UploadClient({
apiBaseUrl: import.meta.env.VITE_API_URL,
});
const uploading = ref(false);
const progress = ref(0);
const imageUrl = ref('');
const handleUpload = async (e: Event) => {
const target = e.target as HTMLInputElement;
const file = target.files?.[0];
if (!file) return;
// Validate file
const validation = uploadClient.validateFile(file, 10, [
'image/jpeg',
'image/jpg',
'image/png',
'image/gif',
]);
if (!validation.valid) {
alert(validation.error);
return;
}
try {
uploading.value = true;
progress.value = 0;
const result = await uploadClient.upload({
file,
folder: 'announcements',
onProgress: (p) => (progress.value = p),
});
imageUrl.value = result.url;
alert('Upload successful!');
} catch (error) {
console.error('Upload failed:', error);
alert('Upload failed');
} finally {
uploading.value = false;
}
};
</script>API Reference
S3UploadClient
Constructor
new S3UploadClient(config: S3UploadConfig)Parameters:
config.apiBaseUrl(string): Base URL of your API serverconfig.authToken(string, optional): Authorization tokenconfig.headers(object, optional): Custom headers
Methods
upload(options: UploadOptions): Promise<UploadResult>
Upload a single file.
Parameters:
options.file(File | Blob): File to uploadoptions.folder(string): Folder path in S3options.filename(string, optional): Custom filenameoptions.contentType(string, optional): Content type (MIME type)options.onProgress(function, optional): Progress callback
Returns:
url(string): CloudFront URLkey(string): S3 keysize(number): File size in bytes
uploadMultiple(files: UploadOptions[]): Promise<UploadResult[]>
Upload multiple files in parallel.
validateFile(file, maxSizeMB, allowedTypes): { valid: boolean, error?: string }
Validate file before upload.
setAuthToken(token: string): void
Update authorization token.
Server-side Setup (Backend Only)
Important: AWS credentials are ONLY needed on your API server, NOT in the client SDK.
The SDK communicates with your API server, which then generates presigned URLs using AWS credentials.
You need to implement a presigned URL endpoint on your backend server:
// Example Express endpoint
app.post('/communities/s3/presigned-url', async (req, res) => {
const { folder, filename, contentType } = req.body;
// Generate presigned URL using AWS SDK
const s3 = new S3Client({ region: 'ap-northeast-2' });
const key = `raw/${folder}/${filename}`;
const command = new PutObjectCommand({
Bucket: 'your-bucket-name',
Key: key,
ContentType: contentType,
});
const uploadUrl = await getSignedUrl(s3, command, { expiresIn: 300 });
const publicUrl = `https://your-cloudfront-domain.cloudfront.net/${key}`;
res.json({
type: 'success',
status: 200,
data: {
uploadUrl,
publicUrl,
key,
expiresIn: 300,
},
message: null,
});
});See the server implementation guide for detailed instructions.
Error Handling
try {
const result = await uploadClient.upload({ file, folder: 'announcements' });
} catch (error) {
if (error.code === 'PRESIGNED_URL_ERROR') {
console.error('Failed to get presigned URL:', error.message);
} else if (error.code === 'S3_UPLOAD_ERROR') {
console.error('Failed to upload to S3:', error.message);
} else {
console.error('Unknown error:', error);
}
}TypeScript Support
This package is written in TypeScript and includes type definitions.
import type { UploadResult, UploadOptions } from '@ahhaohho/s3-upload-sdk';License
ISC
Contributing
Issues and pull requests are welcome!
