* Upload a file to either S3/Cloudflare R2 or local storage based on configuration * @param file File to upload (can be a GraphQL FileUpload or a Buffer) * @param mimetype File mimetype (required when uploading a Buffer) * @param subdirectory Directory path to store the file in * @return
(
file: FileUpload | Buffer,
mimetype?: string,
subdirectory: string = 'uploads',
)
| 69 | * @returns Promise with the upload result |
| 70 | */ |
| 71 | async upload( |
| 72 | file: FileUpload | Buffer, |
| 73 | mimetype?: string, |
| 74 | subdirectory: string = 'uploads', |
| 75 | ): Promise<UploadResult> { |
| 76 | // Generate filename |
| 77 | const fileExtension = mimetype?.split('/')[1] || 'jpg'; |
| 78 | const filename = `${uuidv4()}.${fileExtension}`; |
| 79 | const key = `${subdirectory}/${filename}`; |
| 80 | |
| 81 | // Handle different file input types |
| 82 | if (Buffer.isBuffer(file)) { |
| 83 | // Direct buffer upload |
| 84 | if (!mimetype) { |
| 85 | throw new Error('Mimetype is required when uploading a buffer'); |
| 86 | } |
| 87 | |
| 88 | if (this.s3Client) { |
| 89 | // Upload to S3/Cloudflare R2 |
| 90 | await this.s3Client.send( |
| 91 | new PutObjectCommand({ |
| 92 | Bucket: this.configService.s3Config.bucketName, |
| 93 | Key: key, |
| 94 | Body: file, |
| 95 | ContentType: mimetype, |
| 96 | }), |
| 97 | ); |
| 98 | |
| 99 | // Get the appropriate URL for the uploaded file |
| 100 | const bucketUrl = this.getBucketUrl(); |
| 101 | |
| 102 | return { url: path.join(bucketUrl, key), key }; |
| 103 | } else { |
| 104 | // Upload to local storage from buffer |
| 105 | const directory = path.join(this.mediaDir, subdirectory); |
| 106 | if (!existsSync(directory)) { |
| 107 | mkdirSync(directory, { recursive: true }); |
| 108 | } |
| 109 | |
| 110 | const filePath = path.join(directory, filename); |
| 111 | |
| 112 | try { |
| 113 | await fs.promises.writeFile(filePath, file); |
| 114 | return { url: `/media/${key}`, key }; |
| 115 | } catch (error) { |
| 116 | throw new Error(`Failed to upload file: ${error.message}`); |
| 117 | } |
| 118 | } |
| 119 | } else { |
| 120 | // GraphQL FileUpload |
| 121 | const { createReadStream, mimetype: fileMimetype } = await file; |
| 122 | |
| 123 | if (this.s3Client) { |
| 124 | // Convert stream to buffer and upload to S3/Cloudflare R2 |
| 125 | const buffer = await this.streamToBuffer(createReadStream()); |
| 126 | |
| 127 | await this.s3Client.send( |
| 128 | new PutObjectCommand({ |
no test coverage detected