## Upload Files

The `Put` method uploads files into Amazon S3.

It returns a `{key: S3 Object key}` object on success:

```javascript
const result = await Storage.put("test.txt", "Hello");
```


<!-- TODO Rewrite - which is this differently shown? is it just for grabbing pathImageFile? I am confused why this section exists when it is almost a duplicate of the above -->

import js0 from "/src/fragments/lib/storage/js/browser-uploads.mdx";

<Fragments fragments={{js: js0}} />

import reactnative0 from "/src/fragments/lib/storage/js/react-native-uploads.mdx";

<Fragments fragments={{'react-native': reactnative0}} />

When a networking error happens during the upload, Storage module retries upload for a maximum of 4 attempts. If the upload fails after all retries, you will get an error.

### Public level

```javascript
const result = await Storage.put("test.txt", "Hello");
```

### Protected level

```javascript
const result = await Storage.put("test.txt", "Protected Content", {
  level: "protected",
  contentType: "text/plain",
});
```

### Private level

```javascript
const result = await Storage.put("test.txt", "Private Content", {
  level: "private",
  contentType: "text/plain",
});
```

### Monitor progress of upload

To track the progress of your upload, you can use the `progressCallback`:

```javascript
Storage.put("test.txt", "File content", {
  progressCallback(progress) {
    console.log(`Uploaded: ${progress.loaded}/${progress.total}`);
  },
});
```

### Encrypted uploads

To utilize Server-Side Encryption with AWS KMS, the following options can be passed in with the Put API like so:

```javascript
const serverSideEncryption = AES256 | aws:kms;
const SSECustomerAlgorithm = 'string';
const SSECustomerKey = new Buffer('...') || 'string';
const SSECustomerKeyMD5 = 'string';
const SSEKMSKeyId = 'string';

const result = await Storage.put('test.txt', 'File content', {
    serverSideEncryption, SSECustomerAlgorithm, SSECustomerKey, SSECustomerKeyMD5, SSEKMSKeyId
});
```

Other options available are:

```javascript
Storage.put("test.txt", "My Content", {
  cacheControl: "no-cache", // (String) Specifies caching behavior along the request/reply chain
  contentDisposition: "attachment", // (String) Specifies presentational information for the object
  expires: new Date().now() + 60 * 60 * 24 * 7, // (Date) The date and time at which the object is no longer cacheable. ISO-8601 string, or a UNIX timestamp in seconds
  metadata: {key: "value"}, // (map<String>) A map of metadata to store with the object in S3.
  resumable: true, // (Boolean) Allows uploads to be paused and resumed
  useAccelerateEndpoint: true // If enabled on the bucket, use accelerated S3 endpoint
});
```

## Pause and resume uploads

Passing the `resumable: true` option to the Put API returns an object with the following methods: `pause` , `resume`.
The `Storage.cancel` API is also available if you are looking to cancel the upload at any point of the upload.

```javascript
const upload = Storage.put(file.name, file, {
  resumable: true,
});

upload.pause();

upload.resume();

Storage.cancel(upload);
```

<!-- TODO Rewrite why do we not have multi-part upload documented for JS? -->

When a page refresh occurs during the upload, re-initializing the upload with the same file will continue from previous progress point.

```javascript
const upload = Storage.put(file.name, file, {
  resumable: true,
});


// This duplicate uploads will resume the original upload.
const duplicateUpload = Storage.put(file.name, file, {
  resumable: true,
});
```
<Callout>

Uploads that were initiated over one hour ago will be cancelled automatically. There are instances (e.g device went offline, user logs out) where the incomplete file remains in your S3 account. It is recommended to [setup a s3 lifecycle rule](https://aws.amazon.com/blogs/aws-cloud-financial-management/discovering-and-deleting-incomplete-multipart-uploads-to-lower-amazon-s3-costs/) to automatically cleanup incomplete upload requests.

</Callout>

### Event handlers
With the `resumable: true` flag, there are 3 callback functions available: `completeCallback`, `progressCallback` and `errorCallback`.
```javascript
const upload = Storage.put(file.name, file, {
		resumable: true,
		completeCallback: (event) => {
			console.log(`Successfully uploaded ${event.key}`);
		},
		progressCallback: (progress) => {
			console.log(`Uploaded: ${progress.loaded}/${progress.total}`);
		},
		errorCallback: (err) => {
			console.error('Unexpected error while uploading', err);
		}
})
```

<Callout>

Currently, the `progressCallback` event is dependent and based on the number of parts that are sent to S3. Currently, the library uploads at about 5 MB per part. If you upload a file smaller than this, the event will not be fired.

</Callout>
