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) const response = await fetch(endpoint, { method: 'POST', body: formData, }) if (!response.ok) { const message = await response.text().catch(() => 'Upload failed') throw new Error(message || 'Upload failed') } const result = (await response.json()) as { url?: string } if (!result.url) { throw new Error('Upload response missing URL') } return { url: result.url, type: mediaType } }