From 8b02a8dde334d39f5e62ffac64e0a77ee7d36fdd Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Jan 2026 10:49:11 +0000 Subject: [PATCH] feat: improve relay selection for zap requests with e+a tags When both eventPointer and addressPointer are provided: - Collect outbox relays from both semantic authors - Include relay hints from both pointers - Deduplicate and use combined relay set Priority order: 1. Explicit params.relays (respects CLI -r flags) 2. Semantic author outbox relays + pointer relay hints 3. Sender read relays (fallback) 4. Aggregator relays (final fallback) --- src/lib/create-zap-request.ts | 46 ++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/src/lib/create-zap-request.ts b/src/lib/create-zap-request.ts index e69364d..af7c633 100644 --- a/src/lib/create-zap-request.ts +++ b/src/lib/create-zap-request.ts @@ -57,12 +57,50 @@ export async function createZapRequest( } // Get relays for zap receipt publication + // Priority: explicit params.relays > semantic author relays > sender read relays > aggregators let relays = params.relays; if (!relays || relays.length === 0) { - // Use sender's read relays (where they want to receive zap receipts) - const senderReadRelays = - (await relayListCache.getInboxRelays(account.pubkey)) || []; - relays = senderReadRelays.length > 0 ? senderReadRelays : AGGREGATOR_RELAYS; + const collectedRelays: string[] = []; + + // Collect outbox relays from semantic authors (event author and/or addressable event pubkey) + const authorsToQuery: string[] = []; + if (params.eventPointer?.author) { + authorsToQuery.push(params.eventPointer.author); + } + if (params.addressPointer?.pubkey) { + authorsToQuery.push(params.addressPointer.pubkey); + } + + // Deduplicate authors + const uniqueAuthors = [...new Set(authorsToQuery)]; + + // Fetch outbox relays for each author + for (const authorPubkey of uniqueAuthors) { + const authorOutboxes = + (await relayListCache.getOutboxRelays(authorPubkey)) || []; + collectedRelays.push(...authorOutboxes); + } + + // Include relay hints from pointers + if (params.eventPointer?.relays) { + collectedRelays.push(...params.eventPointer.relays); + } + if (params.addressPointer?.relays) { + collectedRelays.push(...params.addressPointer.relays); + } + + // Deduplicate collected relays + const uniqueRelays = [...new Set(collectedRelays)]; + + if (uniqueRelays.length > 0) { + relays = uniqueRelays; + } else { + // Fallback to sender's read relays (where they want to receive zap receipts) + const senderReadRelays = + (await relayListCache.getInboxRelays(account.pubkey)) || []; + relays = + senderReadRelays.length > 0 ? senderReadRelays : AGGREGATOR_RELAYS; + } } // Build tags