import { fetchRelayInformation } from '@nostr-dev-kit/ndk'; import type NDK from '@nostr-dev-kit/ndk'; import type { NDKRelay } from '@nostr-dev-kit/ndk'; import type { RelayConnection, RelayConnectionEvent } from './relay-manager'; import type { RelayInformation } from '$lib/types/relay'; /** * adapts an NDKRelay (from the shared pool) to the driver-agnostic * RelayConnection interface the RelayManager leans on. keeping this thin adapter * separate means the manager's logic never imports ndk directly. */ class NdkRelayConnection implements RelayConnection { private readonly relay: NDKRelay; /** ndk runs its own reconnection loop; the manager mustn't add a second. */ readonly selfReconnecting = true; constructor( public readonly url: string, ndk: NDK ) { // `getRelay(url, false)` returns (or creates) the pool relay without // eagerly connecting — we call connect() ourselves. this.relay = ndk.pool.getRelay(url, false, false); } async connect(): Promise { // reconnect=true lets ndk retry, but our manager owns the higher-level // backoff and loop prevention across the app. await this.relay.connect(undefined, true); } disconnect(): void { this.relay.disconnect(); } on(event: RelayConnectionEvent, handler: (payload?: string) => void): () => void { // map our vocabulary onto NDKRelay events. const wrapped = (payload?: unknown) => handler(typeof payload === 'string' ? payload : undefined); this.relay.on(event, wrapped as never); return () => this.relay.off(event, wrapped as never); } } /** factory used by the app-level RelayManager wiring. */ export function createNdkConnection(url: string, ndk: NDK): RelayConnection { return new NdkRelayConnection(url, ndk); } /** nip-11 fetch mapped into the app-level RelayInformation model. */ export async function fetchNip11(url: string): Promise { const info = await fetchRelayInformation(url); // `features` and `motd` are nosterm extensions ndk's typed document doesn't // know about, so read them defensively off the raw object. const raw = info as unknown as { features?: unknown; motd?: unknown }; const features = Array.isArray(raw.features) ? raw.features.filter((f): f is string => typeof f === 'string') : undefined; const motd = typeof raw.motd === 'string' ? raw.motd : undefined; return { name: info.name, description: info.description, pubkey: info.pubkey, contact: info.contact, software: info.software, version: info.version, supportedNips: info.supported_nips, features, motd, limitation: info.limitation ? { maxMessageLength: info.limitation.max_message_length, maxSubscriptions: info.limitation.max_subscriptions, authRequired: info.limitation.auth_required, paymentRequired: info.limitation.payment_required } : undefined }; }