Nicolas Cantu 42e3e7e692 Update all dependencies to latest versions and fix compatibility issues
**Motivations:**
- Keep dependencies up to date for security and features
- Automate dependency updates in deployment script
- Fix compatibility issues with major version updates (React 19, Next.js 16, nostr-tools 2.x)

**Root causes:**
- Dependencies were outdated
- Deployment script did not update dependencies before deploying
- Major version updates introduced breaking API changes

**Correctifs:**
- Updated all dependencies to latest versions using npm-check-updates
- Modified deploy.sh to run npm-check-updates before installing dependencies
- Fixed nostr-tools 2.x API changes (generatePrivateKey -> generateSecretKey, signEvent -> finalizeEvent, verifySignature -> verifyEvent)
- Fixed React 19 ref types to accept null
- Fixed JSX namespace issues (JSX.Element -> React.ReactElement)
- Added proper types for event callbacks
- Fixed SimplePool.sub typing issues with type assertions

**Evolutions:**
- Deployment script now automatically updates dependencies to latest versions before deploying
- All dependencies updated to latest versions (Next.js 14->16, React 18->19, nostr-tools 1->2, etc.)

**Pages affectées:**
- package.json
- deploy.sh
- lib/keyManagement.ts
- lib/nostr.ts
- lib/nostrRemoteSigner.ts
- lib/zapVerification.ts
- lib/platformTrackingEvents.ts
- lib/sponsoringTracking.ts
- lib/articlePublisherHelpersVerification.ts
- lib/contentDeliveryVerification.ts
- lib/paymentPollingZapReceipt.ts
- lib/nostrPrivateMessages.ts
- lib/nostrSubscription.ts
- lib/nostrZapVerification.ts
- lib/markdownRenderer.tsx
- components/AuthorFilter.tsx
- components/AuthorFilterButton.tsx
- components/UserArticlesList.tsx
- types/nostr-tools-extended.ts
2025-12-28 21:49:19 +01:00

109 lines
3.0 KiB
TypeScript

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<MediaRef> {
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 }
}