2025-12-23 02:20:57 +01:00

64 lines
1.8 KiB
TypeScript

import type { MediaRef } from '@/types/nostr'
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<MediaRef> {
assertBrowser()
const mediaType = validateFile(file)
const endpoint = process.env.NEXT_PUBLIC_NIP95_UPLOAD_URL
if (!endpoint) {
throw new Error('NIP-95 upload endpoint is not configured')
}
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 }
}