@@ -17,12 +17,17 @@ import { defaultPartition } from '../regions/regionProvider'
1717import { AsyncCollection , toCollection } from '../utilities/asyncCollection'
1818import { toStream } from '../utilities/collectionUtils'
1919import {
20+ _Object ,
2021 BucketLocationConstraint ,
2122 CreateBucketCommand ,
2223 DeleteBucketCommand ,
2324 GetObjectCommand ,
2425 GetObjectCommandInput ,
2526 GetObjectCommandOutput ,
27+ HeadObjectCommand ,
28+ HeadObjectOutput ,
29+ ListObjectsV2Command ,
30+ ListObjectsV2Output ,
2631 PutObjectCommand ,
2732 S3Client as S3ClientSDK ,
2833} from '@aws-sdk/client-s3'
@@ -274,7 +279,7 @@ export class S3Client extends ClientWrapper<S3ClientSDK> {
274279 */
275280 public async downloadFileStream ( bucketName : string , key : string ) : Promise < Readable > {
276281 // GetObject response body is now a `StreamingBlobPayloadOutputTypes` from @smithy/types.
277- // this is a general type for web/node streams, therefore we must cast the nodes streaming type.
282+ // this is a general type for web/node streams, therefore we must cast to nodes streaming type.
278283 const response = await this . makeRequest < GetObjectCommandInput , GetObjectCommandOutput , GetObjectCommand > (
279284 GetObjectCommand ,
280285 {
@@ -290,10 +295,9 @@ export class S3Client extends ClientWrapper<S3ClientSDK> {
290295 return ( response . Body as Readable ) ?? new Readable ( )
291296 }
292297
293- public async headObject ( request : HeadObjectRequest ) : Promise < S3 . HeadObjectOutput > {
294- const s3 = await this . createS3 ( )
298+ public async headObject ( request : HeadObjectRequest ) : Promise < HeadObjectOutput > {
295299 getLogger ( ) . debug ( 'HeadObject called with request: %O' , request )
296- return s3 . headObject ( { Bucket : request . bucketName , Key : request . key } ) . promise ( )
300+ return this . makeRequest ( HeadObjectCommand , { Bucket : request . bucketName , Key : request . key } )
297301 }
298302
299303 /**
@@ -441,6 +445,63 @@ export class S3Client extends ClientWrapper<S3ClientSDK> {
441445 return { buckets : bucketsInRegion }
442446 }
443447
448+ private async listObjectsV2 ( request : ListFilesRequest ) : Promise < ListObjectsV2Output > {
449+ return await this . makeRequest ( ListObjectsV2Command , {
450+ Bucket : request . bucketName ,
451+ Delimiter : DEFAULT_DELIMITER ,
452+ MaxKeys : request . maxResults ?? DEFAULT_MAX_KEYS ,
453+ /**
454+ * Set '' as the default prefix to ensure that the bucket's content will be displayed
455+ * when the user has at least list access to the root of the bucket
456+ * https://github.com/aws/aws-toolkit-vscode/issues/4643
457+ * @default ''
458+ */
459+ Prefix : request . folderPath ?? defaultPrefix ,
460+ ContinuationToken : request . continuationToken ,
461+ } )
462+ }
463+
464+ private extractFilesFromResponse (
465+ listObjectsRsp : ListObjectsV2Output ,
466+ bucketName : string ,
467+ folderPath : string | undefined
468+ ) : File [ ] {
469+ const bucket = new DefaultBucket ( {
470+ partitionId : this . partitionId ,
471+ region : this . regionCode ,
472+ name : bucketName ,
473+ } )
474+ return _ ( listObjectsRsp . Contents )
475+ . reject ( ( file ) => file . Key === folderPath )
476+ . map ( ( file ) => {
477+ assertHasProps ( file , 'Key' )
478+ return toFile ( bucket , file )
479+ } )
480+ . value ( )
481+ }
482+
483+ private extractFoldersFromResponse ( listObjectsRsp : ListObjectsV2Output , bucketName : string ) : Folder [ ] {
484+ return _ ( listObjectsRsp . CommonPrefixes )
485+ . map ( ( prefix ) => prefix . Prefix )
486+ . compact ( )
487+ . map ( ( path ) => new DefaultFolder ( { path, partitionId : this . partitionId , bucketName } ) )
488+ . value ( )
489+ }
490+
491+ public listFilesFromResponse (
492+ listObjectsRsp : ListObjectsV2Output ,
493+ bucketName : string ,
494+ folderPath : string | undefined
495+ ) {
496+ const files = this . extractFilesFromResponse ( listObjectsRsp , bucketName , folderPath )
497+ const folders = this . extractFoldersFromResponse ( listObjectsRsp , bucketName )
498+ return {
499+ files,
500+ folders,
501+ continuationToken : listObjectsRsp . NextContinuationToken ,
502+ }
503+ }
504+
444505 /**
445506 * Lists files and folders in a folder or inside the bucket root.
446507 *
@@ -463,48 +524,9 @@ export class S3Client extends ClientWrapper<S3ClientSDK> {
463524 */
464525 public async listFiles ( request : ListFilesRequest ) : Promise < ListFilesResponse > {
465526 getLogger ( ) . debug ( 'ListFiles called with request: %O' , request )
527+ const output = await this . listObjectsV2 ( request )
528+ const response = this . listFilesFromResponse ( output , request . bucketName , request . folderPath )
466529
467- const s3 = await this . createS3 ( )
468- const bucket = new DefaultBucket ( {
469- partitionId : this . partitionId ,
470- region : this . regionCode ,
471- name : request . bucketName ,
472- } )
473- const output = await s3
474- . listObjectsV2 ( {
475- Bucket : bucket . name ,
476- Delimiter : DEFAULT_DELIMITER ,
477- MaxKeys : request . maxResults ?? DEFAULT_MAX_KEYS ,
478- /**
479- * Set '' as the default prefix to ensure that the bucket's content will be displayed
480- * when the user has at least list access to the root of the bucket
481- * https://github.com/aws/aws-toolkit-vscode/issues/4643
482- * @default ''
483- */
484- Prefix : request . folderPath ?? defaultPrefix ,
485- ContinuationToken : request . continuationToken ,
486- } )
487- . promise ( )
488-
489- const files : File [ ] = _ ( output . Contents )
490- . reject ( ( file ) => file . Key === request . folderPath )
491- . map ( ( file ) => {
492- assertHasProps ( file , 'Key' )
493- return toFile ( bucket , file )
494- } )
495- . value ( )
496-
497- const folders : Folder [ ] = _ ( output . CommonPrefixes )
498- . map ( ( prefix ) => prefix . Prefix )
499- . compact ( )
500- . map ( ( path ) => new DefaultFolder ( { path, partitionId : this . partitionId , bucketName : request . bucketName } ) )
501- . value ( )
502-
503- const response : ListFilesResponse = {
504- files,
505- folders,
506- continuationToken : output . NextContinuationToken ,
507- }
508530 getLogger ( ) . debug ( 'ListFiles returned response: %O' , response )
509531 return response
510532 }
@@ -717,7 +739,7 @@ export class DefaultFolder {
717739 }
718740}
719741
720- export interface File extends S3 . Object , S3 . HeadObjectOutput {
742+ export interface File extends _Object , HeadObjectOutput {
721743 readonly name : string
722744 readonly key : string
723745 readonly arn : string
@@ -726,7 +748,7 @@ export interface File extends S3.Object, S3.HeadObjectOutput {
726748 readonly eTag ?: string
727749}
728750
729- export function toFile ( bucket : Bucket , resp : RequiredProps < S3 . Object , 'Key' > , delimiter = DEFAULT_DELIMITER ) : File {
751+ export function toFile ( bucket : Bucket , resp : RequiredProps < _Object , 'Key' > , delimiter = DEFAULT_DELIMITER ) : File {
730752 return {
731753 key : resp . Key ,
732754 arn : `${ bucket . arn } /${ resp . Key } ` ,
0 commit comments