@3akram/strapi-provider-upload-google-cloud-storage
Version:
Google Cloud Storage provider for Strapi v5 upload
136 lines (135 loc) • 6.63 kB
JavaScript
;
const storage_1 = require("@google-cloud/storage");
const utils_1 = require("./utils");
module.exports = {
init(config) {
// Validate the configuration and set log level if provided
(0, utils_1.validateConfig)(config);
// Log configuration with appropriate level (this will only show if logLevel allows info logs)
utils_1.logger.info('Initializing GCS provider with config:', {
...config,
// Don't log any potential credentials that might be in the config
_sanitized: true
});
// Initialize Google Cloud Storage
const storage = new storage_1.Storage();
const bucket = storage.bucket(config.bucketName);
utils_1.logger.info(`Connected to bucket: ${config.bucketName}`);
// Helper function to construct file path
const getFilePath = (filename) => {
var _a;
const basePath = ((_a = config.basePath) === null || _a === void 0 ? void 0 : _a.replace(/^\/+|\/+$/g, '')) || '';
return basePath ? `${basePath}/${filename}` : filename;
};
// Helper function to create the public url
const getPublicUrl = (filepath) => {
const { bucketName, baseUrl } = config;
const base = baseUrl !== null && baseUrl !== void 0 ? baseUrl : `https://storage.googleapis.com/${bucketName}`;
return `${base}/${filepath}`;
};
return {
async upload(file) {
try {
utils_1.logger.info('Starting upload for file:', {
name: file.name,
hash: file.hash,
ext: file.ext,
mime: file.mime,
size: file.size,
});
// Create a unique filename and path
const filename = `${file.hash}${file.ext}`;
const filepath = getFilePath(filename);
utils_1.logger.info(`Generated filepath: ${filepath}`);
// Create a new blob in the bucket
const blob = bucket.file(filepath);
utils_1.logger.info('Created blob reference');
// Prepare upload options
const uploadOptions = {
resumable: false,
metadata: {
contentType: file.mime,
},
};
// Add predefined ACL if uniform access is not enabled
if (!config.uniform && config.publicFiles) {
uploadOptions.predefinedAcl = 'publicRead';
}
// Upload the file data
const blobStream = blob.createWriteStream(uploadOptions);
utils_1.logger.info('Created write stream with options:', uploadOptions);
// Handle errors during upload
return new Promise((resolve, reject) => {
blobStream.on('error', error => {
utils_1.logger.error(`Error uploading file ${filepath}:`, error);
reject(error);
});
blobStream.on('finish', async () => {
try {
// Check if the file exists in the bucket
const [exists] = await blob.exists();
utils_1.logger.info(`File exists in bucket: ${exists}`);
if (!exists) {
throw new Error('File was not uploaded successfully');
}
// Make the file public if needed and uniform access is not enabled
if (!config.uniform && config.publicFiles) {
await blob.makePublic();
utils_1.logger.info('File made public');
}
// Construct the public URL
const publicUrl = getPublicUrl(filepath);
utils_1.logger.info(`Upload finished. Public URL: ${publicUrl}`);
const result = {
...file,
url: publicUrl,
};
file.url = publicUrl;
utils_1.logger.info('Returning result:', result);
resolve(result);
}
catch (error) {
utils_1.logger.error('Error in finish handler:', error);
reject(error);
}
});
utils_1.logger.info('Writing file buffer to stream...');
if (!file.buffer) {
utils_1.logger.error('File buffer is undefined or null');
reject(new Error('File buffer is missing'));
return;
}
blobStream.end(file.buffer);
});
}
catch (error) {
utils_1.logger.error('Error in upload:', error);
throw error;
}
},
async delete(file) {
try {
if (!file.url) {
return;
}
// Extract filename from the URL
const urlParts = file.url.split('/');
const filename = urlParts[urlParts.length - 1];
if (!filename) {
throw new Error('Could not extract filename from URL');
}
// Get the full filepath
const filepath = getFilePath(filename);
utils_1.logger.info(`Deleting file: ${filepath}`);
// Delete the file
await bucket.file(filepath).delete();
utils_1.logger.info('File deleted successfully');
}
catch (error) {
utils_1.logger.error('Error in delete:', error);
throw error;
}
},
};
},
};