-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathimageUtils.ts
More file actions
83 lines (69 loc) · 2.2 KB
/
imageUtils.ts
File metadata and controls
83 lines (69 loc) · 2.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import { SupabaseClient } from "@supabase/supabase-js";
import { v4 as uuidv4 } from "uuid";
import { ApiError } from "./apiError";
type MulterFile = Express.Multer.File;
function extractFilePathAndNameFromUrl(fileUrl: string): {
filePath: string;
fileName: string;
} {
try {
const url = new URL(fileUrl);
const pathParts = url.pathname.split("/"); // ['', 'storage', 'v1', 'object', 'public', 'images', ...filePathParts]
const filePath = pathParts.slice(6).join("/"); // 'images/...'
if (!filePath) throw new Error("Invalid file URL");
const fileName = filePath.split("/").pop() || "";
return { filePath, fileName };
} catch {
throw new ApiError("Invalid file URL", 400);
}
}
export async function uploadImage(
supabase: SupabaseClient,
file: MulterFile,
folder: string,
fileUrl?: string,
): Promise<string> {
const mime = file.mimetype;
if (!mime) throw new ApiError("File type is missing", 400);
const allowedTypes = ["image/jpeg", "image/png", "image/gif", "image/webp"];
if (!allowedTypes.includes(mime)) {
throw new ApiError(
"Invalid file type. Only JPEG, PNG, GIF, and WebP images are allowed.",
400,
);
}
const ext = mime.split("/")[1];
const filename:string = `${uuidv4()}.${ext}`;
const filePath = `${folder}/${filename}`;
const { error: uploadError } = await supabase.storage
.from("images")
.upload(filePath, file.buffer, {
contentType: file.mimetype,
upsert: true,
});
if (uploadError) {
throw new ApiError(`Image upload failed: ${uploadError.message}`, 500);
}
const { data: urlData } = supabase.storage
.from("images")
.getPublicUrl(filePath);
if (!urlData?.publicUrl) {
throw new ApiError("Failed to get public URL", 500);
}
if (fileUrl) {
await deleteImage(supabase, fileUrl);
}
return urlData.publicUrl;
}
export async function deleteImage(
supabase: SupabaseClient,
fileUrl: string,
): Promise<void> {
const { filePath } = extractFilePathAndNameFromUrl(fileUrl);
const { error: deleteError } = await supabase.storage
.from("images")
.remove([filePath]);
if (deleteError) {
throw new ApiError(`Image deletion failed: ${deleteError.message}`, 500);
}
}