diff --git a/components/ProfileView.tsx b/components/ProfileView.tsx
index b93f96f..f476fe8 100644
--- a/components/ProfileView.tsx
+++ b/components/ProfileView.tsx
@@ -76,10 +76,15 @@ function ProfileHeaderSection({
return (
<>
- {loadingProfile ? (
-
- ) : profile !== null && profile !== undefined ? (
-
+ {(() => {
+ if (loadingProfile) {
+ return
+ }
+ if (profile !== null && profile !== undefined) {
+ return
+ }
+ return null
+ })()}
) : null}
>
)
diff --git a/lib/platformSync.ts b/lib/platformSync.ts
index 5b5e5cb..901a4b1 100644
--- a/lib/platformSync.ts
+++ b/lib/platformSync.ts
@@ -43,11 +43,15 @@ class PlatformSyncService {
const { relaySessionManager } = await import('./relaySessionManager')
const activeRelays = await relaySessionManager.getActiveRelays()
const initialRelay = activeRelays[0] ?? 'Connecting...'
- syncProgressManager.setProgress({ currentStep: 0, totalSteps: 1, completed: false, currentRelay: initialRelay })
+ const totalRelays = activeRelays.length || 1
+ syncProgressManager.setProgress({ currentStep: 0, totalSteps: totalRelays, completed: false, currentRelay: initialRelay })
try {
await this.performSync(pool as unknown as SimplePoolWithSub)
- syncProgressManager.setProgress({ currentStep: 1, totalSteps: 1, completed: true, currentRelay: initialRelay })
+
+ // Mark as completed after all relays are processed
+ const finalRelay = activeRelays[activeRelays.length - 1] ?? initialRelay
+ syncProgressManager.setProgress({ currentStep: totalRelays, totalSteps: totalRelays, completed: true, currentRelay: finalRelay })
} catch (error) {
console.error('Error in platform sync:', error)
syncProgressManager.setProgress(null)
@@ -62,7 +66,7 @@ class PlatformSyncService {
/**
* Perform a sync operation
- * Scans all notes with service='zapwall.fr' tag
+ * Scans all notes with service='zapwall.fr' tag from ALL active relays
*/
private async performSync(pool: SimplePoolWithSub): Promise {
const filters = [
@@ -75,71 +79,109 @@ class PlatformSyncService {
},
]
- // Use relay rotation for platform sync
- const { tryWithRelayRotation } = await import('./relayRotation')
+ const { relaySessionManager } = await import('./relaySessionManager')
const { syncProgressManager } = await import('./syncProgressManager')
+ const activeRelays = await relaySessionManager.getActiveRelays()
- return tryWithRelayRotation(
- pool as unknown as import('nostr-tools').SimplePool,
- async (relayUrl, poolWithSub) => {
- // Update progress with current relay
- const currentProgress = syncProgressManager.getProgress()
- if (currentProgress) {
- syncProgressManager.setProgress({
- ...currentProgress,
- currentRelay: relayUrl,
- })
- }
+ if (activeRelays.length === 0) {
+ throw new Error('No active relays available')
+ }
+
+ const allEvents: Event[] = []
+ const processedEventIds = new Set()
+
+ // Synchronize from all active relays
+ for (let i = 0; i < activeRelays.length; i++) {
+ const relayUrl = activeRelays[i]
+ if (!relayUrl) {
+ continue
+ }
+
+ // Update progress with current relay
+ syncProgressManager.setProgress({
+ currentStep: 0,
+ totalSteps: activeRelays.length,
+ completed: false,
+ currentRelay: relayUrl,
+ })
+
+ try {
+ console.log(`[PlatformSync] Synchronizing from relay ${i + 1}/${activeRelays.length}: ${relayUrl}`)
const { createSubscription } = require('@/types/nostr-tools-extended')
- const sub = createSubscription(poolWithSub, [relayUrl], filters)
+ const sub = createSubscription(pool, [relayUrl], filters)
- const events: Event[] = []
+ const relayEvents: Event[] = []
let resolved = false
- const finalize = async (): Promise => {
+ const finalize = (): void => {
if (resolved) {
return
}
resolved = true
sub.unsub()
- this.syncSubscription = null
- // Process all events and cache them
- await this.processAndCacheEvents(events)
+ // Deduplicate events by ID before adding to allEvents
+ for (const event of relayEvents) {
+ if (!processedEventIds.has(event.id)) {
+ processedEventIds.add(event.id)
+ allEvents.push(event)
+ }
+ }
- this.lastSyncTime = Date.now()
+ console.log(`[PlatformSync] Relay ${relayUrl} completed, received ${relayEvents.length} events`)
}
- return new Promise((resolve) => {
+ await new Promise((resolve) => {
sub.on('event', (event: Event): void => {
// Only process events with service='zapwall.fr'
const tags = extractTagsFromEvent(event)
if (tags.service === PLATFORM_SERVICE) {
- events.push(event)
+ relayEvents.push(event)
}
})
sub.on('eose', (): void => {
- void (async (): Promise => {
- await finalize()
- resolve()
- })()
+ finalize()
+ resolve()
})
// Timeout after SYNC_TIMEOUT_MS
setTimeout((): void => {
- void (async (): Promise => {
- await finalize()
- resolve()
- })()
+ finalize()
+ resolve()
}, this.SYNC_TIMEOUT_MS).unref?.()
this.syncSubscription = sub
})
- },
- 30000 // 30 second timeout per relay
- )
+
+ // Update progress after each relay
+ syncProgressManager.setProgress({
+ currentStep: i + 1,
+ totalSteps: activeRelays.length,
+ completed: false,
+ currentRelay: relayUrl,
+ })
+ } catch (error) {
+ const errorMessage = error instanceof Error ? error.message : String(error)
+ console.warn(`[PlatformSync] Relay ${relayUrl} failed: ${errorMessage}`)
+ // Mark relay as failed but continue with next relay
+ relaySessionManager.markRelayFailed(relayUrl)
+ // Update progress even on failure
+ syncProgressManager.setProgress({
+ currentStep: i + 1,
+ totalSteps: activeRelays.length,
+ completed: false,
+ currentRelay: relayUrl,
+ })
+ }
+ }
+
+ // Process all collected events
+ await this.processAndCacheEvents(allEvents)
+ console.log(`[PlatformSync] Total events collected from all relays: ${allEvents.length}`)
+
+ this.lastSyncTime = Date.now()
}
/**
diff --git a/lib/zapRequestBuilder.ts b/lib/zapRequestBuilder.ts
index d81013a..8be3566 100644
--- a/lib/zapRequestBuilder.ts
+++ b/lib/zapRequestBuilder.ts
@@ -6,7 +6,15 @@ import type { Article } from '@/types/nostr'
* These tags will be included in the zap receipt (kind 9735) by the Lightning wallet
*/
export function buildPurchaseZapRequestTags(article: Article): string[][] {
- const category = article.category === 'science-fiction' ? 'sciencefiction' : article.category === 'scientific-research' ? 'research' : 'sciencefiction'
+ const category = (() => {
+ if (article.category === 'science-fiction') {
+ return 'sciencefiction'
+ }
+ if (article.category === 'scientific-research') {
+ return 'research'
+ }
+ return 'sciencefiction'
+ })()
return [
['kind_type', 'purchase'],
@@ -30,7 +38,15 @@ export function buildReviewTipZapRequestTags(params: {
seriesId?: string
text?: string
}): string[][] {
- const category = params.category === 'science-fiction' ? 'sciencefiction' : params.category === 'scientific-research' ? 'research' : 'sciencefiction'
+ const category = (() => {
+ if (params.category === 'science-fiction') {
+ return 'sciencefiction'
+ }
+ if (params.category === 'scientific-research') {
+ return 'research'
+ }
+ return 'sciencefiction'
+ })()
return [
['kind_type', 'review_tip'],
@@ -55,7 +71,15 @@ export function buildSponsoringZapRequestTags(params: {
articleId?: string
text?: string
}): string[][] {
- const category = params.category === 'science-fiction' ? 'sciencefiction' : params.category === 'scientific-research' ? 'research' : 'sciencefiction'
+ const category = (() => {
+ if (params.category === 'science-fiction') {
+ return 'sciencefiction'
+ }
+ if (params.category === 'scientific-research') {
+ return 'research'
+ }
+ return 'sciencefiction'
+ })()
return [
['kind_type', 'sponsoring'],