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
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,
|
|
};
|