import { GetObjectCommand, PutObjectCommand, PutObjectCommandOutput, S3Client, S3ClientConfig, } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; import type { ImgInfo, S3UserConfig, UploadResult } from './types'; import { extractInfo } from './utils'; async function getFileURL( opts: createUploadTaskOpts, eTag: string, versionId: string, ): Promise { try { const signedUrl = await getSignedUrl( opts.client, new GetObjectCommand({ Bucket: opts.bucketName, IfMatch: eTag, Key: opts.path, VersionId: versionId, }), { expiresIn: 3600 }, ); const urlObject = new URL(signedUrl); urlObject.search = ''; return urlObject.href; } catch (error) { // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.reject(error); } } function createS3Client(opts: S3UserConfig): S3Client { const clientOptions: S3ClientConfig = { credentials: { accessKeyId: opts.accessKeyId, secretAccessKey: opts.secretAccessKey, }, endpoint: opts.endpoint || undefined, forcePathStyle: opts.pathStyleAccess, region: opts.region || 'auto', }; const client = new S3Client(clientOptions); return client; } interface createUploadTaskOpts { acl: string; bucketName: string; client: S3Client; item: ImgInfo; path: string; urlPrefix?: string; } async function createUploadTask(opts: createUploadTaskOpts): Promise { if (!opts.item.buffer) { throw new Error('undefined image'); } let body: Buffer; let contentType: string; let contentEncoding: string; try { ({ body, contentType, contentEncoding } = (await extractInfo(opts.item)) as any); } catch (error) { // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.reject(error); } const command = new PutObjectCommand({ ACL: opts.acl as any, Body: body, Bucket: opts.bucketName, ContentEncoding: contentEncoding, ContentType: contentType, Key: opts.path, }); let output: PutObjectCommandOutput; try { output = await opts.client.send(command); } catch (error) { // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.reject(error); } let url: string; if (opts.urlPrefix) { url = `${opts.urlPrefix}/${opts.path}`; } else { try { url = await getFileURL(opts, output.ETag as string, output.VersionId as string); } catch (error) { // eslint-disable-next-line unicorn/no-useless-promise-resolve-reject return Promise.reject(error); } } return { eTag: output.ETag, imgURL: url, key: opts.path, url: url, versionId: output.VersionId, }; } export default { createS3Client, createUploadTask, };