@@ -13,7 +13,9 @@ import {
1313 UploadPartCopyCommand ,
1414} from '@aws-sdk/client-s3' ;
1515import { NodeHttpHandler } from '@smithy/node-http-handler' ;
16+ import { Upload } from '@aws-sdk/lib-storage' ;
1617import { createReadStream } from 'fs' ;
18+ import { stat } from 'fs/promises' ;
1719import { Agent as HttpAgent } from 'http' ;
1820import { Agent as HttpsAgent } from 'https' ;
1921import { Readable } from 'stream' ;
@@ -168,36 +170,49 @@ export class S3Datasource extends Datasource {
168170 }
169171
170172 public async put ( file : string , data : Buffer | string , options : PutOptions = { } ) : Promise < void > {
171- let command = new PutObjectCommand ( {
172- Bucket : this . options . bucket ,
173- Key : this . key ( file ) ,
174- Body : data ,
175- ...( options . mimetype ? { ContentType : options . mimetype } : { } ) ,
176- } ) ;
173+ try {
174+ if ( typeof data === 'string' ) {
175+ const size = await stat ( data ) . then ( ( file ) => file . size ) ;
176+ if ( size > 25 * 1024 * 1024 ) {
177+ // 25mb
178+ this . logger . debug ( 'putting object with multipart upload' , { file, key : this . key ( file ) } ) ;
179+
180+ try {
181+ const upload = new Upload ( {
182+ client : this . client ,
183+ params : {
184+ Bucket : this . options . bucket ,
185+ Key : this . key ( file ) ,
186+ Body : createReadStream ( data ) ,
187+ ...( options . mimetype ? { ContentType : options . mimetype } : { } ) ,
188+ } ,
189+ leavePartsOnError : false ,
190+ } ) ;
191+
192+ await upload . done ( ) ;
193+ return ;
194+ } catch ( error ) {
195+ this . logger . warn ( 'multipart upload failed, retrying with a single request' , {
196+ error : error instanceof Error ? error . message : error ,
197+ } ) ;
198+ }
199+ }
200+ }
177201
178- if ( typeof data === 'string' ) {
179- const readStream = createReadStream ( data ) ;
180- command = new PutObjectCommand ( {
202+ const command = new PutObjectCommand ( {
181203 Bucket : this . options . bucket ,
182204 Key : this . key ( file ) ,
183- Body : readStream ,
205+ Body : typeof data === 'string' ? createReadStream ( data ) : data ,
184206 ...( options . mimetype ? { ContentType : options . mimetype } : { } ) ,
185207 } ) ;
186-
187- this . logger . debug ( 'putting object from stream' , { file, key : this . key ( file ) } ) ;
188- }
189-
190- try {
191208 const res = await this . client . send ( command ) ;
192209
193210 if ( ! isOk ( res . $metadata . httpStatusCode || 0 ) ) {
194- this . logger . error (
195- 'there was an error while putting object' ,
196- res . $metadata as Record < string , unknown > ,
197- ) ;
211+ throw new Error ( `S3 put failed with status ${ res . $metadata . httpStatusCode ?? 'unknown' } ` ) ;
198212 }
199213 } catch ( e ) {
200214 this . logger . error ( 'there was an error while putting object' , e as Record < string , unknown > ) ;
215+ throw e ;
201216 }
202217 }
203218
0 commit comments