Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
at main 104 lines 3.0 kB view raw
1import { S3 } from "@aws-sdk/client-s3"; 2import { Upload } from "@aws-sdk/lib-storage"; 3import { CHAIN, EVER_API, EVER_BUCKET, EVER_REGION } from "@hey/data/constants"; 4import generateUUID from "@hey/helpers/generateUUID"; 5import { immutable } from "@lens-chain/storage-client"; 6import { hono } from "./fetcher"; 7import { storageClient } from "./storageClient"; 8 9interface UploadResult { 10 mimeType: string; 11 uri: string; 12} 13 14const FALLBACK_TYPE = "image/jpeg"; 15const FILE_SIZE_LIMIT_MB = 8 * 1024 * 1024; // 8MB in bytes 16 17const getS3Client = async (): Promise<S3> => { 18 const data = await hono.metadata.sts(); 19 20 if (!data) { 21 throw new Error("Failed to get S3 client"); 22 } 23 24 const client = new S3({ 25 credentials: { 26 accessKeyId: data.accessKeyId ?? "", 27 secretAccessKey: data.secretAccessKey ?? "", 28 sessionToken: data.sessionToken ?? "" 29 }, 30 endpoint: EVER_API, 31 maxAttempts: 10, 32 region: EVER_REGION 33 }); 34 35 return client; 36}; 37 38const uploadToIPFS = async ( 39 data: FileList | File[] 40): Promise<UploadResult[]> => { 41 try { 42 const files = Array.from(data) as File[]; 43 const s3Files = files.filter( 44 (file: File) => file.size > FILE_SIZE_LIMIT_MB 45 ); 46 const client = s3Files.length > 0 ? await getS3Client() : null; 47 48 const attachments = await Promise.all( 49 files.map(async (file: File) => { 50 // If the file is less than FILE_SIZE_LIMIT_MB, upload it to the Grove 51 if (file.size <= FILE_SIZE_LIMIT_MB) { 52 const storageNodeResponse = await storageClient.uploadFile(file, { 53 acl: immutable(CHAIN.id) 54 }); 55 56 return { 57 mimeType: file.type || FALLBACK_TYPE, 58 uri: storageNodeResponse.uri 59 }; 60 } 61 62 // For files larger than FILE_SIZE_LIMIT_MB, use the S3 client 63 if (client) { 64 const currentDate = new Date() 65 .toLocaleDateString("en-GB") 66 .replace(/\//g, "-"); 67 68 const params = { 69 Body: file, 70 Bucket: EVER_BUCKET, 71 ContentType: file.type, 72 Key: `${currentDate}/${generateUUID()}` 73 }; 74 const task = new Upload({ client, params }); 75 await task.done(); 76 const result = await client.headObject(params); 77 const metadata = result.Metadata; 78 const cid = metadata?.["ipfs-hash"]; 79 80 return { mimeType: file.type || FALLBACK_TYPE, uri: `ipfs://${cid}` }; 81 } 82 83 return { mimeType: file.type || FALLBACK_TYPE, uri: "" }; 84 }) 85 ); 86 87 return attachments; 88 } catch { 89 return []; 90 } 91}; 92 93export const uploadFileToIPFS = async (file: File): Promise<UploadResult> => { 94 try { 95 const ipfsResponse = await uploadToIPFS([file]); 96 const metadata = ipfsResponse[0]; 97 98 return { mimeType: file.type || FALLBACK_TYPE, uri: metadata.uri }; 99 } catch { 100 return { mimeType: file.type || FALLBACK_TYPE, uri: "" }; 101 } 102}; 103 104export default uploadToIPFS;