feat(relay-selection): add per-relay filter optimization

Add RelayFilterMap type and buildPerRelayFilters function to group
authors by their target relays. This enables consumers to send only
relevant authors to each relay instead of the full filter.

Result now includes:
- perRelayFilters: Array of { relay, authors[] } mappings

This reduces bandwidth and improves relay processing efficiency.
This commit is contained in:
Claude
2025-12-24 14:48:56 +00:00
parent 29dbdadc8b
commit cdeca71ef0
2 changed files with 58 additions and 0 deletions

View File

@@ -25,6 +25,7 @@ import type {
RelaySelectionResult,
RelaySelectionReasoning,
RelaySelectionOptions,
RelayFilterMap,
} from "@/types/relay-selection";
/**
@@ -486,6 +487,37 @@ function buildReasoning(
);
}
/**
* Builds per-relay filter maps for optimized queries
*
* Groups authors by which relay they should be queried from,
* allowing consumers to send only relevant authors to each relay.
*
* @param selectedPointers - ProfilePointers after optimization (with filtered relays)
* @returns Array of per-relay filter mappings
*/
function buildPerRelayFilters(
selectedPointers: ProfilePointer[],
): RelayFilterMap[] {
// Group authors by relay
const relayToAuthors = new Map<string, Set<string>>();
for (const pointer of selectedPointers) {
for (const relay of pointer.relays || []) {
if (!relayToAuthors.has(relay)) {
relayToAuthors.set(relay, new Set());
}
relayToAuthors.get(relay)!.add(pointer.pubkey);
}
}
// Convert to array
return Array.from(relayToAuthors.entries()).map(([relay, authors]) => ({
relay,
authors: Array.from(authors),
}));
}
/**
* Creates a fallback result when no pubkeys or all fetches failed
*
@@ -707,9 +739,13 @@ export async function selectRelaysForFilter(
pTagPointers,
);
// Build per-relay filter maps for optimized queries
const perRelayFilters = buildPerRelayFilters(selectedPointers);
return {
relays,
reasoning,
isOptimized: true,
perRelayFilters,
};
}

View File

@@ -17,6 +17,14 @@ export interface RelaySelectionResult {
/** True if using NIP-65 optimization, false if using fallback */
isOptimized: boolean;
/**
* Per-relay author mappings for optimized queries (optional)
*
* When present, consumers can use this to send only relevant
* authors to each relay instead of the full authors list.
*/
perRelayFilters?: RelayFilterMap[];
}
/**
@@ -52,3 +60,17 @@ export interface RelaySelectionOptions {
/** Timeout in ms for fetching kind:10002 events (default: 1000) */
timeout?: number;
}
/**
* Per-relay filter mapping for optimized queries
*
* Instead of sending the same filter to all relays, we can send
* only the relevant authors to each relay based on their relay lists.
*/
export interface RelayFilterMap {
/** Relay URL (normalized) */
relay: string;
/** Authors that should be queried from this relay */
authors: string[];
}