UNPKG

@3akram/strapi-provider-upload-google-cloud-storage

Version:
154 lines (131 loc) 6.43 kB
import { Storage } from '@google-cloud/storage'; import type { ProviderOptions, File } from './types'; import { logger, validateConfig } from './utils'; export = { init(config: ProviderOptions) { // Validate the configuration and set log level if provided validateConfig(config); // Log configuration with appropriate level (this will only show if logLevel allows info logs) 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(); const bucket = storage.bucket(config.bucketName); logger.info(`Connected to bucket: ${config.bucketName}`); // Helper function to construct file path const getFilePath = (filename: string): string => { const basePath = config.basePath?.replace(/^\/+|\/+$/g, '') || ''; return basePath ? `${basePath}/${filename}` : filename; }; // Helper function to create the public url const getPublicUrl = (filepath: string) => { const {bucketName, baseUrl} = config; const base = baseUrl ?? `https://storage.googleapis.com/${bucketName}`; return `${base}/${filepath}`; } return { async upload(file: File) { try { 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); logger.info(`Generated filepath: ${filepath}`); // Create a new blob in the bucket const blob = bucket.file(filepath); logger.info('Created blob reference'); // Prepare upload options const uploadOptions: any = { 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); logger.info('Created write stream with options:', uploadOptions); // Handle errors during upload return new Promise((resolve, reject) => { blobStream.on('error', error => { 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(); 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(); logger.info('File made public'); } // Construct the public URL const publicUrl = getPublicUrl(filepath); logger.info(`Upload finished. Public URL: ${publicUrl}`); const result = { ...file, url: publicUrl, }; file.url = publicUrl; logger.info('Returning result:', result); resolve(result); } catch (error) { logger.error('Error in finish handler:', error); reject(error); } }); logger.info('Writing file buffer to stream...'); if (!file.buffer) { logger.error('File buffer is undefined or null'); reject(new Error('File buffer is missing')); return; } blobStream.end(file.buffer); }); } catch (error) { logger.error('Error in upload:', error); throw error; } }, async delete(file: 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); logger.info(`Deleting file: ${filepath}`); // Delete the file await bucket.file(filepath).delete(); logger.info('File deleted successfully'); } catch (error) { logger.error('Error in delete:', error); throw error; } }, }; }, };