mirror of
https://github.com/transloadit/uppy.git
synced 2026-07-25 19:23:55 +00:00
| Package | Version | Package | Version | | ---------------------- | ------- | ---------------------- | ------- | | @uppy/box | 2.2.1 | @uppy/onedrive | 3.2.1 | | @uppy/companion-client | 3.7.4 | @uppy/progress-bar | 3.1.0 | | @uppy/core | 3.9.3 | @uppy/provider-views | 3.10.0 | | @uppy/dashboard | 3.7.5 | @uppy/status-bar | 3.3.0 | | @uppy/file-input | 3.1.0 | @uppy/utils | 5.7.4 | | @uppy/form | 3.2.0 | @uppy/xhr-upload | 3.6.4 | | @uppy/image-editor | 2.4.4 | uppy | 3.23.0 | | @uppy/informer | 3.1.0 | | | - @uppy/form: migrate to TS (Merlijn Vos / #4937) - @uppy/box: fetchPreAuthToken in box too (Mikael Finstad / #4969) - @uppy/progress-bar: refactor to TypeScript (Mikael Finstad / #4921) - @uppy/onedrive: fix custom oauth2 credentials for onedrive (Mikael Finstad / #4968) - @uppy/companion-client,@uppy/utils,@uppy/xhr-upload: improvements for #4922 (Mikael Finstad / #4960) - @uppy/utils: fix various type issues (Mikael Finstad / #4958) - @uppy/provider-views: migrate to TS (Merlijn Vos / #4919) - @uppy/utils: simplify `findDOMElements` (Mikael Finstad / #4957) - @uppy/xhr-upload: fix getResponseData regression (Merlijn Vos / #4964) - @uppy/informer: migrate to TS (Merlijn Vos / #4967) - @uppy/core: remove unused import (Antoine du Hamel / #4972) - @uppy/image-editor: remove default target (Merlijn Vos / #4966) - @uppy/angular: Build fixes (Mikael Finstad / #4959) - meta: Fix flaky e2e test (Murderlon) - meta: fix e2e flake (Mikael Finstad / #4961) - meta: add support for `Fragment` short syntax (Antoine du Hamel / #4953) - @uppy/file-input: refactor to TypeScript (Antoine du Hamel / #4954)
267 lines
8.6 KiB
HTML
267 lines
8.6 KiB
HTML
<!doctype html>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<title>Uppy – AWS upload example</title>
|
||
<link
|
||
href="https://releases.transloadit.com/uppy/v3.23.0/uppy.min.css"
|
||
rel="stylesheet"
|
||
/>
|
||
</head>
|
||
<body>
|
||
<h1>AWS upload example</h1>
|
||
<div id="uppy"></div>
|
||
<script type="module">
|
||
import {
|
||
Uppy,
|
||
Dashboard,
|
||
AwsS3,
|
||
} from 'https://releases.transloadit.com/uppy/v3.23.0/uppy.min.mjs'
|
||
/**
|
||
* This generator transforms a deep object into URL-encodable pairs
|
||
* to work with `URLSearchParams` on the client and `body-parser` on the server.
|
||
*/
|
||
function* serializeSubPart(key, value) {
|
||
if (typeof value !== 'object') {
|
||
yield [key, value]
|
||
return
|
||
}
|
||
if (Array.isArray(value)) {
|
||
for (const val of value) {
|
||
yield* serializeSubPart(`${key}[]`, val)
|
||
}
|
||
return
|
||
}
|
||
for (const [subkey, val] of Object.entries(value)) {
|
||
yield* serializeSubPart(key ? `${key}[${subkey}]` : subkey, val)
|
||
}
|
||
}
|
||
function serialize(data) {
|
||
// If you want to avoid preflight requests, use URL-encoded syntax:
|
||
return new URLSearchParams(serializeSubPart(null, data))
|
||
// If you don't care about additional preflight requests, you can also use:
|
||
// return JSON.stringify(data)
|
||
// You'd also have to add `Content-Type` header with value `application/json`.
|
||
}
|
||
{
|
||
const MiB = 0x10_00_00
|
||
|
||
const uppy = new Uppy()
|
||
.use(Dashboard, {
|
||
inline: true,
|
||
target: '#uppy',
|
||
})
|
||
.use(AwsS3, {
|
||
id: 'myAWSPlugin',
|
||
|
||
// Files that are more than 100MiB should be uploaded in multiple parts.
|
||
shouldUseMultipart: (file) => file.size > 100 * MiB,
|
||
|
||
/**
|
||
* This method tells Uppy how to retrieve a temporary token for signing on the client.
|
||
* Signing on the client is optional, you can also do the signing from the server.
|
||
*/
|
||
async getTemporarySecurityCredentials({ signal }) {
|
||
const response = await fetch('/sts', { signal })
|
||
if (!response.ok)
|
||
throw new Error('Unsuccessful request', { cause: response })
|
||
return response.json()
|
||
},
|
||
|
||
// ========== Non-Multipart Uploads ==========
|
||
|
||
/**
|
||
* This method tells Uppy how to handle non-multipart uploads.
|
||
* If for some reason you want to only support multipart uploads,
|
||
* you don't need to implement it.
|
||
*/
|
||
async getUploadParameters(file, options) {
|
||
if (typeof crypto?.subtle === 'object') {
|
||
// If WebCrypto is available, let's do signing from the client.
|
||
return uppy
|
||
.getPlugin('myAWSPlugin')
|
||
.createSignedURL(file, options)
|
||
}
|
||
|
||
// Send a request to our Express.js signing endpoint.
|
||
const response = await fetch('/sign-s3', {
|
||
method: 'POST',
|
||
headers: {
|
||
accept: 'application/json',
|
||
},
|
||
body: serialize({
|
||
filename: file.name,
|
||
contentType: file.type,
|
||
}),
|
||
signal: options.signal,
|
||
})
|
||
|
||
if (!response.ok)
|
||
throw new Error('Unsuccessful request', { cause: response })
|
||
|
||
// Parse the JSON response.
|
||
const data = await response.json()
|
||
|
||
// Return an object in the correct shape.
|
||
return {
|
||
method: data.method,
|
||
url: data.url,
|
||
fields: {}, // For presigned PUT uploads, this should be left empty.
|
||
// Provide content type header required by S3
|
||
headers: {
|
||
'Content-Type': file.type,
|
||
},
|
||
}
|
||
},
|
||
|
||
// ========== Multipart Uploads ==========
|
||
|
||
// The following methods are only useful for multipart uploads:
|
||
// If you are not interested in multipart uploads, you don't need to
|
||
// implement them (you'd also need to set `shouldUseMultipart: false` though).
|
||
|
||
async createMultipartUpload(file, signal) {
|
||
signal?.throwIfAborted()
|
||
|
||
const metadata = {}
|
||
|
||
Object.keys(file.meta || {}).forEach((key) => {
|
||
if (file.meta[key] != null) {
|
||
metadata[key] = file.meta[key].toString()
|
||
}
|
||
})
|
||
|
||
const response = await fetch('/s3/multipart', {
|
||
method: 'POST',
|
||
// Send and receive JSON.
|
||
headers: {
|
||
accept: 'application/json',
|
||
},
|
||
body: serialize({
|
||
filename: file.name,
|
||
type: file.type,
|
||
metadata,
|
||
}),
|
||
signal,
|
||
})
|
||
|
||
if (!response.ok)
|
||
throw new Error('Unsuccessful request', { cause: response })
|
||
|
||
// Parse the JSON response.
|
||
const data = await response.json()
|
||
|
||
return data
|
||
},
|
||
|
||
async abortMultipartUpload(file, { key, uploadId }, signal) {
|
||
const filename = encodeURIComponent(key)
|
||
const uploadIdEnc = encodeURIComponent(uploadId)
|
||
const response = await fetch(
|
||
`/s3/multipart/${uploadIdEnc}?key=${filename}`,
|
||
{
|
||
method: 'DELETE',
|
||
signal,
|
||
},
|
||
)
|
||
|
||
if (!response.ok)
|
||
throw new Error('Unsuccessful request', { cause: response })
|
||
},
|
||
|
||
async signPart(file, options) {
|
||
if (typeof crypto?.subtle === 'object') {
|
||
// If WebCrypto, let's do signing from the client.
|
||
return uppy
|
||
.getPlugin('myAWSPlugin')
|
||
.createSignedURL(file, options)
|
||
}
|
||
|
||
const { uploadId, key, partNumber, signal } = options
|
||
|
||
signal?.throwIfAborted()
|
||
|
||
if (uploadId == null || key == null || partNumber == null) {
|
||
throw new Error(
|
||
'Cannot sign without a key, an uploadId, and a partNumber',
|
||
)
|
||
}
|
||
|
||
const filename = encodeURIComponent(key)
|
||
const response = await fetch(
|
||
`/s3/multipart/${uploadId}/${partNumber}?key=${filename}`,
|
||
{ signal },
|
||
)
|
||
|
||
if (!response.ok)
|
||
throw new Error('Unsuccessful request', { cause: response })
|
||
|
||
const data = await response.json()
|
||
|
||
return data
|
||
},
|
||
|
||
async listParts(file, { key, uploadId }, signal) {
|
||
signal?.throwIfAborted()
|
||
|
||
const filename = encodeURIComponent(key)
|
||
const response = await fetch(
|
||
`/s3/multipart/${uploadId}?key=${filename}`,
|
||
{ signal },
|
||
)
|
||
|
||
if (!response.ok)
|
||
throw new Error('Unsuccessful request', { cause: response })
|
||
|
||
const data = await response.json()
|
||
|
||
return data
|
||
},
|
||
|
||
async completeMultipartUpload(
|
||
file,
|
||
{ key, uploadId, parts },
|
||
signal,
|
||
) {
|
||
signal?.throwIfAborted()
|
||
|
||
const filename = encodeURIComponent(key)
|
||
const uploadIdEnc = encodeURIComponent(uploadId)
|
||
const response = await fetch(
|
||
`s3/multipart/${uploadIdEnc}/complete?key=${filename}`,
|
||
{
|
||
method: 'POST',
|
||
headers: {
|
||
accept: 'application/json',
|
||
},
|
||
body: serialize({ parts }),
|
||
signal,
|
||
},
|
||
)
|
||
|
||
if (!response.ok)
|
||
throw new Error('Unsuccessful request', { cause: response })
|
||
|
||
const data = await response.json()
|
||
|
||
return data
|
||
},
|
||
})
|
||
|
||
uppy.on('complete', (result) => {
|
||
console.log(
|
||
'Upload complete! We’ve uploaded these files:',
|
||
result.successful,
|
||
)
|
||
})
|
||
|
||
uppy.on('upload-success', (file, data) => {
|
||
console.log(
|
||
'Upload success! We’ve uploaded this file:',
|
||
file.meta['name'],
|
||
)
|
||
})
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|