UNPKG

linode-s3-utils

Version:

Clean, intuitive class-based S3-compatible object storage utilities with named parameters for Linode Object Storage and AWS S3

340 lines (269 loc) 8.52 kB
# 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 ```bash npm install linode-s3-utils ``` ## Quick Start ```javascript 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: ```bash export LINODE_BUCKET_REGION=us-east-1 export LINODE_S3_ACCESS_KEY=your-access-key export LINODE_S3_SECRET_KEY=your-secret-key ``` ```javascript const 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 ```javascript const s3 = new S3Utils(config) ``` **Parameters:** - `config.region` (string): AWS/Linode region - `config.accessKeyId` (string): Access key ID - `config.secretAccessKey` (string): Secret access key - `config.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. ```javascript 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 file - `params.key` (string): Object key (path) in the bucket - `params.bucket` (string): Bucket name - `params.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. ```javascript 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 upload - `params.key` (string): Object key (path) in the bucket - `params.bucket` (string): Bucket name - `params.contentType` (string): MIME type - `params.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. ```javascript 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 bucket - `params.bucket` (string): Bucket name - `params.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. ```javascript const result = await s3.deleteObject({ key: 'old-file.jpg', bucket: 'my-bucket' }) ``` **Parameters:** - `params.key` (string): Object key to delete - `params.bucket` (string): Bucket name #### `s3.getPublicUrl(key, bucket)` Get public URL for an object. ```javascript const url = s3.getPublicUrl('photos/photo.jpg', 'my-bucket') ``` ## Usage Patterns ### Pattern 1: Single Instance for Entire App ```javascript // 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 ``` ```javascript // 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 ```javascript 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 = appS3 ``` ### Pattern 3: Express Route Integration ```javascript 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):** ```javascript // 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):** ```javascript // 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: ```javascript 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