'use client'; import * as storage from '@/lib/storage/storage.external'; import { StorageProvider } from '@/lib/storage/storage.interface'; import { wrap } from '@/utils/types/results'; import { z } from 'zod'; export const FileUploadResp = z.object({ signedUrl: z.string(), key: z.string(), }); export type FileUploadResp = z.infer; async function hashFile(file: File): Promise { const buffer = await file.arrayBuffer(); const hashBuffer = await crypto.subtle.digest('SHA-256', buffer); const hex = Array.from(new Uint8Array(hashBuffer)) .map((b) => b.toString(16).padStart(2, '0')) .join(''); const ext = file.name.split('.').pop(); return ext ? `${hex}.${ext}` : hex; } export const uploadFile = wrap(async (file: File) => { const fileKey = await hashFile(file); const existsResult = await storage.checkExists(fileKey); if (existsResult) { const presignedUrl = await storage.getSignedUrl(fileKey); if (!presignedUrl.ok) { throw new Error('Failed to retrieve file URL'); } return { signedUrl: presignedUrl.value, key: fileKey }; } const result = await storage.getPutUrl(fileKey, file.type); if (!result.ok) { throw new Error('File upload failed'); } const response = await fetch(result.value, { method: 'PUT', headers: { 'Content-Type': file.type }, body: file, }); if (!response.ok) { throw new Error('Failed to upload file'); } const presignedUrl = await storage.getSignedUrl(fileKey); if (!presignedUrl.ok) { throw new Error('Failed to retrieve file URL'); } return { signedUrl: presignedUrl.value, key: fileKey }; });