/** * Storage abstraction for S3/GCS */ import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, HeadObjectCommand, } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; export class StorageClient { config; s3Client; bucket; constructor(config) { this.config = config; this.bucket = config.bucket; this.s3Client = new S3Client({ region: config.region || 'us-east-1', credentials: config.accessKeyId && config.secretAccessKey ? { accessKeyId: config.accessKeyId, secretAccessKey: config.secretAccessKey, } : undefined, }); } async upload(object) { const command = new PutObjectCommand({ Bucket: this.bucket, Key: object.key, Body: typeof object.content === 'string' ? Buffer.from(object.content) : object.content, ContentType: object.contentType, Metadata: object.metadata, }); await this.s3Client.send(command); return object.key; } async download(key) { const command = new GetObjectCommand({ Bucket: this.bucket, Key: key, }); const response = await this.s3Client.send(command); if (!response.Body) { throw new Error(`Object ${key} not found or empty`); } const chunks = []; if (response.Body) { const body = response.Body; for await (const chunk of body) { chunks.push(chunk); } } return Buffer.concat(chunks); } async delete(key) { const command = new DeleteObjectCommand({ Bucket: this.bucket, Key: key, }); await this.s3Client.send(command); } async getPresignedUrl(key, expiresIn) { const command = new GetObjectCommand({ Bucket: this.bucket, Key: key, }); return getSignedUrl(this.s3Client, command, { expiresIn }); } async objectExists(key) { try { const command = new HeadObjectCommand({ Bucket: this.bucket, Key: key, }); await this.s3Client.send(command); return true; } catch (error) { if (error && typeof error === 'object' && 'name' in error && error.name === 'NotFound') { return false; } throw error; } } } //# sourceMappingURL=storage.js.map