Casting Users
The User cast wraps a pubkey into an observable model with reactive access to profiles, contacts, mutes, bookmarks, relay lists, and more. It's the primary way to work with Nostr users in applesauce.
Import castUser from applesauce-common/casts:
import { castUser, User } from "applesauce-common/casts";castUser()
Cast a pubkey (or profile pointer, or event) to a User instance. Users are cached globally, so casting the same pubkey twice returns the same instance.
const user = castUser(pubkey, eventStore);
const user2 = castUser(profilePointer, eventStore);
const user3 = castUser(event, eventStore); // Uses event.pubkeyUser
The User class provides reactive access to all user-related data through observables.
Basic properties
user.pubkey; // Hex pubkey string
user.npub; // NIP-19 encoded npub
user.nprofile; // NIP-19 encoded nprofile with relay hints
user.pointer; // ProfilePointer object with relay hintsProfile
Get the user's profile metadata (kind 0).
const profile = use$(user.profile$);
if (profile) {
const displayName = profile.displayName;
const name = profile.name;
const about = profile.about;
const picture = profile.picture;
const banner = profile.banner;
const website = profile.website;
const nip05 = profile.dnsIdentity;
const lud16 = profile.lud16;
const lightningAddress = profile.lightningAddress; // lud16 or lud06
}See Profile cast for more details.
Contacts
Get the user's contact list (follows).
const contacts = use$(user.contacts$);
// contacts is an array of User objects
contacts?.forEach((contact) => {
const contactProfile = use$(contact.profile$);
console.log(contactProfile?.displayName);
});Example: Contact Manager
Mutes
Get the user's mute list with public and hidden mutes.
const mutes = use$(user.mutes$);
if (mutes) {
// Public mutes
const hashtags = mutes.hashtags; // Set<string>
const words = mutes.words; // Set<string>
const pubkeys = mutes.pubkeys; // Set<string>
const threads = mutes.threads; // Set<string>
// Check for hidden mutes
const hasHidden = mutes.hasHidden;
const unlocked = mutes.unlocked;
// Unlock hidden mutes
if (hasHidden && !unlocked) {
await mutes.unlock(signer);
}
// Access hidden mutes (after unlocking)
const hidden = use$(mutes.hidden$);
}See Mutes cast for more details.
Example: Mutes Manager
Mailboxes (NIP-65)
Get the user's inbox and outbox relays.
const mailboxes = use$(user.mailboxes$);
const outboxes = use$(user.outboxes$);
const inboxes = use$(user.inboxes$);
// Use outboxes for publishing
if (outboxes && outboxes.length > 0) {
await pool.publish(outboxes, event);
}
// Use inboxes for fetching user's content
if (inboxes && inboxes.length > 0) {
pool.subscription(inboxes, filter, { eventStore });
}Bookmarks
Get the user's bookmark list (kind 10003).
const bookmarks = use$(user.bookmarks$);
if (bookmarks) {
// Get resolved events
const notes = use$(bookmarks.notes$);
const articles = use$(bookmarks.articles$);
// Check for hidden bookmarks
if (bookmarks.hasHidden && !bookmarks.unlocked) {
await bookmarks.unlock(signer);
}
// Access hidden bookmarks
const hiddenNotes = use$(bookmarks.hiddenNotes$);
const hiddenArticles = use$(bookmarks.hiddenArticles$);
}See BookmarksList cast for more details.
Example: Bookmarks Manager
Relay Lists
Get the user's various relay lists.
// Favorite relays (kind 10012)
const favoriteRelays = use$(user.favoriteRelays$);
const relays = favoriteRelays?.relays; // string[]
// Search relays (kind 10007)
const searchRelays = use$(user.searchRelays$);
// Blocked relays (kind 10006)
const blockedRelays = use$(user.blockedRelays$);
// DM relays (kind 10050)
const dmRelays = use$(user.directMessageRelays$);All relay lists support hidden relays:
if (favoriteRelays?.hasHidden && !favoriteRelays.unlocked) {
await favoriteRelays.unlock(signer);
}
const hiddenRelays = use$(favoriteRelays.hidden$);See Relay Lists casts for more details.
Groups
Get the user's NIP-29 group list.
const groupsList = use$(user.groups$);
if (groupsList) {
const groups = groupsList.groups; // GroupPointer[]
// Unlock hidden groups if needed
if (groupsList.hasHidden && !groupsList.unlocked) {
await groupsList.unlock(signer);
}
const hiddenGroups = use$(groupsList.hidden$);
}See GroupsList cast for more details.
Live Stream
Get the user's current live stream (kind 30311).
const stream = use$(user.live$);
if (stream) {
const title = stream.title;
const status = stream.status; // "live" | "ended" | "planned"
const viewers = stream.viewers;
const chatMessages = use$(stream.chat$);
}See Stream cast for more details.
Request Methods
Request replaceable or addressable events directly from the user.
// Request a replaceable event (e.g., kind 30311 with identifier "my-stream")
const stream$ = user.replaceable(30311, "my-stream", relays);
// Request an addressable event (requires identifier)
const article$ = user.addressable(30023, "my-article", relays);User Cache
Users are cached globally by pubkey. This ensures that the same User instance is returned for the same pubkey, which is important for reactive subscriptions.
const user1 = castUser(pubkey, eventStore);
const user2 = castUser(pubkey, eventStore);
console.log(user1 === user2); // trueTo clear the cache (rarely needed):
User.cache.clear();Usage with Actions
Combine users with the action system to modify user data:
import { ActionRunner } from "applesauce-actions";
import { FollowUser, UnfollowUser, MuteUser } from "applesauce-actions/actions";
const actions = new ActionRunner(eventStore, factory);
// Follow a user
await actions.exec(FollowUser, contactPubkey).forEach(async (signed) => {
await pool.publish(user.outboxes$, signed);
});
// Unfollow a user
await actions.exec(UnfollowUser, contactPubkey).forEach(async (signed) => {
await pool.publish(user.outboxes$, signed);
});
// Mute a user
await actions.run(MuteUser, targetPubkey, false); // false = public muteTIP
All $ suffixed properties on User return reactive observables that update when the underlying data changes. Use use$ from applesauce-react/hooks to consume them in React components.
