UNPKG

@westerncoal-in/provider-upload-aws-custom-s3

Version:

Strapi upload provider for AWS S3 with folder-based routing by extension

149 lines (138 loc) 4.79 kB
'use strict'; var fp = require('lodash/fp'); var clientS3 = require('@aws-sdk/client-s3'); var s3RequestPresigner = require('@aws-sdk/s3-request-presigner'); var libStorage = require('@aws-sdk/lib-storage'); var utils = require('./utils.js'); // Set custom folder based on file extension const IMAGE_EXTENSIONS = [ '.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.tiff', '.svg', '.ico', '.jfif' ]; const VIDEO_EXTENSIONS = [ '.mp4', '.mov', '.avi', '.mkv', '.webm', '.flv', '.wmv', '.mpeg', '.mpg', '.3gp' ]; const DOCUMENT_EXTENSIONS = [ '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.txt', '.rtf', '.odt', '.csv', '.tsv' ]; const AUDIO_EXTENSIONS = [ '.mp3', '.wav', '.aac', '.flac', '.ogg', '.m4a', '.wma', '.amr' ]; const assertUrlProtocol = (url) => { // Regex to test protocol like "http://", "https://" return /^\w*:\/\//.test(url); }; const getConfig = ({ baseUrl, rootPath, s3Options, ...legacyS3Options }) => { if (Object.keys(legacyS3Options).length > 0) { process.emitWarning("S3 configuration options passed at root level of the plugin's providerOptions is deprecated and will be removed in a future release. Please wrap them inside the 's3Options:{}' property."); } const credentials = utils.extractCredentials({ s3Options, ...legacyS3Options }); const config = { ...s3Options, ...legacyS3Options, ...credentials ? { credentials } : {} }; config.params.ACL = fp.getOr(clientS3.ObjectCannedACL.public_read, [ 'params', 'ACL' ], config); return config; }; var index = { init({ baseUrl, rootPath, s3Options, ...legacyS3Options }) { // TODO V5 change config structure to avoid having to do this const config = getConfig({ baseUrl, rootPath, s3Options, ...legacyS3Options }); const s3Client = new clientS3.S3Client(config); const filePrefix = rootPath ? `${rootPath.replace(/\/+$/, '')}` : ''; const getFileKey = (file) => { const ext = (file.ext || '').toLowerCase(); // Determine folder based on file extension let folder = 'others'; if (IMAGE_EXTENSIONS.includes(ext)) { folder = 'images'; } else if (VIDEO_EXTENSIONS.includes(ext)) { folder = 'videos'; } else if (DOCUMENT_EXTENSIONS.includes(ext)) { folder = 'documents'; } else if (AUDIO_EXTENSIONS.includes(ext)) { folder = 'audios'; } const path = file.path ? `${file.path}/` : ''; return `${filePrefix}/${folder}/${path}${file.hash}${file.ext}`; }; const upload = async (file, customParams = {}) => { const fileKey = getFileKey(file); const uploadObj = new libStorage.Upload({ client: s3Client, params: { Bucket: config.params.Bucket, Key: fileKey, Body: file.stream || Buffer.from(file.buffer, 'binary'), ACL: config.params.ACL, ContentType: file.mime, ...customParams } }); const upload = await uploadObj.done(); if (assertUrlProtocol(upload.Location)) { file.url = baseUrl ? `${baseUrl}/${fileKey}` : upload.Location; } else { // Default protocol to https protocol file.url = `https://${upload.Location}`; } }; return { isPrivate() { return config.params.ACL === 'private'; }, async getSignedUrl(file, customParams) { // Do not sign the url if it does not come from the same bucket. if (!utils.isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) { return { url: file.url }; } const fileKey = getFileKey(file); const url = await s3RequestPresigner.getSignedUrl(// @ts-expect-error - TODO fix client type s3Client, new clientS3.GetObjectCommand({ Bucket: config.params.Bucket, Key: fileKey, ...customParams }), { expiresIn: fp.getOr(15 * 60, [ 'params', 'signedUrlExpires' ], config) }); return { url }; }, uploadStream(file, customParams = {}) { return upload(file, customParams); }, upload(file, customParams = {}) { return upload(file, customParams); }, delete(file, customParams = {}) { const command = new clientS3.DeleteObjectCommand({ Bucket: config.params.Bucket, Key: getFileKey(file), ...customParams }); return s3Client.send(command); } }; } }; module.exports = index; //# sourceMappingURL=index.js.map