import { GetObjectCommand, HeadObjectCommand, PutObjectCommand, S3Client, } from "@aws-sdk/client-s3"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; import type { ApiEnv } from "./env.js"; export type PresignPutResult = { url: string; headers: Record; }; export type DocumentsStore = { presignPut(input: { objectKey: string; contentType: string }): Promise; objectExists(objectKey: string): Promise; presignGet(objectKey: string): Promise; }; const SIGN_EXPIRES_SECONDS = 900; export function createDocumentsStore(env: ApiEnv): DocumentsStore { const client = new S3Client({ region: env.awsRegion, endpoint: env.documentsEndpoint || undefined, forcePathStyle: Boolean(env.documentsEndpoint), credentials: env.documentsAccessKey && env.documentsSecretKey ? { accessKeyId: env.documentsAccessKey, secretAccessKey: env.documentsSecretKey } : undefined, }); const bucket = env.documentsBucket; return { async presignPut({ objectKey, contentType }) { const url = await getSignedUrl( client, new PutObjectCommand({ Bucket: bucket, Key: objectKey, ContentType: contentType }), { expiresIn: SIGN_EXPIRES_SECONDS }, ); return { url, headers: { "Content-Type": contentType } }; }, async objectExists(objectKey) { try { await client.send(new HeadObjectCommand({ Bucket: bucket, Key: objectKey })); return true; } catch { return false; } }, async presignGet(objectKey) { return getSignedUrl(client, new GetObjectCommand({ Bucket: bucket, Key: objectKey }), { expiresIn: SIGN_EXPIRES_SECONDS, }); }, }; } export function createMemoryDocumentsStore(): DocumentsStore & { uploaded: Set } { const uploaded = new Set(); return { uploaded, async presignPut({ objectKey, contentType }) { return { url: `http://127.0.0.1:9000/seahaven-ap-documents/${objectKey}?presign=put`, headers: { "Content-Type": contentType }, }; }, async objectExists(objectKey) { return uploaded.has(objectKey); }, async presignGet(objectKey) { return `http://127.0.0.1:9000/seahaven-ap-documents/${objectKey}?presign=get`; }, }; }