import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; import type { ObjectStorage } from './interface.js'; interface MinioStorageOptions { endpoint: string; region: string; bucket: string; accessKey: string; secretKey: string; forcePathStyle: boolean; } export class MinioStorage implements ObjectStorage { private readonly client: S3Client; private readonly bucket: string; constructor(opts: MinioStorageOptions) { this.bucket = opts.bucket; this.client = new S3Client({ endpoint: opts.endpoint, region: opts.region, credentials: { accessKeyId: opts.accessKey, secretAccessKey: opts.secretKey, }, forcePathStyle: opts.forcePathStyle, }); } async signPut( key: string, contentType: string, _byteSize: number, ttlSec: number, ): Promise<{ url: string; expiresAt: Date }> { const cmd = new PutObjectCommand({ Bucket: this.bucket, Key: key, ContentType: contentType, }); const url = await getSignedUrl(this.client, cmd, { expiresIn: ttlSec }); return { url, expiresAt: new Date(Date.now() + ttlSec * 1000) }; } async signGet(key: string, ttlSec: number): Promise<{ url: string; expiresAt: Date }> { const cmd = new GetObjectCommand({ Bucket: this.bucket, Key: key }); const url = await getSignedUrl(this.client, cmd, { expiresIn: ttlSec }); return { url, expiresAt: new Date(Date.now() + ttlSec * 1000) }; } async delete(key: string): Promise { await this.client.send(new DeleteObjectCommand({ Bucket: this.bucket, Key: key })); } }