Skip to content

feat(lib-transfer-manager): add uploadDirectory functionality#8121

Merged
smilkuri merged 5 commits into
mainfrom
feat/directory-transfer
Jun 29, 2026
Merged

feat(lib-transfer-manager): add uploadDirectory functionality#8121
smilkuri merged 5 commits into
mainfrom
feat/directory-transfer

Conversation

@smilkuri

@smilkuri smilkuri commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Issue

Internal JS-6110

Description

Adds uploadDirectory functionality to S3TransferManager for uploading files from a local directory to an S3 bucket.

Testing

yarn test:e2e

Test Files  1 passed (1)
      Tests  37 passed (37)
   Start at  18:36:24
   Duration  273.35s (transform 256ms, setup 0ms, import 448ms, tests 272.77s, environment 0ms)

Checklist

  • If the PR is a feature, add integration tests (*.integ.spec.ts) or E2E tests.
    • It's not a feature.
  • My E2E tests are resilient to concurrent i/o.
    • I didn't write any E2E tests.
  • I added access level annotations e.g. @public, @internal tags and enabled doc generation on the package. Remember that access level annotations go below the description, not above.
    • I didn't add any public functions.
  • Streams - how do they work?? My WebStream readers/locks are properly lifecycled. Node.js stream backpressure is handled. Error handling.
    • No streams here.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@smilkuri
smilkuri requested a review from a team as a code owner June 23, 2026 15:38
@smilkuri
smilkuri force-pushed the feat/directory-transfer branch 3 times, most recently from ca50c40 to a89984e Compare June 25, 2026 14:04
@smilkuri
smilkuri force-pushed the feat/directory-transfer branch from a89984e to d13bff3 Compare June 25, 2026 16:40
@smilkuri smilkuri changed the title WIP feat(lib-transfer-manager): add uploadDirectory functionality feat(lib-transfer-manager): add uploadDirectory functionality Jun 26, 2026
Comment thread lib/lib-transfer-manager/src/submodules/transfer-manager/types.ts Outdated
Comment thread lib/lib-transfer-manager/src/submodules/transfer-manager/types.ts Outdated
* S3 key prefix prepended to each object key.
* By default, if no prefix is specified, objects are uploaded to the root of the bucket.
*/
s3Prefix?: string;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does this one property get named with "s3" as a prefix?

everything in here is S3. This is more like keyPrefix.

@smilkuri smilkuri Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Named it according to the specification.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refer to SEP as "spec" or specification in public

* Return true to include the file for upload, false to skip.
* By default, if no filter is specified, all files will be uploaded.
*/
filter?: (filePath: string) => boolean;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also accept a regex?

* Max concurrent file uploads for this directory operation.
* Default: 100.
*/
maxConcurrency?: number;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this 100? the default MPU doesn't even have 100 concurrency

@smilkuri smilkuri Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was the default specified in the SEP. For file level concurreny, not part-level.But for directories with many large files the memory could be high.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for small files this will call PutObject with file stream input rather than MPU, right?

The memory usage in that case is mostly stream chunk buffers? I think if MPU is triggered by a large file in the directory, it should count more than 1 against the concurrency limit.

@smilkuri
smilkuri force-pushed the feat/directory-transfer branch from 15ee262 to 9afa92d Compare June 26, 2026 16:41
* @internal
*/
export class Semaphore {
private queue: Array<{ weight: number; resolve: () => void }> = [];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Problem I can think of here with FIFO based ordering is if a file needs more slots than available, it will also block the requests behind it which might need a fewer slots. But if we let smaller files go first, it might lead to large files waiting indefinitely.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the semaphore to allow a request to proceed as long as inFlightRequest count is less than concurrency limit.

@smilkuri
smilkuri force-pushed the feat/directory-transfer branch from bd2115b to d0e8007 Compare June 29, 2026 17:54
* Uses fs.opendir with recursive option (Node 20+).
* Handles symlink cycle detection when followSymbolicLinks is true.
*
* @internal

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor issue - private methods don't need the @internal tag.

transferOptions?: TransferOptions;
}): Promise<{ objectsUploaded: number; objectsFailed: number }> {
throw new Error("Method not implemented.");
public async uploadDirectory(request: UploadDirectoryRequest, transferOptions?: TransferOptions): Promise<UploadDirectoryResponse> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this being a method makes TM inherently unusable in browsers, right?

perhaps this method should dispatch to a injectable implementation which throws 'not implemented' in browsers?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, currently upload (threadUploadInParts, threadedUploadInPartsFromFile paths) and uploadAll doesn't have browser support, considering the less no of customers we have that use the SDK in browsers. But will add it later.

@smilkuri
smilkuri merged commit 29b5656 into main Jun 29, 2026
7 checks passed
@trivikr
trivikr deleted the feat/directory-transfer branch July 15, 2026 16:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants