UNPKG

cloudflare-r2-sdk

Version:

A streamlined Node.js library for effortless integration and management of Cloudflare R2 Object Storage.

194 lines (180 loc) 5.43 kB
const { S3Client, PutObjectCommand, ListBucketsCommand, ListObjectsV2Command, DeleteObjectCommand, HeadObjectCommand, GetObjectCommand } = require('@aws-sdk/client-s3'); const { getSignedUrl } = require('@aws-sdk/s3-request-presigner'); const axios = require('axios'); class R2Client { constructor(accountId, accessKey, secretKey, region = 'auto') { this.endpoint = `https://${accountId}.r2.cloudflarestorage.com`; this.s3 = new S3Client({ region: region, endpoint: this.endpoint, credentials: { accessKeyId: accessKey, secretAccessKey: secretKey, }, }); this.publicDomain = null; } setPublicDomain(domain) { this.publicDomain = domain; } async generateSignedUrl(bucketName, keyName, expiresIn = 604800) { const command = new PutObjectCommand({ Bucket: bucketName, Key: keyName, }); return await getSignedUrl(this.s3, command, { expiresIn }); } async put(bucketName, keyName, fileBuffer, contentType = 'application/octet-stream') { try { const signedUrl = await this.generateSignedUrl(bucketName, keyName); // Upload file using signed URL const response = await axios.put(signedUrl, fileBuffer, { headers: { 'Content-Type': contentType, }, }); if (response.status === 200) { const objectURL = await this.getObjectURL(bucketName, keyName); if (objectURL.success) { return { data: objectURL, status: response.status, message: 'Object has been uploaded successfully', }; } else { return { success: false, message: 'Object uploaded but failed to generate URL', error: objectURL.error, }; } } else { return { success: false, status: response.status, message: 'Object upload failed', }; } } catch (error) { console.error('Error:', error); return { success: false, message: 'Object upload failed', error: error.message, }; } } async listBuckets() { try { const command = new ListBucketsCommand({}); const response = await this.s3.send(command); const jsonResp = {buckets: response.Buckets} return jsonResp } catch (error) { console.error('Error listing buckets:', error); } } async listObjects(bucketName) { try { const command = new ListObjectsV2Command({ Bucket: bucketName, }); const response = await this.s3.send(command); const jsonResp = {objects: response.Contents} return jsonResp; } catch (error) { console.error('Error listing objects:', error); } } async deleteObject(bucketName, keyName) { try { // Check if the object exists const headCommand = new HeadObjectCommand({ Bucket: bucketName, Key: keyName, }); try { await this.s3.send(headCommand); } catch (error) { if (error.name === 'NotFound') { return { success: false, message: 'Object does not exist', }; } throw error; } // Object exists, proceed to delete const command = new DeleteObjectCommand({ Bucket: bucketName, Key: keyName, }); const response = await this.s3.send(command); const success = response.$metadata.httpStatusCode === 204; return { success: success, message: 'Object has been deleted', statusCode: response.$metadata.httpStatusCode, attempts: response.$metadata.attempts, totalRetryDelay: response.$metadata.totalRetryDelay, requestId: response.$metadata.requestId, extendedRequestId: response.$metadata.extendedRequestId, cfId: response.$metadata.cfId }; } catch (error) { console.error('Error deleting object:', error); return { success: false, error: error.message, }; } } async getObjectURL(bucketName, keyName, expiresIn = 604800) { try { const command = new GetObjectCommand({ Bucket: bucketName, Key: keyName, }); const url = await getSignedUrl(this.s3, command, { expiresIn }); const permanentURL = this.publicDomain ? `${this.publicDomain}/${keyName}` : null; return { success: true, statusCode: 200, expire: expiresIn, bucket: bucketName, keyname: keyName, url: url, permanentURL: permanentURL, message: 'Generated signed URL for object', }; } catch (error) { console.error('Error generating object URL:', error); return { success: false, message: 'Failed to generate signed URL for object', error: error.message, }; } } async ping() { try { const start = Date.now(); const command = new ListBucketsCommand({}); await this.s3.send(command); const latency = Date.now() - start; return { success: true, latency: latency, message: 'Ping successful', }; } catch (error) { console.error('Ping failed:', error); return { success: false, message: 'Ping failed', error: error.message, }; } } } module.exports = R2Client;