Lists
high level
Example
final myset = await ndk.lists.getSetByName(
name: "myset",
kind: Nip51List.kRelaySet,
customSigner: mySigner,
);
if (myset == null) {
print("set not found");
return;
}
print("received a set with ${myset.elements.length} elements");
How to use
We distinguish between lists and sets:
- Lists: Single lists identified by kind (e.g., bookmarks, mute list)
- Sets: Named collections identified by kind + name/d-tag (e.g., relay sets, follow sets)
Both can have public and private (encrypted) elements.
Lists Methods
getSingleNip51List
Retrieves a NIP-51 list by kind.
/// Returns a NIP-51 list by the given kind.
///
/// Retrieves the most recent list event for the specified kind.
/// First checks cache unless [forceRefresh] is true, then queries relays.
///
/// [kind] the kind of NIP-51 list to retrieve \
/// [forceRefresh] if true, bypass cache and query relays directly \
/// [timeout] maximum duration to wait for relay responses
///
/// Returns the list if found, null otherwise.
Future<Nip51List?> getSingleNip51List(
int kind, {
bool forceRefresh = false,
Duration timeout = const Duration(seconds: 5),
}) async {
if (_eventSigner == null) {
throw Exception("cannot get nip51 list without a signer");
addElementToList
Adds an element to a list. Creates the list if it doesn't exist.
}
/// Returns a NIP-51 list by kind for a given public key.
///
/// Retrieves the most recent list event for the specified kind and public key.
/// Unlike [getSingleNip51List], this works with any public key, not just
/// the logged-in user.
///
/// [kind] the kind of NIP-51 list to retrieve \
/// [publicKey] the public key of the user whose list to retrieve \
/// [forceRefresh] if true, bypass cache and query relays directly \
/// [timeout] maximum duration to wait for relay responses
///
/// Returns the list if found, null otherwise.
Future<Nip51List?> getPublicList({
required int kind,
required String publicKey,
bool forceRefresh = false,
Duration timeout = const Duration(seconds: 5),
}) async {
removeElementFromList
Removes an element from a list.
/// Returns the updated list.\
/// Throws an exception if no event signer is available.
Future<Nip51List> addElementToList({
required int kind,
required String tag,
required String value,
Iterable<String>? broadcastRelays,
bool private = false,
}) async {
if (_eventSigner == null) {
throw Exception(
"cannot broadcast private nip51 list without a signer that can sign");
}
Nip51List? list = await getSingleNip51List(
kind,
forceRefresh: true,
);
list ??= Nip51List(
Sets Methods
getSetByName
Gets a specific set by name (d-tag) and kind.
}
/// get a nip51 set
Stream<Iterable<Nip51Set>?> _getSets(
int kind,
EventSigner signer, {
bool forceRefresh = false,
}) {
final relaySets = <String, Nip51Set>{};
return _requests
.query(
filters: [
Filter(
authors: [signer.getPublicKey()],
kinds: [kind],
)
],
getPublicSets
Returns a stream of all public sets for a given public key and kind.
if (_eventSigner == null) {
throw Exception("getSetByName() no account");
}
signer = _eventSigner!;
Nip51Set? relaySet = await _getCachedSetByName(name, signer, kind);
if (relaySet == null || forceRefresh) {
Nip51Set? newRelaySet;
await for (final event in _requests.query(filters: [
Filter(
authors: [signer.getPublicKey()],
kinds: [kind],
tags: {
"#d": [name]
},
addElementToSet
Adds an element to a named set. Creates the set if it doesn't exist.
newRelaySet = await Nip51Set.fromEvent(event, signer);
await _cacheManager.saveEvent(event);
} else if (Helpers.isNotBlank(event.content)) {
Nip51Set? decryptedRelaySet =
await Nip51Set.fromEvent(event, signer);
if (decryptedRelaySet != null && decryptedRelaySet.name == name) {
newRelaySet = decryptedRelaySet;
await _cacheManager.saveEvent(event);
}
}
}
}
return newRelaySet;
}
return relaySet;
}
/// Returns a stream of public sets for a given public key, default is pubkey of logged in user.
///
/// Queries relays for all sets of the specified kind belonging to the
/// given public key. Only public (non-encrypted) sets are returned.
removeElementFromSet
Removes an element from a named set.
///
/// Returns the updated set.
Future<Nip51Set?> addElementToSet({
required String name,
required String tag,
required String value,
required int kind,
bool private = false,
Iterable<String>? specificRelays,
}) async {
Nip51Set? set =
await getSetByName(name: name, kind: kind, forceRefresh: true);
set ??= Nip51Set(
name: name,
pubKey: _eventSigner!.getPublicKey(),
kind: Nip51List.kRelaySet,
createdAt: Helpers.now,
elements: []);
set.addElement(tag, value, private);
set.createdAt = Helpers.now;
Nip01Event event = await set.toEvent(_eventSigner);
setCompleteSet
Overwrites or creates a complete set. Warning: This replaces the entire set.
throw Exception(
"cannot broadcast private nip51 list without a signer that can sign");
}
Nip51Set? mySet = await getSetByName(
name: name,
kind: kind,
forceRefresh: true,
);
if ((mySet == null || mySet.allRelays.isEmpty)) {
mySet = Nip51Set(
name: name,
kind: Nip51List.kRelaySet,
pubKey: _eventSigner!.getPublicKey(),
createdAt: Helpers.now,
elements: []);
deleteSet
Deletes a set by name and broadcasts a deletion event.
/// Overwrites or creates a complete NIP-51 set.
///
/// **Warning:** This replaces the entire set. Consider using
/// [addElementToSet] or [removeElementFromSet] for incremental updates.
///
/// [set] the complete set to broadcast \
/// [kind] kind of the set \
/// [specificRelays] optional specific relays to broadcast to
///
/// Returns the set after broadcasting.
Future<Nip51Set> setCompleteSet({
required Nip51Set set,
required int kind,
Iterable<String>? specificRelays,
Common Use Cases
Relay Sets
// Add relay to a set
await ndk.lists.addElementToSet(
name: "my-relays",
tag: "relay",
value: "wss://relay.example.com",
kind: Nip51List.kRelaySet,
);
// Get a relay set
final relaySet = await ndk.lists.getSetByName(
name: "my-relays",
kind: Nip51List.kRelaySet,
);
Bookmarks
// Add bookmark
await ndk.lists.addElementToList(
kind: Nip51List.kBookmarks,
tag: "e",
value: eventId,
);
// Get bookmarks
final bookmarks = await ndk.lists.getSingleNip51List(
Nip51List.kBookmarks,
mySigner,
);
Follow Sets
// Add to follow set
await ndk.lists.addElementToSet(
name: "close-friends",
tag: "p",
value: pubkey,
kind: Nip51List.kFollowSet,
);
// Stream all public follow sets
ndk.lists.getPublicSets(
kind: Nip51List.kFollowSet,
publicKey: somePubkey,
).listen((sets) {
print("Found ${sets?.length ?? 0} follow sets");
});