Uppy & Tus - Multiple File Uploads

Hello there, I am working on a course platform and I want the instructors to be able to upload multiple files at once with Uppy.js.

Current Problem: The (resumable) upload of a single file is working fine. My endpoint /api/media/generate-upload-url creates a new file upload at Bunny.net for each file in the Uppy.js Dashboard.

So let’s say I select two files and click upload. What happens is two files are created on Bunny.net (see Screenshot). The upload then proceeds and only the first upload succeeds. In the screenshot you can also see that only the first upload was successful. This is the case every time I select multiple files. What actually works is upload one file and then upload another file (add them seperate on the Uppy Dashboard) but not when I select multiple files.

My Code:

<template>
	<div>
		<Head title="Video Uploader" />
		<Heading class="mb-6">Video Uploader</Heading>
		<Card class="flex flex-col items-center justify-center" style="min-height: 300px">
			<uppy-dashboard :uppy="uppy" :props="dashboardOptions"></uppy-dashboard>
		</Card>
	</div>
</template>

<script>
import Uppy from '@uppy/core';
import Tus from '@uppy/tus';
import { Dashboard } from '@uppy/vue';
import axios from 'axios';

import '@uppy/core/dist/style.css';
import '@uppy/dashboard/dist/style.css';

export default {
	components: {
		UppyDashboard: Dashboard,
	},
	data() {
		return {
			uppy: new Uppy({
				autoProceed: false,
				restrictions: { maxNumberOfFiles: 5 },
			}),
			dashboardOptions: {
				inline: true,
				target: '.DashboardContainer',
				replaceTargetContent: true,
				showProgressDetails: true,
				height: 470,
			},
		};
	},
	mounted() {
		this.uppy.use(Tus, {
			endpoint: 'https://video.bunnycdn.com/tusupload',
			retryDelays: [0, 1000, 3000, 5000]
		});

		this.uppy.on('file-added', (file) => {
			console.log('File added:', file.name);
			this.prepareUpload(file);
		});

		this.uppy.on('upload-success', (file, response) => {
			console.log('Upload complete:', file.name);
		});

		this.uppy.on('upload-error', (file, error, response) => {
			console.error('Upload error:', file.name, error);
		});
	},
	methods: {
		prepareUpload(file) {
			axios.post('/api/media/generate-upload-url', { title: file.name }).then((response) => {
				const tusPlugin = this.uppy.getPlugin('Tus');
				
				tusPlugin.setOptions({
					headers: {
						'AuthorizationSignature': response.data.signature,
						'AuthorizationExpire': response.data.expirationTime,
						'VideoId': response.data.guid,
						'LibraryId': response.data.libraryId,
					}
				});

				this.uppy.setFileMeta(file.id, {
					filetype: file.type,
					title: file.name
				});

				// this.uppy.upload([file.id]);
			}).catch((error) => {
				console.error('Error fetching upload URL:', error);
			});
		},
	},
	beforeDestroy() {
		this.uppy.close();
	}
}
</script>

<style scoped>
.DashboardContainer {
	margin-top: 20px;
}
</style>

Thanks in advance for your help guys!

Hi, I would suggest keeping everything in one place instead of spreading it over data, mounted, and methods.

Then something like this probably works best:

import Uppy from "@uppy/core";
import Tus from "@uppy/tus";

let token = null;

async function getAuthToken() {
  const res = await fetch("/auth/token");
  const json = await res.json();
  return json.token;
}

new Uppy().use(Tus, {
  endpoint: "<your-endpoint>",
  // Called again for every retry too.
  async onBeforeRequest(req) {
    if (!token) {
      token = await getAuthToken();
    }
    req.setHeader("Authorization", `Bearer ${token}`);
  },
  async onAfterResponse(req, res) {
    if (res.getStatus() === 401) {
      token = await getAuthToken();
    }
  },
});