@nostr-dev-kit/ndk
Version:
NDK - Nostr Development Kit. Includes AI Guardrails to catch common mistakes during development.
119 lines (100 loc) • 3.82 kB
text/typescript
import type { NDK } from "../../ndk/index.js";
import { NDKRelaySet } from "../../relay/sets/index.js";
import { normalizeRelayUrl, tryNormalizeRelayUrl } from "../../utils/normalize-url.js";
import type { NostrEvent } from "../index.js";
import { NDKEvent } from "../index.js";
import { NDKKind } from "./index.js";
const READ_MARKER = "read";
const WRITE_MARKER = "write";
/**
* Represents a relay list for a user, ideally coming from a NIP-65 kind:10002 or alternatively from a kind:3 event's content.
* @group Kind Wrapper
*/
export class NDKRelayList extends NDKEvent {
static kind = NDKKind.RelayList;
static kinds = [NDKKind.RelayList];
constructor(ndk?: NDK, rawEvent?: NostrEvent) {
super(ndk, rawEvent);
this.kind ??= NDKKind.RelayList;
}
static from(ndkEvent: NDKEvent): NDKRelayList {
return new NDKRelayList(ndkEvent.ndk, ndkEvent.rawEvent());
}
get readRelayUrls(): WebSocket["url"][] {
return this.tags
.filter((tag) => tag[0] === "r" || tag[0] === "relay")
.filter((tag) => !tag[2] || (tag[2] && tag[2] === READ_MARKER))
.map((tag) => tryNormalizeRelayUrl(tag[1]))
.filter((url) => !!url) as WebSocket["url"][];
}
set readRelayUrls(relays: WebSocket["url"][]) {
for (const relay of relays) {
this.tags.push(["r", relay, READ_MARKER]);
}
}
get writeRelayUrls(): WebSocket["url"][] {
return this.tags
.filter((tag) => tag[0] === "r" || tag[0] === "relay")
.filter((tag) => !tag[2] || (tag[2] && tag[2] === WRITE_MARKER))
.map((tag) => tryNormalizeRelayUrl(tag[1]))
.filter((url) => !!url) as WebSocket["url"][];
}
set writeRelayUrls(relays: WebSocket["url"][]) {
for (const relay of relays) {
this.tags.push(["r", relay, WRITE_MARKER]);
}
}
get bothRelayUrls(): WebSocket["url"][] {
return this.tags
.filter((tag) => tag[0] === "r" || tag[0] === "relay")
.filter((tag) => !tag[2])
.map((tag) => tag[1]);
}
set bothRelayUrls(relays: WebSocket["url"][]) {
for (const relay of relays) {
this.tags.push(["r", relay]);
}
}
get relays(): WebSocket["url"][] {
return this.tags.filter((tag) => tag[0] === "r" || tag[0] === "relay").map((tag) => tag[1]);
}
/**
* Provides a relaySet for the relays in this list.
*/
get relaySet(): NDKRelaySet {
if (!this.ndk) throw new Error("NDKRelayList has no NDK instance");
return new NDKRelaySet(
new Set(this.relays.map((u) => this.ndk?.pool.getRelay(u)).filter((r) => !!r)),
this.ndk,
);
}
}
export function relayListFromKind3(ndk: NDK, contactList: NDKEvent): NDKRelayList | undefined {
try {
const content = JSON.parse(contactList.content);
const relayList = new NDKRelayList(ndk);
const readRelays = new Set<string>();
const writeRelays = new Set<string>();
for (let [key, config] of Object.entries(content)) {
try {
key = normalizeRelayUrl(key);
} catch {
continue;
}
if (!config) {
readRelays.add(key);
writeRelays.add(key);
} else {
const relayConfig: { read?: boolean; write?: boolean } = config;
if (relayConfig.write) writeRelays.add(key);
if (relayConfig.read) readRelays.add(key);
}
}
relayList.readRelayUrls = Array.from(readRelays);
relayList.writeRelayUrls = Array.from(writeRelays);
return relayList;
} catch {
/* */
}
return undefined;
}