Files
nosterm-client/src/lib/nostr/ndk-relay-driver.ts
T
Robert Goodall cd2b900639
ci / build (push) Successful in 1m3s
ci / image (push) Successful in 41s
Initial commit: Nosterm client (terminal-style Nostr chat SPA)
2026-07-24 13:47:53 -04:00

80 lines
2.8 KiB
TypeScript

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<void> {
// 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<RelayInformation> {
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
};
}