import type { MediaRef } from '@/types/nostr' import { getPrimaryNip95Api } from './config' const MAX_IMAGE_BYTES = 5 * 1024 * 1024 const MAX_VIDEO_BYTES = 45 * 1024 * 1024 const IMAGE_TYPES = ['image/png', 'image/jpeg', 'image/jpg', 'image/webp'] const VIDEO_TYPES = ['video/mp4', 'video/webm', 'video/quicktime'] function assertBrowser(): void { if (typeof window === 'undefined') { throw new Error('NIP-95 upload is only available in the browser') } } function validateFile(file: File): MediaRef['type'] { if (IMAGE_TYPES.includes(file.type)) { if (file.size > MAX_IMAGE_BYTES) { throw new Error('Image exceeds 5MB limit') } return 'image' } if (VIDEO_TYPES.includes(file.type)) { if (file.size > MAX_VIDEO_BYTES) { throw new Error('Video exceeds 45MB limit') } return 'video' } throw new Error('Unsupported media type') } /** * Upload media via NIP-95. * This implementation validates size/type then delegates to a pluggable uploader. * The actual upload endpoint must be provided via env/config; otherwise an error is thrown. */ export async function uploadNip95Media(file: File): Promise { assertBrowser() const mediaType = validateFile(file) const endpoint = await getPrimaryNip95Api() if (!endpoint) { throw new Error( 'NIP-95 upload endpoint is not configured. Please configure a NIP-95 API endpoint in the application settings.' ) } const formData = new FormData() formData.append('file', file) let response: Response try { response = await fetch(endpoint, { method: 'POST', body: formData, }) } catch (e) { const errorMessage = e instanceof Error ? e.message : 'Network error' console.error('NIP-95 upload fetch error:', { endpoint, error: errorMessage, fileSize: file.size, fileType: file.type, }) throw new Error(`Failed to fetch upload endpoint: ${errorMessage}`) } if (!response.ok) { let errorMessage = 'Upload failed' try { const text = await response.text() errorMessage = text || `HTTP ${response.status} ${response.statusText}` } catch (_e) { errorMessage = `HTTP ${response.status} ${response.statusText}` } console.error('NIP-95 upload response error:', { endpoint, status: response.status, statusText: response.statusText, errorMessage, fileSize: file.size, fileType: file.type, }) throw new Error(errorMessage) } let result: { url?: string } try { result = (await response.json()) as { url?: string } } catch (e) { const errorMessage = e instanceof Error ? e.message : 'Invalid JSON response' console.error('NIP-95 upload JSON parse error:', { endpoint, error: errorMessage, status: response.status, }) throw new Error(`Invalid upload response: ${errorMessage}`) } if (!result.url) { console.error('NIP-95 upload missing URL:', { endpoint, response: result, }) throw new Error('Upload response missing URL') } return { url: result.url, type: mediaType } }