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.
74 lines
2.5 KiB
74 lines
2.5 KiB
import type { TRelayList } from '@/types' |
|
import { normalizeAnyRelayUrl } from '@/lib/url' |
|
|
|
/** Paid / subscription relay — presence in favorites or NIP-65 lists implies access to the matching aggregator. */ |
|
export const NOSTR_LAND_WSS = 'wss://nostr.land' |
|
|
|
/** Aggregator for nostr.land subscribers only; others get auth / policy errors if contacted. */ |
|
export const AGGR_NOSTR_LAND_WSS = 'wss://aggr.nostr.land' |
|
|
|
function canonWs(url: string): string { |
|
return (normalizeAnyRelayUrl(url) || url.trim()).toLowerCase() |
|
} |
|
|
|
const NOSTR_LAND_CANON = canonWs(NOSTR_LAND_WSS) |
|
const AGGR_CANON = canonWs(AGGR_NOSTR_LAND_WSS) |
|
|
|
/** True if this URL is the nostr.land websocket (normalized). */ |
|
export function isNostrLandWsUrl(url: string | undefined | null): boolean { |
|
if (!url?.trim()) return false |
|
return canonWs(url) === NOSTR_LAND_CANON |
|
} |
|
|
|
/** True if any normalized URL equals nostr.land. */ |
|
export function relayUrlListMentionsNostrLand(urls: readonly string[] | undefined): boolean { |
|
if (!urls?.length) return false |
|
for (const u of urls) { |
|
if (isNostrLandWsUrl(u)) return true |
|
} |
|
return false |
|
} |
|
|
|
/** True if nostr.land appears in any NIP-65 / HTTP relay list slice. */ |
|
export function nip65RelayListMentionsNostrLand(rl: TRelayList | null | undefined): boolean { |
|
if (!rl) return false |
|
return ( |
|
relayUrlListMentionsNostrLand(rl.read) || |
|
relayUrlListMentionsNostrLand(rl.write) || |
|
relayUrlListMentionsNostrLand(rl.httpRead) || |
|
relayUrlListMentionsNostrLand(rl.httpWrite) |
|
) |
|
} |
|
|
|
/** |
|
* Subscriber may use {@link AGGR_NOSTR_LAND_WSS}: they listed nostr.land in kind-10012 favorites or NIP-65 lists. |
|
*/ |
|
export function viewerMayUseNostrLandAggr( |
|
favoriteRelays: readonly string[] | undefined, |
|
nip65: TRelayList | null | undefined |
|
): boolean { |
|
if (relayUrlListMentionsNostrLand(favoriteRelays)) return true |
|
return nip65RelayListMentionsNostrLand(nip65 ?? undefined) |
|
} |
|
|
|
/** |
|
* Drop {@link AGGR_NOSTR_LAND_WSS} when the viewer is not a nostr.land subscriber; otherwise ensure it appears once. |
|
*/ |
|
export function applyNostrLandAggrRelayPolicy(urls: readonly string[], allowAggr: boolean): string[] { |
|
const out: string[] = [] |
|
const seen = new Set<string>() |
|
const push = (u: string) => { |
|
const c = canonWs(u) |
|
if (!c || seen.has(c)) return |
|
if (!allowAggr && c === AGGR_CANON) return |
|
seen.add(c) |
|
out.push(normalizeAnyRelayUrl(u) || u.trim()) |
|
} |
|
for (const u of urls) { |
|
push(u) |
|
} |
|
if (allowAggr && !seen.has(AGGR_CANON)) { |
|
out.unshift(AGGR_NOSTR_LAND_WSS) |
|
} |
|
return out |
|
}
|
|
|