@@ -4,32 +4,44 @@ import { ApiError } from './apiError'
44
55type MulterFile = Express . Multer . File
66
7+ function extractFilePathAndNameFromUrl ( fileUrl : string ) : { filePath : string , fileName : string } {
8+ try {
9+ const url = new URL ( fileUrl )
10+ const pathParts = url . pathname . split ( '/' ) // ['', 'storage', 'v1', 'object', 'public', 'images', ...filePathParts]
11+ const filePath = pathParts . slice ( 6 ) . join ( '/' ) // 'images/...'
12+ if ( ! filePath ) throw new Error ( 'Invalid file URL' )
13+ const fileName = filePath . split ( '/' ) . pop ( ) || ''
14+ return { filePath, fileName }
15+ } catch {
16+ throw new ApiError ( 'Invalid file URL' , 400 )
17+ }
18+ }
19+
20+
721export async function uploadImage (
822 supabase : SupabaseClient ,
923 file : MulterFile ,
10- folder : string ,
11- fileName ?: string
24+ folder : string ,
25+ fileUrl ?: string
1226) : Promise < string > {
13- // 1) Determine file extension
14- const mime = file . mimetype // e.g. 'image/jpeg'
15- if ( ! mime ) {
16- throw new ApiError ( 'File type is missing' , 400 )
17- }
18- // Validate MIME type against allowed image types
19- const allowedTypes = [ 'image/jpeg' , 'image/png' , 'image/gif' , 'image/webp' ]
20- if ( ! allowedTypes . includes ( mime ) ) {
21- throw new ApiError ( 'Invalid file type. Only JPEG, PNG, GIF, and WebP images are allowed.' , 400 )
22- }
23-
27+ const mime = file . mimetype
28+ if ( ! mime ) throw new ApiError ( 'File type is missing' , 400 )
29+ const allowedTypes = [ 'image/jpeg' , 'image/png' , 'image/gif' , 'image/webp' ]
30+ if ( ! allowedTypes . includes ( mime ) ) {
31+ throw new ApiError ( 'Invalid file type. Only JPEG, PNG, GIF, and WebP images are allowed.' , 400 )
32+ }
2433 const ext = mime . split ( '/' ) [ 1 ]
2534
26- // 2) Create filename
27- const filename = fileName ? fileName : `${ uuidv4 ( ) } .${ ext } `
35+ let filename : string
36+ if ( fileUrl ) {
37+ const { fileName } = extractFilePathAndNameFromUrl ( fileUrl )
38+ filename = fileName
39+ } else {
40+ filename = `${ uuidv4 ( ) } .${ ext } `
41+ }
2842
29- // 3) Build full path inside the bucket
3043 const filePath = `${ folder } /${ filename } `
3144
32- // 4) Perform the upload (upsert: true will overwrite same path if it exists)
3345 const { error : uploadError } = await supabase
3446 . storage
3547 . from ( 'images' )
@@ -42,7 +54,6 @@ const filename = fileName ? fileName : `${uuidv4()}.${ext}`
4254 throw new ApiError ( `Image upload failed: ${ uploadError . message } ` , 500 )
4355 }
4456
45- // 5) Generate a public URL
4657 const { data : urlData } = supabase
4758 . storage
4859 . from ( 'images' )
@@ -59,9 +70,7 @@ export async function deleteImage(
5970 supabase : SupabaseClient ,
6071 fileUrl : string
6172) : Promise < void > {
62- const url = new URL ( fileUrl ) ;
63- const pathParts = url . pathname . split ( '/' ) ; // ['', 'storage', 'v1', 'object', 'public', 'images', ...filePathParts]
64- const filePath = pathParts . slice ( 6 ) . join ( '/' ) ; // 'images/...'
73+ const { filePath } = extractFilePathAndNameFromUrl ( fileUrl )
6574 if ( ! filePath ) {
6675 throw new ApiError ( 'Invalid file URL' , 400 )
6776 }
0 commit comments