fast-back-blaze
Version:
A Node.js module to simplify BackBlaze R2 interactions, providing an instance-based API for uploads, deletions, and URL generation.
138 lines (126 loc) • 6.97 kB
JavaScript
// src/index.js
const { S3Client, PutObjectCommand, DeleteObjectCommand } = require('@aws-sdk/client-s3');
const BackblazeB2Error = require('./utils/errorHandling'); // Import custom error handler, renamed from R2Error
/**
* Creates an instance of the Backblaze B2 client with methods for file operations.
* @param {object} options - Configuration options for Backblaze B2.
* @param {string} options.accessKeyId - Your Backblaze B2 Application Key ID.
* @param {string} options.secretAccessKey - Your Backblaze B2 Application Key.
* @param {string} options.bucketName - The name of your Backblaze B2 bucket.
* @param {string} options.endpoint - The S3 compatible endpoint URL for your Backblaze B2 bucket (e.g., 'https://s3.us-west-001.backblazeb2.com').
* @param {string} [options.region] - The region for your Backblaze B2 bucket (e.g., 'us-west-001'). This is used for constructing the endpoint if not provided.
* @returns {object} An object containing uploadFile, deleteFile, and getFileUrl methods.
*/
function createBackblazeB2({ accessKeyId, secretAccessKey, bucketName, endpoint, region }) {
// Validate required options
if (!accessKeyId || !secretAccessKey || !bucketName) {
throw new BackblazeB2Error('Backblaze B2: accessKeyId, secretAccessKey, and bucketName are required to create an instance.');
}
// Determine the B2 endpoint
let b2Endpoint = endpoint;
if (!b2Endpoint) {
if (!region) {
throw new BackblazeB2Error('Backblaze B2: Either endpoint or region must be provided.');
}
b2Endpoint = `https://s3.${region}.backblazeb2.com`;
}
// Initialize the S3Client configured for Backblaze B2
const b2 = new S3Client({
region: region || 'us-west-001', // Backblaze B2 requires a specific region, even if endpoint is provided
endpoint: b2Endpoint,
credentials: {
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey,
},
// Backblaze B2 typically uses path-style access
forcePathStyle: true,
});
/**
* Uploads a file to the configured Backblaze B2 bucket.
* Provides comprehensive information about the uploaded file upon success.
* @param {Buffer} fileBuffer - The binary data of the file to upload.
* @param {string} fileName - The desired key (path and name) for the file in B2 (e.g., 'users/123/profile.jpg').
* @param {string} contentType - The MIME type of the file (e.g., 'image/jpeg', 'video/mp4').
* @returns {Promise<object>} A promise that resolves to an object with upload details:
* { Key: string, ETag: string, Bucket: string, Location: string (public URL), ContentType: string, Size: number }
* @throws {BackblazeB2Error} If the upload operation fails.
*/
const uploadFile = async (fileBuffer, fileName, contentType) => {
const params = {
Bucket: bucketName,
Key: fileName,
Body: fileBuffer,
ContentType: contentType,
};
try {
const command = new PutObjectCommand(params);
const data = await b2.send(command);
// Construct the public URL. This assumes your B2 bucket is configured for public access.
// For private buckets, you would typically generate a pre-signed URL here or on demand.
// Backblaze B2 public URLs are typically in the format:
// https://f00X.backblazeb2.com/file/yourBucketName/yourFileName
// The `s3Endpoint` is not used for public URLs directly in this fashion.
// You will need to know your friendly URL or use the B2 native download URL structure.
// For simplicity, we'll construct a URL based on the S3 endpoint for now, but
// be aware that Backblaze B2's public URLs are different.
// A more robust solution might involve retrieving the friendly URL from B2 API or
// having it configured externally.
const publicUrl = `${b2Endpoint}/${bucketName}/${fileName}`; // This might not be the actual public URL
return {
Key: fileName,
ETag: data.ETag ? data.ETag.replace(/"/g, '') : undefined, // Remove quotes from ETag if present
Bucket: bucketName,
Location: publicUrl, // The full public URL of the uploaded file (needs refinement for true B2 public URL)
ContentType: contentType,
Size: fileBuffer.length // Size of the uploaded content in bytes
};
} catch (error) {
console.error(`Error uploading file '${fileName}' to Backblaze B2 bucket '${bucketName}':`, error);
throw new BackblazeB2Error(`Failed to upload file '${fileName}'.`, error);
}
};
/**
* Deletes a file from the configured Backblaze B2 bucket.
* @param {string} fileName - The key (path and name) of the file to delete from B2.
* @returns {Promise<void>} A promise that resolves upon successful deletion.
* @throws {BackblazeB2Error} If the deletion operation fails.
*/
const deleteFile = async (fileName) => {
const params = {
Bucket: bucketName,
Key: fileName,
};
try {
const command = new DeleteObjectCommand(params);
await b2.send(command);
} catch (error) {
console.error(`Error deleting file '${fileName}' from Backblaze B2 bucket '${bucketName}':`, error);
throw new BackblazeB2Error(`Failed to delete file '${fileName}'.`, error);
}
};
/**
* Generates the public URL for a file in the configured Backblaze B2 bucket.
* This function assumes the B2 bucket is configured for public access.
* For private buckets, you would need to generate a pre-signed URL.
* IMPORTANT: This method constructs a URL based on the S3 compatible endpoint.
* For true public download URLs from Backblaze B2, you often need to use the B2 native
* download URL format (e.g., https://f00X.backblazeb2.com/file/yourBucketName/yourFileName)
* which typically requires knowing your "friendly URL" or making an additional B2 API call.
* This function provides the S3-compatible URL.
* @param {string} fileName - The key (path and name) of the file.
* @returns {string} The public URL of the file.
*/
const getFileUrl = (fileName) => {
if (!fileName) {
throw new BackblazeB2Error('File name is required to generate a URL.');
}
return `${b2Endpoint}/${bucketName}/${fileName}`;
};
// Return the public API of the Backblaze B2 client instance
return {
uploadFile,
deleteFile,
getFileUrl,
};
}
module.exports = createBackblazeB2;