Relay Class
The Relay
class provides a reactive interface for connecting to and communicating with Nostr relays using RxJS observables.
Creating a Relay Connection
import { Relay } from "applesauce-relay";
// Create a new relay instance
const relay = new Relay("wss://relay.example.com");
// Access relay state observables
relay.connected$.subscribe((connected) => console.log("Connection status:", connected));
relay.notices$.subscribe((notices) => console.log("Relay notices:", notices));
Subscribing to Events
The req
or subscription
methods returns an observable that emits events from the relay.
INFO
The subscription
method is a wrapper around the req
method that automatically handles reconnection and retries.
// Subscribe to specific kinds of events
relay
.req({
kinds: [1],
authors: ["pubkey1", "pubkey2"],
})
.subscribe({
next: (response) => {
if (response === "EOSE") {
console.log("End of stored events");
} else {
console.log("Event:", response);
}
},
error: (err) => console.error("Subscription error:", err),
});
Publishing Events
Send events to the relay using the event
or publish
methods.
INFO
The publish
method is a wrapper around the event
method that automatically handles reconnecting and retrying.
import { generatePrivateKey, getPublicKey, getEventHash, signEvent } from "nostr-tools";
const sk = generatePrivateKey();
const pk = getPublicKey(sk);
const event = {
kind: 1,
pubkey: pk,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: "Hello Nostr!",
};
event.id = getEventHash(event);
event.sig = signEvent(event, sk);
relay.event(event).subscribe((response) => {
console.log(`Published: ${response.ok}`, response.message);
});
Making One-time Requests
Use the request
method for one-time queries that complete after receiving EOSE
.
import { lastValueFrom } from "rxjs";
import { getProfileContent } from "applesauce-core/helpers";
// Get latest user profile
async function getProfile(pubkey) {
const events = await lastValueFrom(
relay.request({
kinds: [0],
authors: [pubkey],
limit: 1,
}),
);
return getProfileContent(events[0]);
}
Authentication
The Relay
class supports NIP-42 authentication and keeps track of the authentication state and challenge.
challenge$
- An observable that tracks the authentication challenge from the relay.authenticated$
- An observable that tracks the authentication state of the relay.authenticate
- A method that can be used to authenticate the relay.
More information about authentication can be found in the typedocs.
import { nip42 } from "nostr-tools";
// Listen for authentication challenges
relay.challenge$.subscribe(async (challenge) => {
if (!challenge) return;
// Using browser extension as signer
try {
await lastValueFrom(relay.authenticate(window.nostr));
console.log("Authentication successful");
} catch (e) {
console.error("Authentication failed:", e);
}
});
Persistent Subscriptions
The subscription
method can be used to create persistent subscriptions that automatically reconnect after connection issues.
// Create a persistent subscription
const subscription = relay
.subscription({ kinds: [1, 6], since: Math.floor(Date.now() / 1000) }, { id: "feed", retries: 3 })
.subscribe({
next: (response) => {
if (response !== "EOSE") {
console.log("New event:", response.content);
}
},
});
// Later, to unsubscribe
subscription.unsubscribe();
Dynamic Filters
The req
, and subscription
methods can accept an observable for the filters. this allows for you to set the filters later or update them dynamically.
WARNING
Make sure to use a ReplaySubject
, BehaviorSubject
, or the shareReplay
operator to keep the last filters in case the relay disconnects and needs to resubscribe.
import { BehaviorSubject } from "rxjs";
import { onlyEvents } from "applesauce-relay/operators";
// Create a subject with initial filters
const filters = new BehaviorSubject({
kinds: [1],
limit: 20,
});
// Subscribe using dynamic filters
relay
.req(filters)
.pipe(onlyEvents())
.subscribe((event) => console.log(event.content));
// Update filters later
setTimeout(() => {
filters.next({
kinds: [1],
"#t": ["nostr"],
limit: 20,
});
}, 5000);
Relay Information
The Relay
class keeps track of the relay information and emits it as an observable from the information$
property.
// Get relay information
relay.information$.subscribe((info) => {
if (info) {
console.log("Relay name:", info.name);
console.log("Supported NIPs:", info.supported_nips);
console.log("Software:", info.software);
if (info.limitation) {
console.log("Max message size:", info.limitation.max_message_length);
}
}
});