|
|
|
@ -69,6 +69,9 @@ import { |
|
|
|
viewerUsesGlobalRelayDefaults |
|
|
|
viewerUsesGlobalRelayDefaults |
|
|
|
} from '@/lib/viewer-relay-defaults' |
|
|
|
} from '@/lib/viewer-relay-defaults' |
|
|
|
import { |
|
|
|
import { |
|
|
|
|
|
|
|
filterViewerBlockedRelaysForFetch, |
|
|
|
|
|
|
|
getViewerBlockedRelayUrls, |
|
|
|
|
|
|
|
isRelayBlockedByUser, |
|
|
|
parseBlockedRelayUrlsFromEvent, |
|
|
|
parseBlockedRelayUrlsFromEvent, |
|
|
|
setViewerBlockedRelayUrls |
|
|
|
setViewerBlockedRelayUrls |
|
|
|
} from '@/lib/viewer-blocked-relays' |
|
|
|
} from '@/lib/viewer-blocked-relays' |
|
|
|
@ -720,11 +723,6 @@ class ClientService extends EventTarget { |
|
|
|
|
|
|
|
|
|
|
|
/** IndexedDB-first: personal lists (incl. cache + HTTP) before policy or network so locals stay allowed. */ |
|
|
|
/** IndexedDB-first: personal lists (incl. cache + HTTP) before policy or network so locals stay allowed. */ |
|
|
|
const storageUrls = await this.collectViewerPersonalRelayUrlsFromStorage(pk) |
|
|
|
const storageUrls = await this.collectViewerPersonalRelayUrlsFromStorage(pk) |
|
|
|
this.viewerHttpIndexRelayBases = storageUrls.httpIndexBases |
|
|
|
|
|
|
|
setViewerPersonalRelayKeys(buildPersonalRelayKeySet(storageUrls.all), { viewerActive: true }) |
|
|
|
|
|
|
|
syncViewerRelayStackNostrLandAggrEligible(storageUrls.all) |
|
|
|
|
|
|
|
relaySessionStrikes.setSessionCacheRelayKeysFromKind10432(storageUrls.cacheRelayEvent) |
|
|
|
|
|
|
|
this.closeMetadataPolicyDisallowedRelayConnections() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
const blockedEvt = await indexedDb.getReplaceableEvent(pk, ExtendedKind.BLOCKED_RELAYS) |
|
|
|
const blockedEvt = await indexedDb.getReplaceableEvent(pk, ExtendedKind.BLOCKED_RELAYS) |
|
|
|
@ -733,6 +731,13 @@ class ClientService extends EventTarget { |
|
|
|
setViewerBlockedRelayUrls([]) |
|
|
|
setViewerBlockedRelayUrls([]) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.viewerHttpIndexRelayBases = filterViewerBlockedRelaysForFetch(storageUrls.httpIndexBases) |
|
|
|
|
|
|
|
setViewerPersonalRelayKeys(buildPersonalRelayKeySet(storageUrls.all), { viewerActive: true }) |
|
|
|
|
|
|
|
syncViewerRelayStackNostrLandAggrEligible(storageUrls.all) |
|
|
|
|
|
|
|
relaySessionStrikes.setSessionCacheRelayKeysFromKind10432(storageUrls.cacheRelayEvent) |
|
|
|
|
|
|
|
this.closeMetadataPolicyDisallowedRelayConnections() |
|
|
|
|
|
|
|
this.closeViewerBlockedRelayConnections() |
|
|
|
|
|
|
|
|
|
|
|
const urls = [...storageUrls.all] |
|
|
|
const urls = [...storageUrls.all] |
|
|
|
try { |
|
|
|
try { |
|
|
|
urls.push(...(await this.fetchFavoriteRelays(pk))) |
|
|
|
urls.push(...(await this.fetchFavoriteRelays(pk))) |
|
|
|
@ -742,6 +747,7 @@ class ClientService extends EventTarget { |
|
|
|
setViewerPersonalRelayKeys(buildPersonalRelayKeySet(urls), { viewerActive: true }) |
|
|
|
setViewerPersonalRelayKeys(buildPersonalRelayKeySet(urls), { viewerActive: true }) |
|
|
|
syncViewerRelayStackNostrLandAggrEligible(urls) |
|
|
|
syncViewerRelayStackNostrLandAggrEligible(urls) |
|
|
|
this.closeMetadataPolicyDisallowedRelayConnections() |
|
|
|
this.closeMetadataPolicyDisallowedRelayConnections() |
|
|
|
|
|
|
|
this.closeViewerBlockedRelayConnections() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** NIP-65 / 10243 / 10432 / favorites (10012) from IndexedDB only — no network. */ |
|
|
|
/** NIP-65 / 10243 / 10432 / favorites (10012) from IndexedDB only — no network. */ |
|
|
|
@ -802,8 +808,9 @@ class ClientService extends EventTarget { |
|
|
|
.map((u) => normalizeHttpRelayUrl(u) || u) |
|
|
|
.map((u) => normalizeHttpRelayUrl(u) || u) |
|
|
|
.filter(Boolean) |
|
|
|
.filter(Boolean) |
|
|
|
if (fresh.length > 0) { |
|
|
|
if (fresh.length > 0) { |
|
|
|
this.viewerHttpIndexRelayBases = fresh |
|
|
|
const filtered = filterViewerBlockedRelaysForFetch(fresh) |
|
|
|
return fresh |
|
|
|
this.viewerHttpIndexRelayBases = filtered |
|
|
|
|
|
|
|
return filtered |
|
|
|
} |
|
|
|
} |
|
|
|
} catch { |
|
|
|
} catch { |
|
|
|
/* keep session cache */ |
|
|
|
/* keep session cache */ |
|
|
|
@ -835,6 +842,20 @@ class ClientService extends EventTarget { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Close pooled sockets to relays on the viewer block list (hostname-aware, wss/https). */ |
|
|
|
|
|
|
|
closeViewerBlockedRelayConnections(): void { |
|
|
|
|
|
|
|
const blocked = getViewerBlockedRelayUrls() |
|
|
|
|
|
|
|
if (!blocked.length) return |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
const toClose = [...this.pool.listConnectionStatus().keys()].filter((url) => |
|
|
|
|
|
|
|
isRelayBlockedByUser(url, blocked) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
if (toClose.length > 0) this.pool.close(toClose) |
|
|
|
|
|
|
|
} catch { |
|
|
|
|
|
|
|
// ignore
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** NIP-66: fetch relay discovery events (30166) in background to supplement search/NIP support. */ |
|
|
|
/** NIP-66: fetch relay discovery events (30166) in background to supplement search/NIP support. */ |
|
|
|
private async fetchNip66RelayDiscovery(): Promise<void> { |
|
|
|
private async fetchNip66RelayDiscovery(): Promise<void> { |
|
|
|
if (isMetadataRelaysOnlyPolicyActive()) return |
|
|
|
if (isMetadataRelaysOnlyPolicyActive()) return |
|
|
|
@ -3190,12 +3211,9 @@ class ClientService extends EventTarget { |
|
|
|
let eosedAt: number | null = null |
|
|
|
let eosedAt: number | null = null |
|
|
|
let eventIds = new Set<string>() |
|
|
|
let eventIds = new Set<string>() |
|
|
|
|
|
|
|
|
|
|
|
const httpTimelinePollBases = httpIndexBasesForRelayQuery( |
|
|
|
const httpTimelinePollBases = filterViewerBlockedRelaysForFetch( |
|
|
|
originalDedupedRelays, |
|
|
|
httpIndexBasesForRelayQuery(originalDedupedRelays, this.viewerHttpIndexRelayBases) |
|
|
|
this.viewerHttpIndexRelayBases |
|
|
|
).filter((u) => relayAuthoritativeTimeline || !relaySessionStrikes.isReadHttpSkipped(u)) |
|
|
|
).filter( |
|
|
|
|
|
|
|
(u) => relayAuthoritativeTimeline || !relaySessionStrikes.isReadHttpSkipped(u) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
let httpPollIntervalId: ReturnType<typeof setInterval> | null = null |
|
|
|
let httpPollIntervalId: ReturnType<typeof setInterval> | null = null |
|
|
|
let httpPollCursorUnix = 0 |
|
|
|
let httpPollCursorUnix = 0 |
|
|
|
const clearHttpTimelinePoll = () => { |
|
|
|
const clearHttpTimelinePoll = () => { |
|
|
|
|