Files
welshman/packages/client/src/plugins/relays.ts
T
2026-06-18 11:40:39 -07:00

55 lines
1.6 KiB
TypeScript

import {fetchJson} from "@welshman/lib"
import type {Maybe} from "@welshman/lib"
import {displayRelayUrl, displayRelayProfile} from "@welshman/util"
import type {RelayProfile} from "@welshman/util"
import {LoadableMapPlugin} from "./base.js"
import type {Projection} from "./base.js"
/**
* NIP-11 relay profiles, keyed by url. A "local" loadable collection: items
* aren't nostr events, they're fetched over HTTP from each relay.
*/
export class Relays extends LoadableMapPlugin<RelayProfile> {
fetch = async (url: string): Promise<Maybe<RelayProfile>> => {
try {
const json = await fetchJson(url.replace(/^ws/, "http"), {
headers: {
Accept: "application/nostr+json",
},
})
if (json) {
const info = {...json, url} as RelayProfile
if (!Array.isArray(info.supported_nips)) {
info.supported_nips = []
}
info.supported_nips = info.supported_nips.map(String)
this.set(url, info)
return info
}
} catch (e) {
// pass
}
}
display = (url: string): Projection<string> =>
this.project(url, $relay => displayRelayProfile($relay, displayRelayUrl(url)))
hasNegentropy = async (url: string) => {
const relay = await this.load(url)
if (relay?.negentropy) return true
if (relay?.supported_nips?.includes("77")) return true
if (relay?.software?.includes?.("strfry") && !relay?.version?.match(/^0\./)) return true
return false
}
hasNip = async (url: string, nip: number | string) =>
(await this.load(url))?.supported_nips?.includes(String(nip)) ?? false
}