uppy/examples/aws-nodejs/public/index.html

216 lines
8 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Uppy AWS upload example</title>
<link href="https://releases.transloadit.com/uppy/v3.10.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.10.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, {
// Files that are more than 100MiB should be uploaded in multiple parts.
shouldUseMultipart: (file) => file.size > 100 * MiB,
// ========== 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) {
// 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,
}),
})
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) {
if (signal?.aborted) {
const err = new DOMException('The operation was aborted', 'AbortError')
Object.defineProperty(err, 'cause', { __proto__: null, configurable: true, writable: true, value: signal.reason })
throw err
}
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, { uploadId, key, partNumber, signal }) {
if (signal?.aborted) {
const err = new DOMException('The operation was aborted', 'AbortError')
Object.defineProperty(err, 'cause', { __proto__: null, configurable: true, writable: true, value: signal.reason })
throw err
}
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) {
if (signal?.aborted) {
const err = new DOMException('The operation was aborted', 'AbortError')
Object.defineProperty(err, 'cause', { __proto__: null, configurable: true, writable: true, value: signal.reason })
throw err
}
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) {
if (signal?.aborted) {
const err = new DOMException('The operation was aborted', 'AbortError')
Object.defineProperty(err, 'cause', { __proto__: null, configurable: true, writable: true, value: signal.reason })
throw err
}
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! Weve uploaded these files:', result.successful)
})
uppy.on('upload-success', (file, data) => {
console.log('Upload success! Weve uploaded this file:', file.meta['name'])
})
}
</script>
</body>
</html>