User State
Managing a user's complete state: profile, follows, relays, app data, and NIP-51 lists.
UserState<TAppData>
UserState provides a high-level API for reading and writing a user's Nostr state with safe sync semantics.
Constructor
typescript
import { UserState } from '@snort/system'
const state = new UserState<AppData>(
'pubkey',
{
appdataId: 'my-app-data',
initAppdata: { theme: 'light' } as AppData,
encryptAppdata: true,
},
{
// Optional: initial state object for fast startup
profile: cachedProfile,
follows: cachedFollows,
relays: cachedRelays,
appdata: cachedAppData,
}
)Options
typescript
interface UserStateOptions<T> {
appdataId: string // d-tag for app data event
initAppdata: T // Default app data value
encryptAppdata: boolean // NIP-44 encrypt app data
}State Object
typescript
interface UserStateObject<TAppData> {
profile?: UserMetadata
follows?: Array<string>
relays?: Array<FullRelaySettings>
appdata?: TAppData
}Initialization
typescript
await state.init(signer, system)This loads and syncs all state from relays.
Reading State
get profile(): UserMetadata | undefined
Get current profile data.
typescript
const profile = state.profile
console.log(profile?.name, profile?.about)get follows(): Array<string>
Get list of followed pubkeys.
typescript
const followList = state.followsget relays(): Array<FullRelaySettings>
Get user's relay list.
typescript
const relays = state.relaysget appdata(): TAppData | undefined
Get app-specific data.
typescript
const data = state.appdata
console.log(data?.theme)getList(kind: EventKind): DiffSyncTags | undefined
Get any NIP-51 list by kind.
typescript
const muteList = state.getList(EventKind.MuteList)
const bookmarks = state.getList(EventKind.BookmarksList)Writing State
updateProfile(profile: UserMetadata): Promise<void>
Update user profile. Only writes if the profile is newer.
typescript
await state.updateProfile({
name: 'kieran',
about: 'Building stuff',
picture: 'https://example.com/avatar.png',
})updateFollows(follows: Array<string>): Promise<void>
Update contact list.
typescript
await state.updateFollows(['pubkey1', 'pubkey2', 'pubkey3'])updateRelays(relays: Array<FullRelaySettings>): Promise<void>
Update relay list.
typescript
await state.updateRelays([
{ url: 'wss://relay.snort.social', settings: { read: true, write: true } },
{ url: 'wss://nos.lol', settings: { read: true, write: false } },
])updateAppData(data: TAppData): Promise<void>
Update app data.
typescript
await state.updateAppData({
theme: 'dark',
lastRead: Date.now(),
})updateList(kind: EventKind, tags: Array<Array<string>>): Promise<void>
Update a NIP-51 list.
typescript
await state.updateList(EventKind.MuteList, [
['p', 'pubkey-to-mute'],
])Change Events
typescript
import { UserStateChangeType } from '@snort/system'
state.on('change', (type) => {
switch (type) {
case UserStateChangeType.Profile:
console.log('Profile updated')
break
case UserStateChangeType.Contacts:
console.log('Follows updated')
break
case UserStateChangeType.Relays:
console.log('Relays updated')
break
case UserStateChangeType.AppData:
console.log('App data updated')
break
case UserStateChangeType.MuteList:
console.log('Mute list updated')
break
case UserStateChangeType.GenericList:
console.log('Generic list updated')
break
}
})DiffSyncTags
Low-level sync mechanism for tag-based lists (kind 3, kind 10002, NIP-51 lists).
- Computes diff between local and remote tags
- Merges and publishes the merged result
- Prevents data loss from concurrent edits
JsonEventSync
Low-level sync mechanism for JSON content events (kind 0 profile, kind 30078 app data).
- Parses JSON content
- Only writes if newer
- Handles encryption for app data