- **Motivations :** Assurer passage du lint strict et clarifier la logique paiements/publications. - **Root causes :** Fonctions trop longues, promesses non gérées et typages WebLN/Nostr incomplets. - **Correctifs :** Refactor PaymentModal (handlers void), extraction helpers articlePublisher, simplification polling sponsoring/zap, corrections curly et awaits. - **Evolutions :** Nouveau module articlePublisherHelpers pour présentation/aiguillage contenu privé. - **Page affectées :** components/PaymentModal.tsx, lib/articlePublisher.ts, lib/articlePublisherHelpers.ts, lib/paymentPolling.ts, lib/sponsoring.ts, lib/nostrZapVerification.ts et dépendances liées.
110 lines
2.7 KiB
TypeScript
110 lines
2.7 KiB
TypeScript
import type { AlbyInvoice } from '@/types/alby'
|
|
import { storageService } from './storage/indexedDB'
|
|
|
|
interface StoredArticleData {
|
|
content: string
|
|
authorPubkey: string
|
|
articleId: string
|
|
invoice: {
|
|
invoice: string
|
|
paymentHash: string
|
|
amount: number
|
|
expiresAt: number
|
|
} | null
|
|
createdAt: number
|
|
}
|
|
|
|
// Default expiration: 30 days in milliseconds
|
|
const DEFAULT_EXPIRATION = 30 * 24 * 60 * 60 * 1000
|
|
|
|
/**
|
|
* Store private content temporarily until payment is confirmed
|
|
* Also stores the invoice if provided
|
|
* Uses IndexedDB exclusively
|
|
* Content expires after 30 days by default
|
|
*/
|
|
export async function storePrivateContent(
|
|
articleId: string,
|
|
content: string,
|
|
authorPubkey: string,
|
|
invoice?: AlbyInvoice
|
|
): Promise<void> {
|
|
try {
|
|
const key = `article_private_content_${articleId}`
|
|
const data: StoredArticleData = {
|
|
content,
|
|
authorPubkey,
|
|
articleId,
|
|
invoice: invoice
|
|
? {
|
|
invoice: invoice.invoice,
|
|
paymentHash: invoice.paymentHash,
|
|
amount: invoice.amount,
|
|
expiresAt: invoice.expiresAt,
|
|
}
|
|
: null,
|
|
createdAt: Date.now(),
|
|
}
|
|
|
|
// Store with expiration (30 days)
|
|
await storageService.set(key, data, DEFAULT_EXPIRATION)
|
|
} catch (error) {
|
|
console.error('Error storing private content:', error)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get stored private content for an article
|
|
* Returns null if not found or expired
|
|
*/
|
|
export async function getStoredPrivateContent(articleId: string): Promise<{
|
|
content: string
|
|
authorPubkey: string
|
|
invoice?: AlbyInvoice
|
|
} | null> {
|
|
try {
|
|
const key = `article_private_content_${articleId}`
|
|
const data = await storageService.get<StoredArticleData>(key)
|
|
|
|
if (!data) {
|
|
return null
|
|
}
|
|
|
|
return {
|
|
content: data.content,
|
|
authorPubkey: data.authorPubkey,
|
|
invoice: data.invoice
|
|
? {
|
|
invoice: data.invoice.invoice,
|
|
paymentHash: data.invoice.paymentHash,
|
|
amount: data.invoice.amount,
|
|
expiresAt: data.invoice.expiresAt,
|
|
}
|
|
: undefined,
|
|
}
|
|
} catch (error) {
|
|
console.error('Error retrieving private content:', error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get stored invoice for an article
|
|
*/
|
|
export async function getStoredInvoice(articleId: string): Promise<AlbyInvoice | null> {
|
|
const stored = await getStoredPrivateContent(articleId)
|
|
return stored?.invoice ?? null
|
|
}
|
|
|
|
/**
|
|
* Remove stored private content (after successful send or expiry)
|
|
*/
|
|
export async function removeStoredPrivateContent(articleId: string): Promise<void> {
|
|
try {
|
|
const key = `article_private_content_${articleId}`
|
|
await storageService.delete(key)
|
|
} catch (error) {
|
|
console.error('Error removing private content:', error)
|
|
}
|
|
}
|