@@ -11,6 +11,7 @@ const {
1111 HeadBucketCommand,
1212} = require ( '@aws-sdk/client-s3' ) ;
1313const { getSignedUrl } = require ( '@aws-sdk/s3-request-presigner' ) ;
14+ const { Upload } = require ( '@aws-sdk/lib-storage' ) ;
1415const optionsFromArguments = require ( './lib/optionsFromArguments' ) ;
1516
1617const awsCredentialsDeprecationNotice = function awsCredentialsDeprecationNotice ( ) {
@@ -108,6 +109,10 @@ class S3Adapter {
108109 this . _hasBucket = false ;
109110 }
110111
112+ get supportsStreaming ( ) {
113+ return true ;
114+ }
115+
111116 async createBucket ( ) {
112117 if ( this . _hasBucket ) {
113118 return ;
@@ -138,15 +143,12 @@ class S3Adapter {
138143 }
139144 }
140145
141- // For a given config object, filename, and data, store a file in S3
142- // Returns a promise containing the S3 object creation response
143- async createFile ( filename , data , contentType , options = { } ) {
146+ _buildCreateFileParams ( filename , data , contentType , options = { } ) {
144147 const params = {
145148 Bucket : this . _bucket ,
146149 Key : this . _bucketPrefix + filename ,
147150 Body : data ,
148151 } ;
149-
150152 if ( this . _generateKey instanceof Function ) {
151153 params . Key = this . _bucketPrefix + this . _generateKey ( filename ) ;
152154 }
@@ -172,16 +174,39 @@ class S3Adapter {
172174 params . Metadata = options . metadata ;
173175 }
174176 if ( options . tags && typeof options . tags === 'object' ) {
175- const serializedTags = serialize ( options . tags ) ;
176- params . Tagging = serializedTags ;
177+ params . Tagging = serialize ( options . tags ) ;
177178 }
179+ return params ;
180+ }
181+
182+ // For a given config object, filename, and data, store a file in S3
183+ // Returns a promise containing the S3 object creation response
184+ async createFile ( filename , data , contentType , options = { } ) {
185+ const params = this . _buildCreateFileParams ( filename , data , contentType , options ) ;
186+ const endpoint = this . _endpoint || `https://${ this . _bucket } .s3.${ this . _region } .amazonaws.com` ;
187+
188+ // Streaming upload path
189+ if ( typeof data ?. pipe === 'function' ) {
190+ const upload = new Upload ( { client : this . _s3Client , params } ) ;
191+ return new Promise ( ( resolve , reject ) => {
192+ data . on ( 'error' , ( err ) => {
193+ upload . abort ( ) . catch ( ( ) => { } ) ;
194+ reject ( err ) ;
195+ } ) ;
196+ this . createBucket ( )
197+ . then ( ( ) => upload . done ( ) )
198+ . then (
199+ ( response ) => resolve ( Object . assign ( response || { } , { Location : `${ endpoint } /${ params . Key } ` } ) ) ,
200+ reject
201+ ) ;
202+ } ) ;
203+ }
204+
205+ // Buffer upload path
178206 await this . createBucket ( ) ;
179207 const command = new PutObjectCommand ( params ) ;
180208 const response = await this . _s3Client . send ( command ) ;
181- const endpoint = this . _endpoint || `https://${ this . _bucket } .s3.${ this . _region } .amazonaws.com` ;
182- const location = `${ endpoint } /${ params . Key } ` ;
183-
184- return Object . assign ( response || { } , { Location : location } ) ;
209+ return Object . assign ( response || { } , { Location : `${ endpoint } /${ params . Key } ` } ) ;
185210 }
186211
187212 async deleteFile ( filename ) {
0 commit comments