You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
3.1 KiB
101 lines
3.1 KiB
/** |
|
* Service for fetching user's preferred relays from their inbox/outbox |
|
*/ |
|
|
|
import { NostrClient } from './nostr-client.js'; |
|
import type { NostrEvent } from '../../types/nostr.js'; |
|
import { KIND } from '../../types/nostr.js'; |
|
import logger from '../logger.js'; |
|
import { truncatePubkey } from '../../utils/security.js'; |
|
|
|
export async function getUserRelays( |
|
pubkey: string, |
|
nostrClient: NostrClient |
|
): Promise<{ inbox: string[]; outbox: string[] }> { |
|
const inbox: string[] = []; |
|
const outbox: string[] = []; |
|
|
|
try { |
|
// Fetch kind 10002 (relay list) - get multiple to find the newest |
|
// Use a higher limit to ensure we get all relay list events |
|
const relayListEvents = await nostrClient.fetchEvents([ |
|
{ |
|
kinds: [KIND.RELAY_LIST], |
|
authors: [pubkey], |
|
limit: 20 // Get more events to ensure we find the newest |
|
} |
|
]); |
|
|
|
logger.debug({ |
|
pubkey: truncatePubkey(pubkey), |
|
eventCount: relayListEvents.length, |
|
eventIds: relayListEvents.map(e => e.id) |
|
}, 'Fetched relay list events'); |
|
|
|
if (relayListEvents.length > 0) { |
|
// Sort by created_at descending to get the newest event first |
|
relayListEvents.sort((a, b) => b.created_at - a.created_at); |
|
const event = relayListEvents[0]; |
|
logger.debug({ |
|
pubkey: truncatePubkey(pubkey), |
|
eventId: event.id, |
|
tagCount: event.tags.length, |
|
createdAt: new Date(event.created_at * 1000).toISOString() |
|
}, 'Found kind 10002 relay list event'); |
|
|
|
for (const tag of event.tags) { |
|
if (tag[0] === 'relay' && tag[1]) { |
|
const relay = tag[1]; |
|
const read = tag[2] !== 'write'; |
|
const write = tag[2] !== 'read'; |
|
|
|
if (read) inbox.push(relay); |
|
if (write) outbox.push(relay); |
|
} |
|
} |
|
|
|
logger.debug({ |
|
pubkey: truncatePubkey(pubkey), |
|
inboxCount: inbox.length, |
|
outboxCount: outbox.length |
|
}, 'Extracted relays from kind 10002 event'); |
|
} else { |
|
logger.debug({ pubkey: truncatePubkey(pubkey) }, 'No kind 10002 relay list events found'); |
|
} |
|
|
|
// Fallback to kind 3 (contacts) for older clients |
|
if (inbox.length === 0 && outbox.length === 0) { |
|
const contactEvents = await nostrClient.fetchEvents([ |
|
{ |
|
kinds: [KIND.CONTACT_LIST], |
|
authors: [pubkey], |
|
limit: 1 |
|
} |
|
]); |
|
|
|
if (contactEvents.length > 0) { |
|
const event = contactEvents[0]; |
|
// Extract relays from content (JSON) or tags |
|
try { |
|
const content = JSON.parse(event.content); |
|
if (content.relays && Array.isArray(content.relays)) { |
|
inbox.push(...content.relays); |
|
outbox.push(...content.relays); |
|
} |
|
} catch { |
|
// Not JSON, check tags |
|
for (const tag of event.tags) { |
|
if (tag[0] === 'relay' && tag[1]) { |
|
inbox.push(tag[1]); |
|
outbox.push(tag[1]); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} catch (error) { |
|
logger.error({ error, pubkey: truncatePubkey(pubkey) }, 'Failed to fetch user relays'); |
|
} |
|
|
|
return { inbox, outbox }; |
|
} |