@strapi/provider-upload-aws-s3
Version:
AWS S3 provider for strapi upload
115 lines (112 loc) • 4.29 kB
JavaScript
import { getOr } from 'lodash/fp';
import { S3Client, GetObjectCommand, DeleteObjectCommand, ObjectCannedACL } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { Upload } from '@aws-sdk/lib-storage';
import { isUrlFromBucket, extractCredentials } from './utils.mjs';
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 = extractCredentials({
s3Options,
...legacyS3Options
});
const config = {
...s3Options,
...legacyS3Options,
...credentials ? {
credentials
} : {}
};
config.params.ACL = getOr(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 S3Client(config);
const filePrefix = rootPath ? `${rootPath.replace(/\/+$/, '')}/` : '';
const getFileKey = (file)=>{
const path = file.path ? `${file.path}/` : '';
return `${filePrefix}${path}${file.hash}${file.ext}`;
};
const upload = async (file, customParams = {})=>{
const fileKey = getFileKey(file);
const uploadObj = new 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 (!isUrlFromBucket(file.url, config.params.Bucket, baseUrl)) {
return {
url: file.url
};
}
const fileKey = getFileKey(file);
const url = await getSignedUrl(// @ts-expect-error - TODO fix client type
s3Client, new GetObjectCommand({
Bucket: config.params.Bucket,
Key: fileKey,
...customParams
}), {
expiresIn: 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 DeleteObjectCommand({
Bucket: config.params.Bucket,
Key: getFileKey(file),
...customParams
});
return s3Client.send(command);
}
};
}
};
export { index as default };
//# sourceMappingURL=index.mjs.map