Skip to content

Instantly share code, notes, and snippets.

@officialrobert
Created May 5, 2024 01:32
Show Gist options
  • Save officialrobert/fe2e4a96c16463b8ed2304e9b3f54c07 to your computer and use it in GitHub Desktop.
Save officialrobert/fe2e4a96c16463b8ed2304e9b3f54c07 to your computer and use it in GitHub Desktop.
How to do resumable upload using supabase storage
import { Upload } from 'tus-js-client';
import { isEmpty, head } from 'lodash';
function uploadFile(
file: File,
accessToken: string,
bucketName: string,
fileName: string,
contentType: string,
folder?: string
): Promise<{ url: string; name: string } | null> {
return new Promise((resolve, reject) => {
const supabaseProjectId = 'your-project-id';
const publicAuthFilesFolder = 'public-folder';
const filePath = `${
!isEmpty(folder) ? folder : publicAuthFilesFolder
}/${fileName}`;
const upload = new Upload(file, {
endpoint: `https://${supabaseProjectId}.supabase.co/storage/v1/upload/resumable`,
retryDelays: [0, 3000, 5000, 10000, 20000],
headers: {
apikey: supabasePublicKey, // API key from supabase settings
authorization: `Bearer ${accessToken}`, // Auth required because I have RLS enabled for this folder
'x-upsert': 'true', // optionally set upsert to true to overwrite existing files
},
uploadDataDuringCreation: true,
removeFingerprintOnSuccess: true, // Important if you want to allow re-uploading the same file https://github.com/tus/tus-js-client/blob/main/docs/api.md#removefingerprintonsuccess
metadata: {
...(!isEmpty(contentType) && { contentType }),
bucketName: bucketName,
objectName: filePath,
cacheControl: '3600',
},
chunkSize: 6 * 1024 * 1024, // NOTE: it must be set to 6MB (for now) do not change it
onError: function (error) {
console.log('Failed because: ' + error);
reject(error);
},
onProgress: function (bytesUploaded, bytesTotal) {
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
console.log(bytesUploaded, bytesTotal, percentage + '%');
},
onSuccess: function () {
// @ts-ignore
const fileName = upload.file?.name || '';
const url = upload?.url;
if (url) {
const { data: urlData } = supabaseClient.storage
.from(bucketName)
.getPublicUrl(`${filePath}`);
const publicUrl = urlData?.publicUrl || '';
console.log('onSuccess() publicUrl:', publicUrl);
resolve({
url: publicUrl,
name: fileName,
});
}
resolve(null);
},
});
// Check if there are any previous uploads to continue.
return upload.findPreviousUploads().then(function (previousUploads) {
// Found previous uploads so we select the first one.
if (previousUploads.length) {
upload.resumeFromPreviousUpload(previousUploads[0]);
}
upload.start();
});
});
}
// HOW TO CALL
// Callback handler for <input type='file'/>
const handleFileUpload = async (evt) => {
const file = head(evt?.target?.files);
if (file) {
// await uploadFile(file, ...continue with other params)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment