You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
2.8 KiB
TypeScript

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<string> {
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<UploadResult> {
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,
};