Package Exports
- linode-s3-utils
- linode-s3-utils/s3Utils.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (linode-s3-utils) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
linode-s3-utils v1.0
Intuitive class-based S3-compatible object storage utilities with named parameters for Linode Object Storage and AWS S3.
✨ Features
- Class-based approach - Create once, use everywhere
- Named parameters - Self-documenting object-based API
- Environment variable support - Auto-configuration from env vars
- Auto content-type detection - Infers MIME types from file extensions
- Flexible configuration - Works with Linode Object Storage and AWS S3
- Clean error handling - Consistent success/error response format
Installation
npm install linode-s3-utilsQuick Start
const S3Utils = require('linode-s3-utils')
// Create an S3 instance with your configuration
const s3 = new S3Utils({
region: 'us-east-1',
accessKeyId: 'your-access-key',
secretAccessKey: 'your-secret-key'
})
// Upload a file - self-documenting and clear!
const result = await s3.uploadFile({
filePath: './myfile.jpg',
key: 'uploads/myfile.jpg',
bucket: 'my-bucket',
contentType: 'image/jpeg',
acl: 'public-read'
})
console.log(result.publicUrl)
// Generate presigned URL for client uploads
const presignedUrl = await s3.getPresignedUploadUrl({
key: 'uploads/photo.jpg',
bucket: 'my-bucket',
contentType: 'image/jpeg',
expiresIn: 300
})
// Delete an object
await s3.deleteObject({
key: 'old-file.jpg',
bucket: 'my-bucket'
})Environment Variables
Set environment variables and create instance without config:
export LINODE_BUCKET_REGION=us-east-1
export LINODE_S3_ACCESS_KEY=your-access-key
export LINODE_S3_SECRET_KEY=your-secret-keyconst S3Utils = require('linode-s3-utils')
const s3 = new S3Utils() // Uses environment variables automatically
const result = await s3.uploadData({
data: 'Hello World!',
key: 'files/hello.txt',
bucket: 'my-bucket',
contentType: 'text/plain'
})API Reference
Constructor
const s3 = new S3Utils(config)Parameters:
config.region(string): AWS/Linode regionconfig.accessKeyId(string): Access key IDconfig.secretAccessKey(string): Secret access keyconfig.endpoint(string, optional): Custom endpoint (auto-generated for Linode)config.forcePathStyle(boolean, optional): Force path-style addressing (default: true)
Methods
s3.uploadFile(params)
Upload a file from the local filesystem.
const result = await s3.uploadFile({
filePath: './photo.jpg',
key: 'photos/photo.jpg',
bucket: 'my-bucket',
contentType: 'image/jpeg', // optional, auto-detected
acl: 'public-read', // optional, default: 'public-read'
metadata: { // optional
'uploaded-by': 'user123',
'category': 'profile-pics'
}
})
if (result.success) {
console.log('File uploaded:', result.publicUrl)
}Parameters:
params.filePath(string): Local path to the fileparams.key(string): Object key (path) in the bucketparams.bucket(string): Bucket nameparams.contentType(string, optional): MIME type (auto-detected if not provided)params.acl(string, optional): Access control list (default: 'public-read')params.metadata(object, optional): Additional metadata to store with the object
s3.uploadData(params)
Upload data (Buffer or string) directly.
const result = await s3.uploadData({
data: 'Hello World!',
key: 'files/hello.txt',
bucket: 'my-bucket',
contentType: 'text/plain',
acl: 'private', // optional
metadata: { // optional
'source': 'api-generated'
}
})Parameters:
params.data(Buffer|string): Data to uploadparams.key(string): Object key (path) in the bucketparams.bucket(string): Bucket nameparams.contentType(string): MIME typeparams.acl(string, optional): Access control list (default: 'public-read')params.metadata(object, optional): Additional metadata to store with the object
s3.getPresignedUploadUrl(params)
Generate a presigned URL for client-side uploads.
const uploadUrl = await s3.getPresignedUploadUrl({
key: 'uploads/user-photo.jpg',
bucket: 'my-bucket',
contentType: 'image/jpeg',
expiresIn: 300, // 5 minutes
acl: 'public-read'
})Parameters:
params.key(string): Object key (path) in the bucketparams.bucket(string): Bucket nameparams.contentType(string, optional): MIME type (auto-detected if not provided)params.expiresIn(number, optional): URL expiration time in seconds (default: 180)params.acl(string, optional): Access control list (default: 'public-read')
s3.deleteObject(params)
Delete an object.
const result = await s3.deleteObject({
key: 'old-file.jpg',
bucket: 'my-bucket'
})Parameters:
params.key(string): Object key to deleteparams.bucket(string): Bucket name
s3.getPublicUrl(key, bucket)
Get public URL for an object.
const url = s3.getPublicUrl('photos/photo.jpg', 'my-bucket')Usage Patterns
Pattern 1: Single Instance for Entire App
// utils/s3.js
const S3Utils = require('linode-s3-utils')
const s3 = new S3Utils({
region: process.env.LINODE_BUCKET_REGION,
accessKeyId: process.env.LINODE_S3_ACCESS_KEY,
secretAccessKey: process.env.LINODE_S3_SECRET_KEY,
})
module.exports = s3// anywhere in your app
const s3 = require('./utils/s3')
const result = await s3.uploadFile({
filePath: './file.jpg',
key: 'uploads/file.jpg',
bucket: 'my-bucket'
})Pattern 2: Application-Specific Manager
class AppS3Manager {
constructor() {
this.s3 = new S3Utils({ /* config */ })
this.bucketName = 'my-app-bucket'
}
async uploadUserAvatar(userId, imageBuffer, mimeType) {
return await this.s3.uploadData({
data: imageBuffer,
key: `users/${userId}/avatar.${mimeType.split('/')[1]}`,
bucket: this.bucketName,
contentType: mimeType,
metadata: { 'user-id': userId, 'type': 'avatar' }
})
}
async generateUserUploadUrl(userId, fileName, mimeType) {
return await this.s3.getPresignedUploadUrl({
key: `users/${userId}/uploads/${fileName}`,
bucket: this.bucketName,
contentType: mimeType,
expiresIn: 600
})
}
}
const appS3 = new AppS3Manager()
module.exports = appS3Pattern 3: Express Route Integration
const S3Utils = require('linode-s3-utils')
const s3 = new S3Utils({ /* config */ })
router.post('/upload', async (req, res) => {
const result = await s3.uploadData({
data: req.file.buffer,
key: `uploads/${req.file.originalname}`,
bucket: 'my-bucket',
contentType: req.file.mimetype,
metadata: {
'uploaded-by': req.user.id,
'upload-time': new Date().toISOString()
}
})
if (result.success) {
res.json({ url: result.publicUrl })
} else {
res.status(500).json({ error: result.error })
}
})Why Named Parameters?
Comparison: Positional vs Named Parameters
Traditional Approach (Confusing):
// Hard to remember order, unclear what each parameter does
await uploadFile('./file.jpg', 'uploads/file.jpg', 'my-bucket', 'image/jpeg', 'public-read')Our Approach (Clear):
// Self-documenting, clear, order-independent
await s3.uploadFile({
filePath: './file.jpg',
key: 'uploads/file.jpg',
bucket: 'my-bucket',
contentType: 'image/jpeg',
acl: 'public-read'
})Benefits:
- ✅ Self-documenting - parameter names make it clear what each value is
- ✅ Order independent - can specify parameters in any order
- ✅ Optional parameters - easy to omit optional parameters
- ✅ IDE support - better autocomplete and IntelliSense
- ✅ Less error-prone - harder to mix up parameter order
- ✅ Future-proof - easy to add new parameters without breaking changes
Error Handling
All methods return objects with a success boolean:
const result = await s3.uploadFile({
filePath: './file.jpg',
key: 'file.jpg',
bucket: 'bucket'
})
if (result.success) {
console.log('Success:', result.publicUrl)
} else {
console.error('Error:', result.error)
}Supported File Types
Auto-detection for common extensions:
- Images: jpg, jpeg, png, gif
- Documents: pdf, txt, json, html, css, js
- Media: mp3, mp4, mov, wav
License
MIT