Compare commits

..

4 Commits

3 changed files with 83 additions and 8 deletions

View File

@@ -1,5 +1,5 @@
{
"VERSION": "v0.7.52",
"VERSION_NUMBER": "0.7.52",
"BUILD_DATE": "2026-06-26T17:43:40.739Z"
"VERSION": "v0.7.56",
"VERSION_NUMBER": "0.7.56",
"BUILD_DATE": "2026-06-27T12:17:42.524Z"
}

View File

@@ -6443,9 +6443,17 @@ async function handleSetRelayEventLogging(requestId, enabled, port) {
// from followed authors who write to relays the user does not subscribe to.
// For each discovered relay we also report which followed pubkeys it serves,
// by inverting ndk.outboxTracker.data (pubkey -> OutboxItem{writeRelays}).
function shortHexPubkey(hex) {
if (!hex || hex.length < 16) return hex || '-';
return `${hex.slice(0, 8)}${hex.slice(-4)}`;
}
// Cache for discovered relays — rebuilt only when the contact list changes.
// The version suffix forces a rebuild when the handler code changes (e.g.
// adding servingNames).
let discoveredRelaysCache = null;
let discoveredRelaysCacheKey = '';
const DISCOVERED_RELAYS_CACHE_VERSION = 'v3-names-k0';
async function handleGetDiscoveredRelays(requestId, port) {
try {
@@ -6473,7 +6481,7 @@ async function handleGetDiscoveredRelays(requestId, port) {
? Array.from(kind3Events).sort((a, b) => (b.created_at || 0) - (a.created_at || 0))[0]
: null;
const followedPubkeys = latestKind3 ? extractFollowedPubkeysFromKind3(latestKind3) : [];
const cacheKey = `${latestKind3?.id || 'none'}_${latestKind3?.created_at || 0}`;
const cacheKey = `${DISCOVERED_RELAYS_CACHE_VERSION}_${latestKind3?.id || 'none'}_${latestKind3?.created_at || 0}`;
// Rebuild the relay→[pubkeys] mapping from follows' kind 10002 events
// in the Dexie cache if the contact list has changed.
@@ -6527,6 +6535,67 @@ async function handleGetDiscoveredRelays(requestId, port) {
} catch (_) {}
}
// Look up profile names for all serving pubkeys from the Dexie
// profiles table so we can display usernames instead of pubkeys.
// Look up profile names for all serving pubkeys.
const pubkeyToName = new Map();
const allServingPubkeys = new Set();
for (const servingSet of relayServesPubkeys.values()) {
for (const pk of servingSet) allServingPubkeys.add(pk);
}
// Strategy 1: Try Dexie profiles table.
try {
const adapter = ndk?.cacheAdapter?.adapter;
if (adapter?.db?.profiles) {
for (const pk of allServingPubkeys) {
try {
const row = await adapter.db.profiles.get(pk);
if (row) {
const name = row.displayName || row.name || '';
if (name) pubkeyToName.set(pk, name);
}
} catch (_) {}
}
}
} catch (_) {}
// Strategy 2: If Dexie profiles didn't have names for everyone,
// query kind 0 events from the NDK cache for the missing pubkeys.
const missingPubkeys = Array.from(allServingPubkeys).filter(pk => !pubkeyToName.has(pk));
if (missingPubkeys.length > 0) {
try {
// Query in batches of 400.
for (let i = 0; i < missingPubkeys.length; i += 400) {
const batch = missingPubkeys.slice(i, i + 400);
const k0Events = await ndk.fetchEvents(
{ kinds: [0], authors: batch },
{ cacheUsage: 'ONLY_CACHE' }
);
if (k0Events && k0Events.size > 0) {
// For each author, keep only the latest kind 0.
const latestByAuthor = new Map();
for (const evt of k0Events) {
const existing = latestByAuthor.get(evt.pubkey);
if (!existing || (evt.created_at || 0) > (existing.created_at || 0)) {
latestByAuthor.set(evt.pubkey, evt);
}
}
for (const [pubkey, evt] of latestByAuthor) {
try {
const profile = typeof evt.content === 'string'
? JSON.parse(evt.content) : evt.content;
const name = profile?.display_name || profile?.name || '';
if (name) pubkeyToName.set(pubkey, name);
} catch (_) {}
}
}
}
} catch (_) {}
}
console.log('[Worker] getDiscoveredRelays: profile names resolved for', pubkeyToName.size, 'of', allServingPubkeys.size, 'pubkeys');
// Build the discovered relays list: relays that are NOT in the
// user's own kind 10002 but ARE in follows' kind 10002.
const relays = [];
@@ -6534,11 +6603,17 @@ async function handleGetDiscoveredRelays(requestId, port) {
if (ownRelays.has(relayUrl)) continue; // skip user's own relays
// Check live connection status from the pool.
const poolRelay = ndk.pool?.relays?.get(relayUrl);
const pubkeys = Array.from(servingSet);
// Map pubkeys to names, falling back to truncated pubkey.
const names = pubkeys.map(pk =>
pubkeyToName.get(pk) || shortHexPubkey(pk)
);
relays.push({
url: relayUrl,
status: poolRelay?.status || 0,
connected: poolRelay ? poolRelay.status >= 5 : false,
servingPubkeys: Array.from(servingSet)
servingPubkeys: pubkeys,
servingNames: names
});
}
// Sort by serving count (most follows first), then by URL.

View File

@@ -1383,9 +1383,9 @@ const versionInfo = await getVersion();
for (const relay of relaysWithFollows) {
const connected = relay.connected ? SVG_CHECKED : SVG_UNCHECKED;
const servingCount = Array.isArray(relay.servingPubkeys) ? relay.servingPubkeys.length : 0;
const followsList = Array.isArray(relay.servingPubkeys)
? relay.servingPubkeys.map(shortNpub).join(', ')
: '-';
const followsList = Array.isArray(relay.servingNames) && relay.servingNames.length > 0
? relay.servingNames.join(', ')
: (Array.isArray(relay.servingPubkeys) ? relay.servingPubkeys.map(shortNpub).join(', ') : '-');
const rowClass = relay.connected ? 'tblRowConnected' : '';
html += `<tr class="${rowClass}">`;