Last active
September 16, 2025 14:25
-
-
Save farzd/017b706337c3b85f642940730a9bf005 to your computer and use it in GitHub Desktop.
Uploadsfailing silently
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // following https://supabase.com/docs/guides/storage/uploads/s3-uploads | |
| // @supabase/supabase-js": "2.49.5-next.1", | |
| // "expo": "^53.0.4" | |
| // please see comment at bottom for more | |
| import supabase, { supabaseAnonKey, supabaseUrl } from "./supabase"; | |
| import { File } from "expo-file-system"; | |
| import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"; | |
| import { Upload } from "@aws-sdk/lib-storage"; | |
| export const uploadAudioToSupabase = async ({ | |
| audioUri, | |
| duration, | |
| onProgress, | |
| }: { | |
| audioUri: string; | |
| duration: any; | |
| onProgress?: (percent: any) => void; | |
| }) => { | |
| try { | |
| const { | |
| data: { session }, | |
| error: sessionError, | |
| } = await supabase.auth.getSession(); | |
| if (sessionError || !session) { | |
| throw new Error("User not authenticated"); | |
| } | |
| // Get file info | |
| const file = new File(audioUri); | |
| if (!file.exists) { | |
| throw new Error("Audio file not found"); | |
| } | |
| const fileSize = typeof file.size === "number" ? file.size : 0; | |
| const fileName = audioUri.split("/").pop(); | |
| const contentType = "audio/mp4"; | |
| // Step 1: Prepare upload | |
| const { data: prepareResult, error: prepareError } = | |
| await supabase.functions.invoke("process-upload-v3", { | |
| body: { | |
| duration: duration, | |
| fileSize: fileSize, | |
| fileName: fileName, | |
| }, | |
| }); | |
| if (prepareError || !prepareResult) { | |
| throw new Error(prepareError?.message || "Failed to upload audio"); | |
| } | |
| const { note_id } = prepareResult; | |
| // Step 2: Use AWS S3 multipart upload against Supabase's S3-compatible endpoint | |
| const s3 = new S3Client({ | |
| forcePathStyle: true, | |
| region: "us-east-1", | |
| endpoint: `${supabaseUrl}/storage/v1/s3`, | |
| credentials: { | |
| accessKeyId: "xyz", | |
| secretAccessKey: supabaseAnonKey, | |
| sessionToken: session.access_token, | |
| }, | |
| }); | |
| const bucket = "recordings"; | |
| const key = `${session.user.id}/${fileName}`; | |
| const MULTIPART_THRESHOLD = 8 * 1024 * 1024; // 8MB | |
| let httpStatus: number | undefined = undefined; | |
| if (fileSize > 0 && fileSize < MULTIPART_THRESHOLD) { | |
| // Small file: direct upload with PutObject | |
| onProgress?.(null); | |
| const uint8 = await file.bytes(); | |
| const uploadCommand = new PutObjectCommand({ | |
| Bucket: bucket, | |
| Key: key, | |
| Body: uint8, | |
| ContentType: contentType, | |
| }); | |
| const res = await s3.send(uploadCommand); | |
| httpStatus = res.$metadata.httpStatusCode; | |
| } else { | |
| try { | |
| // Larger file: multipart upload using lib-storage with progress | |
| const stream = file.stream(); | |
| onProgress?.(10); // Start at 10% to indicate beginning | |
| const uploader = new Upload({ | |
| client: s3, | |
| params: { | |
| Bucket: bucket, | |
| Key: key, | |
| Body: stream, | |
| ContentType: contentType, | |
| ContentLength: fileSize, | |
| }, | |
| queueSize: 3, | |
| partSize: 5 * 1024 * 1024, // 5MB parts | |
| leavePartsOnError: false, | |
| }); | |
| uploader.on("httpUploadProgress", ({ loaded = 0, total }) => { | |
| const base = | |
| typeof total === "number" && total > 0 ? total : fileSize; | |
| if (base && base > 0) { | |
| const percent = Math.min( | |
| 100, | |
| Math.max(0, Math.round((loaded / base) * 100)) | |
| ); | |
| onProgress?.(percent); | |
| } | |
| }); | |
| const res = await uploader.done(); | |
| httpStatus = res.$metadata.httpStatusCode; | |
| } catch (error) { | |
| console.error("Multipart upload failed:", error); | |
| throw new Error(`Multipart upload failed: ${error.message}`); | |
| } | |
| } | |
| if (httpStatus !== 200) { | |
| throw new Error("Failed to upload audio"); | |
| } | |
| return { | |
| success: true, | |
| note_id: note_id, | |
| }; | |
| } catch (error) { | |
| console.error("Failed to upload audio: ", error); | |
| throw error; | |
| } | |
| }; |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just a POST request for this failing file. Smaller files that are uploaded directly, not as multi-part also fail at times. About 10% of uploads silently fail like this.