5. Loading Specific Events with Loaders
Loaders are specialized utilities that help you fetch specific events from relays efficiently. While RelayPool subscriptions are great for real-time feeds, loaders are perfect for loading individual events, user profiles, or addressable events on-demand.
What are Loaders?
Loaders are functions that:
- Use the relay pool to fetch events from multiple relays
- Load specific events by ID, address, or other criteria
- Handle multiple relays automatically for better reliability
- Return observables that complete when the request is complete
- Integrate with EventStore to automatically store loaded events
Event Loader
The createEventLoader
function creates a loader for fetching events by their IDs.
Setting up Event Loader
import { createEventLoader } from "applesauce-loaders/loaders";
import { RelayPool } from "applesauce-relay";
import { EventStore } from "applesauce-core";
const pool = new RelayPool();
const eventStore = new EventStore();
// Create an event loader
const eventLoader = createEventLoader(pool, {
// Add events to the EventStore and deduplicate them
eventStore,
// Always check these relays for events
extraRelays: ["wss://relay.damus.io", "wss://nos.lol", "wss://relay.nostr.band"],
});
Loading Events by ID
// Make a request and subscribe to the result
eventLoader({
id: "621233a1ad1b91620f0b4a308c2113243a98925909cdb7b26284cbb4d835a18c",
relays: ["wss://relay.damus.io"],
}).subscribe((event) => {
console.log("Loaded event:", event.id);
console.log("Content:", event.content);
// Event is automatically added to EventStore
});
Loading Multiple Events
Since the event loader returns an observable, you can use the merge
operator from RxJS to make multiple requests at once.
// Make two requests at once and subscribe to the results
merge(
eventLoader({ id: "621233a1ad1b91620f0b4a308c2113243a98925909cdb7b26284cbb4d835a18c" }),
eventLoader({ id: "77941979d4c04283fd9b2f0a280749248cbd41babe3a0731c1597a6d54ae7874" }),
).subscribe({
next: (event) => {
console.log("Loaded event:", event.id);
},
complete: () => {
console.log("Both requested completed");
},
});
Address Loader
The createAddressLoader
function creates a loader for fetching addressable events (kinds 30000-39999) by their kind
, pubkey
and optional identifier
.
Setting up Address Loader
import { createAddressLoader } from "applesauce-loaders/loaders";
// Create an address loader
const addressLoader = createAddressLoader(pool, { eventStore });
Loading Addressable Events
// Load a specific addressable event
const pointer = {
kind: 30023, // Long-form content
pubkey: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
identifier: "my-article",
relays: ["wss://relay.damus.io", "wss://nos.lol"],
};
// Create the request and subscribe to the result
addressLoader(pointer).subscribe((event) => {
console.log("Loaded article:", event.id);
console.log("Title:", getArticleTitle(event));
});
Loading Multiple
Again, same as the event loader. the address loader returns an observable, so you can use the merge
operator from RxJS to make multiple requests at once.
// Make two requests at once and subscribe to the results
merge(
addressLoader({ kind: 30023, pubkey: "pubkey1", identifier: "article-1" }),
addressLoader({ kind: 30023, pubkey: "pubkey2", identifier: "article-2" }),
).subscribe({
next: (event) => {
console.log("Loaded addressable event:", event.id);
},
complete: () => {
console.log("All addressable events loaded");
},
});
Practical Examples
Loading a User's Profile
const addressLoader = createAddressLoader(pool, { eventStore });
function loadUserProfile(pubkey: string, relays: string[]) {
return addressLoader({ kind: 0, pubkey, relays }).pipe(
// Take only the first (most recent) profile
take(1),
map((event) => getProfileContent(event)),
);
}
// Usage
loadUserProfile(
// Pass pubkey
"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d",
// And the relays to load from
["wss://relay.damus.io", "wss://nos.lol"],
).subscribe((profile) => {
if (profile) {
console.log("Profile loaded:", profile.name);
}
});
Loader Configuration
Custom Relays
The event loader and address loader both take an extraRelays
option. This is an array of relays that will always be checked for events.
const addressLoader = createEventLoader(pool, {
eventStore,
extraRelays: ["wss://relay.damus.io", "wss://nos.lol"],
});
const articleLoader = createAddressLoader(pool, {
eventStore,
extraRelays: ["wss://relay.nostr.band", "wss://relay.damus.io"],
});
Timeout Configuration
The event loader and address loader both take a timeout
option which can be used to configure the timeout for the requests.
// Create loader with custom timeout
const eventLoader = createEventLoader(pool, {
eventStore,
extraRelays: ["wss://relay.damus.io"],
timeout: 10000, // 10 second timeout
});
Cache Configuration
The event loader and address loader both take a cacheRequest
option which is used to load events from a local cache first.
// A method to load events from a local cache
async function cacheRequest(filters: Filter[]) {
// Make a request to your custom local cache
const events = await localCache.getEventsForFilters(filters);
// Return the events as an array of events
return events;
}
// Create the loader with the cache request option
const eventLoader = createEventLoader(pool, { eventStore, cacheRequest });
Key Concepts
- Loaders fetch specific events on-demand, unlike subscriptions
- Results are added to the EventStore automatically
- Observables complete when the request is complete
Best Practices
1. Check EventStore First
// Always check if the event is already loaded
const existingEvent = eventStore.getEvent(eventId);
if (existingEvent) {
// Use existing event
console.log("Event already loaded:", existingEvent.content);
} else {
// Load from relays
eventLoader({ ids: [eventId] }).subscribe(/* ... */);
}
2. Use Relays in requests
Its better to pass the relays to the request than to use the extraRelays
option.
// Use multiple relays for better reliability
const eventLoader = createEventLoader(pool, { eventStore });
eventLoader({ id: eventId, relays: ["wss://relay.damus.io", "wss://nos.lol"] }).subscribe((event) => {
console.log("Loaded event:", event.id);
});