# 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.

}

/// Adds an element to a NIP-51 list.
///
/// If the list doesn't exist, it will be created. The updated list is
/// then broadcast to relays and cached locally.
///
/// [kind] the kind of NIP-51 list \
/// [tag] the tag type for the element (e.g., 'p' for pubkey, 'e' for event) \
/// [value] the value to add to the list \
/// [broadcastRelays] optional specific relays to broadcast to \
/// [private] if true, encrypt the element in the list content
///
/// 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,

# removeElementFromList

Removes an element from a list.


/// Removes an element from a NIP-51 list.
///
/// Updates the list by removing the specified element, then broadcasts
/// the updated list to relays and updates the cache.
///
/// [kind] the kind of NIP-51 list \
/// [tag] the tag type of the element to remove \
/// [value] the value to remove from the list \
/// [broadcastRelays] optional specific relays to broadcast to
///
/// Returns the updated list, or null if the list doesn't exist.\
/// Throws an exception if no event signer is available.
Future<Nip51List?> removeElementFromList({
  required int kind,
  required String tag,
  required String value,
  Iterable<String>? broadcastRelays,

# Sets Methods

# getSetByName

Gets a specific set by name (d-tag) and kind.

/// Gets a NIP-51 set by name identifier (d tag).
///
/// Retrieves a specific set for the logged-in user or a custom signer.
/// The set is identified by its name (d tag) and kind.
///
/// [name] name of the set (d tag identifier) \
/// [kind] kind of the set, see Nip51List class for constants \
/// [customSigner] optional signer, defaults to logged-in account \
/// [forceRefresh] if true, skip cache and query relays directly
///
/// Returns the set if found, null otherwise. \
/// Throws an exception if no account is logged in and no custom signer is provided.
Future<Nip51Set?> getSetByName({
  required String name,
  required int kind,
  bool forceRefresh = false,
}) async {
  final EventSigner signer;

# getPublicSets

Returns a stream of all public sets for a given public key and kind.

/// [kind] the kind of sets to retrieve \
/// [publicKey] the public key of the user whose sets to retrieve, default logged in pubkey \
/// [forceRefresh] if true, skip cache and query relays directly
///
/// Returns a stream that emits collections of sets as they are discovered.
Stream<Iterable<Nip51Set>?> getPublicSets({
  required int kind,
  String? publicKey,
  bool forceRefresh = false,
}) {
  final EventSigner mySigner;
  if (publicKey == null) {
    if (_eventSigner == null) {
      throw Exception("getPublicSets() no account");
    }

# addElementToSet

Adds an element to a named set. Creates the set if it doesn't exist.


  return _getSets(kind, mySigner, forceRefresh: forceRefresh);
}

/// Adds an element to a NIP-51 set.
///
/// If the set doesn't exist, it will be created. The updated set is
/// then broadcast to relays and cached locally.
///
/// [name] name of the set (d tag identifier) \
/// [tag] the tag type for the element (e.g., 'relay', 'p', 'e') \
/// [value] the value to add to the set \
/// [kind] kind of the set \
/// [private] if true, encrypt the element in the set content \
/// [specificRelays] optional specific relays to broadcast to
///
/// Returns the updated set.
Future<Nip51Set?> addElementToSet({
  required String name,
  required String tag,
  required String value,

# removeElementFromSet

Removes an element from a named set.

  await _cacheManager.saveEvent(event);
  return set;
}

/// Removes an element from a NIP-51 set.
///
/// Updates the set by removing the specified element, then broadcasts
/// the updated set to relays and updates the cache.
///
/// [name] name of the set (d tag identifier) \
/// [value] the value to remove from the set \
/// [tag] the tag type of the element to remove \
/// [kind] kind of the set \
/// [private] if true, the element was encrypted \
/// [specificRelays] optional specific relays to broadcast to
///
/// Returns the updated set.
/// Throws an exception if no event signer is available.
Future<Nip51Set?> removeElementFromSet({
  required String name,
  required String value,
  required String tag,

# setCompleteSet

Overwrites or creates a complete set. Warning: This replaces the entire set.

  return mySet;
}

/// 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,

# deleteSet

Deletes a set by name and broadcasts a deletion event.


/// Deletes a NIP-51 set by name.
///
/// Broadcasts a deletion event for the set and removes it from the cache.
/// Uses the logged-in account's signer.
///
/// [name] name of the set (d tag identifier) \
/// [kind] kind of the set \
/// [specificRelays] optional specific relays to broadcast the deletion to
///
/// Throws an exception if no event signer is available.
Future deleteSet({
  required String name,
  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");
});