46 lines
1.2 KiB
TypeScript
Raw Normal View History

2024-04-29 15:54:01 -05:00
import { join } from 'node:path';
import { crypto } from '@std/crypto';
import { encodeHex } from '@std/encoding/hex';
import { extensionsByType } from '@std/media-types';
import { Conf } from '@/config.ts';
2024-04-29 15:54:01 -05:00
import { S3Client } from '@/deps.ts';
import type { Uploader } from './types.ts';
2024-04-29 15:54:01 -05:00
/** S3-compatible uploader for AWS, Wasabi, DigitalOcean Spaces, and more. */
2023-09-08 15:01:30 -05:00
const s3Uploader: Uploader = {
async upload(file) {
2024-04-29 15:54:01 -05:00
const sha256 = encodeHex(await crypto.subtle.digest('SHA-256', file.stream()));
const ext = extensionsByType(file.type)?.[0] ?? 'bin';
const filename = `${sha256}.${ext}`;
2024-04-29 15:54:01 -05:00
await client().putObject(filename, file.stream(), {
2023-09-08 15:01:30 -05:00
metadata: {
'Content-Type': file.type,
'x-amz-acl': 'public-read',
},
});
2024-04-29 15:54:01 -05:00
const { pathStyle, bucket } = Conf.s3;
const path = (pathStyle && bucket) ? join(bucket, filename) : filename;
2023-09-08 15:01:30 -05:00
return {
2024-04-29 15:54:01 -05:00
id: filename,
sha256,
url: new URL(path, Conf.mediaDomain).toString(),
2023-09-08 15:01:30 -05:00
};
},
2024-04-29 15:54:01 -05:00
async delete(id) {
await client().deleteObject(id);
2023-09-08 15:01:30 -05:00
},
};
/** Build S3 client from config. */
function client() {
return new S3Client({ ...Conf.s3 });
}
export { s3Uploader };