story-research-zapwall/lib/sponsoring.ts
Nicolas Cantu f5d9033183 Refactor to use cache-first architecture with background sync
**Motivations:**
- total_sponsoring should be calculated from cache, not stored in tags
- Author searches should use cache first, not query Nostr directly
- All elements should be read/written from/to database
- Background sync should scan all notes with service='zapwall.fr' tag and update cache
- Sync should run at startup and resume on each page navigation

**Root causes:**
- total_sponsoring was stored in tags which required updates on every sponsoring payment
- Author queries were querying Nostr directly instead of using cache
- No background sync service to keep cache up to date with new notes

**Correctifs:**
- Removed totalSponsoring from AuthorTags interface and buildAuthorTags
- Modified getAuthorSponsoring to calculate from cache (sponsoring queries) instead of tags
- Modified parsePresentationEvent to set totalSponsoring to 0 (calculated on demand from cache)
- Modified fetchAuthorByHashId and fetchAuthorPresentationFromPool to use cache first and calculate totalSponsoring from cache
- Created platformSyncService that scans all notes with service='zapwall.fr' tag and caches them
- Modified _app.tsx to start continuous sync on mount and resume on page navigation
- All author presentations now calculate totalSponsoring from cache when loaded

**Evolutions:**
- Cache-first architecture: all queries check cache before querying Nostr
- Background sync service keeps cache up to date automatically
- totalSponsoring is always calculated from actual sponsoring data in cache
- Better performance: cache queries are faster than Nostr queries
- Non-blocking sync: background sync doesn't block UI

**Pages affectées:**
- lib/nostrTagSystemTypes.ts
- lib/nostrTagSystemBuild.ts
- lib/articlePublisherHelpersPresentation.ts
- lib/sponsoring.ts
- lib/authorQueries.ts
- lib/platformSync.ts (new)
- pages/_app.tsx
2026-01-06 15:04:14 +01:00

45 lines
1.4 KiB
TypeScript

import { getSponsoringByAuthor } from './sponsoringQueries'
import type { Article } from '@/types/nostr'
/**
* Get total sponsoring for an author by their pubkey
* Calculates from cache (sponsoring queries) instead of tags
*/
export async function getAuthorSponsoring(pubkey: string): Promise<number> {
try {
const sponsoringList = await getSponsoringByAuthor(pubkey, 5000)
// Sum all sponsoring amounts for this author
return sponsoringList.reduce((total, sponsoring) => total + sponsoring.amount, 0)
} catch (error) {
console.error('Error calculating author sponsoring from cache:', error)
return 0
}
}
/**
* Get sponsoring for multiple authors (for sorting)
* Returns a map of pubkey -> total sponsoring
*/
export function getAuthorsSponsoring(pubkeys: string[]): Map<string, number> {
const sponsoringMap = new Map<string, number>()
// For now, we'll extract sponsoring from articles that are already loaded
// In a real implementation, we'd query all presentation articles
// For performance, we'll use the sponsoring from the article's totalSponsoring field
pubkeys.forEach((pubkey) => {
sponsoringMap.set(pubkey, 0)
})
return sponsoringMap
}
/**
* Get sponsoring from an article (if it's a presentation article)
*/
export function getSponsoringFromArticle(article: Article): number {
if (article.isPresentation && article.totalSponsoring !== undefined) {
return article.totalSponsoring
}
return 0
}