Migrates to use "title" instead of "name" tags for NIP-51 lists.

This commit is contained in:
Vitor Pamplona
2026-02-05 15:01:43 -05:00
parent 4ced055035
commit e97a30fcb1
13 changed files with 55 additions and 42 deletions
@@ -81,7 +81,7 @@ class BlockPeopleListState(
) )
} else { } else {
PeopleListEvent.create( PeopleListEvent.create(
name = PeopleListEvent.BLOCK_LIST_D_TAG, title = PeopleListEvent.BLOCK_LIST_D_TAG,
person = UserTag(pubkeyHex), person = UserTag(pubkeyHex),
isPrivate = true, isPrivate = true,
signer = signer, signer = signer,
@@ -87,7 +87,7 @@ class LabeledBookmarkListsState(
suspend fun LabeledBookmarkListEvent.toLabeledBookmarkList() = suspend fun LabeledBookmarkListEvent.toLabeledBookmarkList() =
LabeledBookmarkList( LabeledBookmarkList(
identifier = dTag(), identifier = dTag(),
title = nameOrTitle() ?: dTag(), title = titleOrName() ?: dTag(),
description = description(), description = description(),
image = image(), image = image(),
privateBookmarks = privateBookmarks(signer)?.toSet() ?: emptySet(), privateBookmarks = privateBookmarks(signer)?.toSet() ?: emptySet(),
@@ -160,7 +160,7 @@ class LabeledBookmarkListsState(
) { ) {
val newList = val newList =
LabeledBookmarkListEvent.create( LabeledBookmarkListEvent.create(
name = listName, title = listName,
description = listDescription, description = listDescription,
image = listImage, image = listImage,
publicBookmarks = if (!isBookmarkPrivate && firstBookmark != null) listOf(firstBookmark) else emptyList(), publicBookmarks = if (!isBookmarkPrivate && firstBookmark != null) listOf(firstBookmark) else emptyList(),
@@ -200,7 +200,7 @@ class LabeledBookmarkListsState(
val renamedList = val renamedList =
LabeledBookmarkListEvent.modifyName( LabeledBookmarkListEvent.modifyName(
earlierVersion = listEvent, earlierVersion = listEvent,
newName = newName, newTitle = newName,
signer = account.signer, signer = account.signer,
) )
account.sendMyPublicAndPrivateOutbox(renamedList) account.sendMyPublicAndPrivateOutbox(renamedList)
@@ -229,7 +229,7 @@ class LabeledBookmarkListsState(
) { ) {
val clonedList = val clonedList =
LabeledBookmarkListEvent.create( LabeledBookmarkListEvent.create(
name = customCloneName ?: currentBookmarkList.title, title = customCloneName ?: currentBookmarkList.title,
description = customCloneDescription ?: currentBookmarkList.description, description = customCloneDescription ?: currentBookmarkList.description,
publicBookmarks = currentBookmarkList.publicBookmarks.toList(), publicBookmarks = currentBookmarkList.publicBookmarks.toList(),
privateBookmarks = currentBookmarkList.privateBookmarks.toList(), privateBookmarks = currentBookmarkList.privateBookmarks.toList(),
@@ -118,7 +118,7 @@ class PeopleListsState(
suspend fun PeopleListEvent.toUI() = suspend fun PeopleListEvent.toUI() =
PeopleList( PeopleList(
identifierTag = this.dTag(), identifierTag = this.dTag(),
title = this.nameOrTitle() ?: this.dTag(), title = this.titleOrName() ?: this.dTag(),
description = this.description(), description = this.description(),
image = this.image(), image = this.image(),
privateMembers = cache.load(decryptionCache.privateUserIdSet(this)), privateMembers = cache.load(decryptionCache.privateUserIdSet(this)),
@@ -197,7 +197,7 @@ class PeopleListsState(
val newListTemplate = val newListTemplate =
PeopleListEvent.build( PeopleListEvent.build(
dTag = dTag, dTag = dTag,
name = listName, title = listName,
publicMembers = if (!isPrivate && member != null) listOf(member.toUserTag()) else emptyList(), publicMembers = if (!isPrivate && member != null) listOf(member.toUserTag()) else emptyList(),
privateMembers = if (isPrivate && member != null) listOf(member.toUserTag()) else emptyList(), privateMembers = if (isPrivate && member != null) listOf(member.toUserTag()) else emptyList(),
signer = account.signer, signer = account.signer,
@@ -282,7 +282,7 @@ fun RenderOption(
val name = val name =
when (noteEvent) { when (noteEvent) {
is PeopleListEvent -> { is PeopleListEvent -> {
noteEvent.nameOrTitle() ?: option.note.dTag() noteEvent.titleOrName() ?: option.note.dTag()
} }
is FollowListEvent -> { is FollowListEvent -> {
@@ -81,7 +81,7 @@ fun DisplayPeopleList(
members.take(3) members.take(3)
} }
val name by remember { derivedStateOf { "#${noteEvent.nameOrTitle() ?: noteEvent.dTag()}" } } val name by remember { derivedStateOf { "#${noteEvent.titleOrName() ?: noteEvent.dTag()}" } }
Text( Text(
text = name, text = name,
@@ -316,7 +316,7 @@ class PeopleListName(
override fun name(): String { override fun name(): String {
val noteEvent = note.event val noteEvent = note.event
return if (noteEvent is PeopleListEvent) { return if (noteEvent is PeopleListEvent) {
noteEvent.nameOrTitle() ?: note.dTag() noteEvent.titleOrName() ?: note.dTag()
} else if (noteEvent is FollowListEvent) { } else if (noteEvent is FollowListEvent) {
noteEvent.title() ?: note.dTag() noteEvent.title() ?: note.dTag()
} else { } else {
@@ -40,7 +40,7 @@ import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.BookmarkIdTag
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.EventBookmark import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.EventBookmark
import com.vitorpamplona.quartz.nip51Lists.encryption.PrivateTagsInContent import com.vitorpamplona.quartz.nip51Lists.encryption.PrivateTagsInContent
import com.vitorpamplona.quartz.nip51Lists.remove import com.vitorpamplona.quartz.nip51Lists.remove
import com.vitorpamplona.quartz.nip51Lists.tags.NameTag import com.vitorpamplona.quartz.nip51Lists.tags.TitleTag
import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.TimeUtils
@Immutable @Immutable
@@ -62,7 +62,7 @@ class BookmarkListEvent(
override fun linkedAddressIds() = tags.mapNotNull(AddressBookmark::parseAddressId) override fun linkedAddressIds() = tags.mapNotNull(AddressBookmark::parseAddressId)
fun name() = tags.firstNotNullOfOrNull(NameTag::parse) fun title() = tags.firstNotNullOfOrNull(TitleTag::parse)
fun countBookmarks() = tags.count(BookmarkIdTag::isTagged) fun countBookmarks() = tags.count(BookmarkIdTag::isTagged)
@@ -192,19 +192,19 @@ class BookmarkListEvent(
} }
suspend fun create( suspend fun create(
name: String = "", title: String = "",
publicBookmarks: List<BookmarkIdTag> = emptyList(), publicBookmarks: List<BookmarkIdTag> = emptyList(),
privateBookmarks: List<BookmarkIdTag> = emptyList(), privateBookmarks: List<BookmarkIdTag> = emptyList(),
dTag: String = DEFAULT_D_TAG_BOOKMARKS, dTag: String = DEFAULT_D_TAG_BOOKMARKS,
signer: NostrSigner, signer: NostrSigner,
createdAt: Long = TimeUtils.now(), createdAt: Long = TimeUtils.now(),
): BookmarkListEvent { ): BookmarkListEvent {
val template = build(name, publicBookmarks, privateBookmarks, signer, dTag, createdAt) val template = build(title, publicBookmarks, privateBookmarks, signer, dTag, createdAt)
return signer.sign(template) return signer.sign(template)
} }
suspend fun build( suspend fun build(
name: String = "", title: String = "",
publicBookmarks: List<BookmarkIdTag> = emptyList(), publicBookmarks: List<BookmarkIdTag> = emptyList(),
privateBookmarks: List<BookmarkIdTag> = emptyList(), privateBookmarks: List<BookmarkIdTag> = emptyList(),
signer: NostrSigner, signer: NostrSigner,
@@ -218,7 +218,7 @@ class BookmarkListEvent(
) { ) {
dTag(dTag) dTag(dTag)
alt(ALT) alt(ALT)
name(name) title(title)
bookmarks(publicBookmarks) bookmarks(publicBookmarks)
initializer() initializer()
@@ -23,7 +23,11 @@ package com.vitorpamplona.quartz.nip51Lists.bookmarkList
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.BookmarkIdTag import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.BookmarkIdTag
import com.vitorpamplona.quartz.nip51Lists.tags.NameTag import com.vitorpamplona.quartz.nip51Lists.tags.NameTag
import com.vitorpamplona.quartz.nip51Lists.tags.TitleTag
@Deprecated("NIP-51 has deprecated name. Use title instead", ReplaceWith("title()"))
fun TagArrayBuilder<BookmarkListEvent>.name(name: String) = addUnique(NameTag.assemble(name)) fun TagArrayBuilder<BookmarkListEvent>.name(name: String) = addUnique(NameTag.assemble(name))
fun TagArrayBuilder<BookmarkListEvent>.title(title: String) = addUnique(TitleTag.assemble(title))
fun TagArrayBuilder<BookmarkListEvent>.bookmarks(bookmarks: List<BookmarkIdTag>) = addAll(bookmarks.map { it.toTagArray() }) fun TagArrayBuilder<BookmarkListEvent>.bookmarks(bookmarks: List<BookmarkIdTag>) = addAll(bookmarks.map { it.toTagArray() })
@@ -68,11 +68,12 @@ class LabeledBookmarkListEvent(
override fun linkedAddressIds() = tags.mapNotNull(AddressBookmark::parseAddressId) override fun linkedAddressIds() = tags.mapNotNull(AddressBookmark::parseAddressId)
@Deprecated("NIP-51 has deprecated name. Use title instead", ReplaceWith("title()"))
fun name() = tags.firstNotNullOfOrNull(NameTag::parse) fun name() = tags.firstNotNullOfOrNull(NameTag::parse)
fun title() = tags.firstNotNullOfOrNull(TitleTag::parse) fun title() = tags.firstNotNullOfOrNull(TitleTag::parse)
fun nameOrTitle() = name() ?: title() fun titleOrName() = title() ?: name()
fun description() = tags.firstNotNullOfOrNull(DescriptionTag::parse) fun description() = tags.firstNotNullOfOrNull(DescriptionTag::parse)
@@ -93,7 +94,7 @@ class LabeledBookmarkListEvent(
fun createBookmarkAddress(pubKey: HexKey) = Address(KIND, pubKey, Uuid.random().toString()) fun createBookmarkAddress(pubKey: HexKey) = Address(KIND, pubKey, Uuid.random().toString())
suspend fun create( suspend fun create(
name: String = "", title: String = "",
bookmarkIdTag: BookmarkIdTag, bookmarkIdTag: BookmarkIdTag,
isPrivate: Boolean, isPrivate: Boolean,
optionalListDescription: String? = null, optionalListDescription: String? = null,
@@ -102,7 +103,7 @@ class LabeledBookmarkListEvent(
): LabeledBookmarkListEvent = ): LabeledBookmarkListEvent =
if (isPrivate) { if (isPrivate) {
create( create(
name = name, title = title,
description = optionalListDescription, description = optionalListDescription,
publicBookmarks = emptyList(), publicBookmarks = emptyList(),
privateBookmarks = listOf(bookmarkIdTag), privateBookmarks = listOf(bookmarkIdTag),
@@ -111,7 +112,7 @@ class LabeledBookmarkListEvent(
) )
} else { } else {
create( create(
name = name, title = title,
description = optionalListDescription, description = optionalListDescription,
publicBookmarks = listOf(bookmarkIdTag), publicBookmarks = listOf(bookmarkIdTag),
privateBookmarks = emptyList(), privateBookmarks = emptyList(),
@@ -195,7 +196,7 @@ class LabeledBookmarkListEvent(
suspend fun modifyName( suspend fun modifyName(
earlierVersion: LabeledBookmarkListEvent, earlierVersion: LabeledBookmarkListEvent,
newName: String, newTitle: String,
signer: NostrSigner, signer: NostrSigner,
createdAt: Long = TimeUtils.now(), createdAt: Long = TimeUtils.now(),
): LabeledBookmarkListEvent { ): LabeledBookmarkListEvent {
@@ -203,9 +204,9 @@ class LabeledBookmarkListEvent(
val currentTitle = earlierVersion.tags.first { it[0] == NameTag.TAG_NAME || it[0] == TitleTag.TAG_NAME } val currentTitle = earlierVersion.tags.first { it[0] == NameTag.TAG_NAME || it[0] == TitleTag.TAG_NAME }
val newTitleTag = val newTitleTag =
if (currentTitle[0] == NameTag.TAG_NAME) { if (currentTitle[0] == NameTag.TAG_NAME) {
NameTag.assemble(newName) NameTag.assemble(newTitle)
} else { } else {
TitleTag.assemble(newName) TitleTag.assemble(newTitle)
} }
return resign( return resign(
@@ -287,7 +288,7 @@ class LabeledBookmarkListEvent(
@OptIn(ExperimentalUuidApi::class) @OptIn(ExperimentalUuidApi::class)
suspend fun create( suspend fun create(
name: String = "", title: String = "",
description: String? = null, description: String? = null,
image: String? = null, image: String? = null,
publicBookmarks: List<BookmarkIdTag> = emptyList(), publicBookmarks: List<BookmarkIdTag> = emptyList(),
@@ -297,7 +298,7 @@ class LabeledBookmarkListEvent(
createdAt: Long = TimeUtils.now(), createdAt: Long = TimeUtils.now(),
): LabeledBookmarkListEvent { ): LabeledBookmarkListEvent {
val template = val template =
build(name, publicBookmarks, privateBookmarks, signer, dTag, createdAt) { build(title, publicBookmarks, privateBookmarks, signer, dTag, createdAt) {
if (description != null) description(description) if (description != null) description(description)
if (image != null) image(image) if (image != null) image(image)
} }
@@ -306,7 +307,7 @@ class LabeledBookmarkListEvent(
@OptIn(ExperimentalUuidApi::class) @OptIn(ExperimentalUuidApi::class)
suspend fun build( suspend fun build(
name: String = "", title: String = "",
publicBookmarks: List<BookmarkIdTag> = emptyList(), publicBookmarks: List<BookmarkIdTag> = emptyList(),
privateBookmarks: List<BookmarkIdTag> = emptyList(), privateBookmarks: List<BookmarkIdTag> = emptyList(),
signer: NostrSigner, signer: NostrSigner,
@@ -320,7 +321,7 @@ class LabeledBookmarkListEvent(
) { ) {
dTag(dTag) dTag(dTag)
alt(ALT) alt(ALT)
name(name) title(title)
bookmarks(publicBookmarks) bookmarks(publicBookmarks)
initializer() initializer()
@@ -25,9 +25,13 @@ import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.BookmarkIdTag
import com.vitorpamplona.quartz.nip51Lists.tags.DescriptionTag import com.vitorpamplona.quartz.nip51Lists.tags.DescriptionTag
import com.vitorpamplona.quartz.nip51Lists.tags.ImageTag import com.vitorpamplona.quartz.nip51Lists.tags.ImageTag
import com.vitorpamplona.quartz.nip51Lists.tags.NameTag import com.vitorpamplona.quartz.nip51Lists.tags.NameTag
import com.vitorpamplona.quartz.nip51Lists.tags.TitleTag
@Deprecated("NIP-51 has deprecated name. Use title instead", ReplaceWith("title()"))
fun TagArrayBuilder<LabeledBookmarkListEvent>.name(name: String) = addUnique(NameTag.assemble(name)) fun TagArrayBuilder<LabeledBookmarkListEvent>.name(name: String) = addUnique(NameTag.assemble(name))
fun TagArrayBuilder<LabeledBookmarkListEvent>.title(title: String) = addUnique(TitleTag.assemble(title))
fun TagArrayBuilder<LabeledBookmarkListEvent>.bookmarks(bookmarks: List<BookmarkIdTag>) = addAll(bookmarks.map { it.toTagArray() }) fun TagArrayBuilder<LabeledBookmarkListEvent>.bookmarks(bookmarks: List<BookmarkIdTag>) = addAll(bookmarks.map { it.toTagArray() })
fun TagArrayBuilder<LabeledBookmarkListEvent>.description(listDescription: String) = addUnique(DescriptionTag.assemble(listDescription)) fun TagArrayBuilder<LabeledBookmarkListEvent>.description(listDescription: String) = addUnique(DescriptionTag.assemble(listDescription))
@@ -61,11 +61,11 @@ class PeopleListEvent(
override fun linkedPubKeys() = tags.mapNotNull(UserTag::parseKey) override fun linkedPubKeys() = tags.mapNotNull(UserTag::parseKey)
@Deprecated("NIP-51 has deprecated name. Use title instead", ReplaceWith("title()"))
fun name() = tags.firstNotNullOfOrNull(NameTag::parse) fun name() = tags.firstNotNullOfOrNull(NameTag::parse)
fun nameOrTitle() = name() ?: title() fun titleOrName() = title() ?: name()
@Deprecated("NIP-51 has deprecated Title. Use name instead", ReplaceWith("name()"))
fun title() = tags.firstNotNullOfOrNull(TitleTag::parse) fun title() = tags.firstNotNullOfOrNull(TitleTag::parse)
fun description() = tags.firstNotNullOfOrNull(DescriptionTag::parse) fun description() = tags.firstNotNullOfOrNull(DescriptionTag::parse)
@@ -103,7 +103,7 @@ class PeopleListEvent(
@OptIn(ExperimentalUuidApi::class) @OptIn(ExperimentalUuidApi::class)
suspend fun create( suspend fun create(
name: String, title: String,
person: UserTag, person: UserTag,
isPrivate: Boolean, isPrivate: Boolean,
signer: NostrSigner, signer: NostrSigner,
@@ -112,7 +112,7 @@ class PeopleListEvent(
): PeopleListEvent = ): PeopleListEvent =
if (isPrivate) { if (isPrivate) {
create( create(
name = name, title = title,
publicMembers = emptyList(), publicMembers = emptyList(),
privateMembers = listOf(person), privateMembers = listOf(person),
signer = signer, signer = signer,
@@ -121,7 +121,7 @@ class PeopleListEvent(
) )
} else { } else {
create( create(
name = name, title = title,
publicMembers = listOf(person), publicMembers = listOf(person),
privateMembers = emptyList(), privateMembers = emptyList(),
signer = signer, signer = signer,
@@ -249,20 +249,20 @@ class PeopleListEvent(
@OptIn(ExperimentalUuidApi::class) @OptIn(ExperimentalUuidApi::class)
suspend fun create( suspend fun create(
name: String, title: String,
publicMembers: List<UserTag> = emptyList(), publicMembers: List<UserTag> = emptyList(),
privateMembers: List<UserTag> = emptyList(), privateMembers: List<UserTag> = emptyList(),
signer: NostrSigner, signer: NostrSigner,
dTag: String = Uuid.random().toString(), dTag: String = Uuid.random().toString(),
createdAt: Long = TimeUtils.now(), createdAt: Long = TimeUtils.now(),
): PeopleListEvent { ): PeopleListEvent {
val template = build(name, publicMembers, privateMembers, signer, dTag, createdAt) val template = build(title, publicMembers, privateMembers, signer, dTag, createdAt)
return signer.sign(template) return signer.sign(template)
} }
@OptIn(ExperimentalUuidApi::class) @OptIn(ExperimentalUuidApi::class)
suspend fun build( suspend fun build(
name: String, title: String,
publicMembers: List<UserTag> = emptyList(), publicMembers: List<UserTag> = emptyList(),
privateMembers: List<UserTag> = emptyList(), privateMembers: List<UserTag> = emptyList(),
signer: NostrSigner, signer: NostrSigner,
@@ -276,7 +276,7 @@ class PeopleListEvent(
) { ) {
dTag(dTag) dTag(dTag)
alt(ALT) alt(ALT)
name(name) title(title)
peoples(publicMembers) peoples(publicMembers)
initializer() initializer()
@@ -293,7 +293,7 @@ class PeopleListEvent(
): PeopleListEvent { ): PeopleListEvent {
val newListTemplate = val newListTemplate =
build( build(
name = title, title = title,
publicMembers = publicMembers, publicMembers = publicMembers,
privateMembers = privateMembers, privateMembers = privateMembers,
signer = signer, signer = signer,
@@ -316,7 +316,7 @@ class PeopleListEvent(
): PeopleListEvent { ): PeopleListEvent {
val cloneTemplate = val cloneTemplate =
build( build(
name = title, title = title,
publicMembers = publicMembers, publicMembers = publicMembers,
privateMembers = privateMembers, privateMembers = privateMembers,
signer = signer, signer = signer,
@@ -330,14 +330,14 @@ class PeopleListEvent(
} }
suspend fun createListWithUser( suspend fun createListWithUser(
name: String, title: String,
pubKeyHex: String, pubKeyHex: String,
isPrivate: Boolean, isPrivate: Boolean,
signer: NostrSigner, signer: NostrSigner,
createdAt: Long = TimeUtils.now(), createdAt: Long = TimeUtils.now(),
): PeopleListEvent = ): PeopleListEvent =
create( create(
name = name, title = title,
person = UserTag(pubKey = pubKeyHex), person = UserTag(pubKey = pubKeyHex),
isPrivate = isPrivate, isPrivate = isPrivate,
signer = signer, signer = signer,
@@ -25,9 +25,13 @@ import com.vitorpamplona.quartz.nip51Lists.muteList.tags.UserTag
import com.vitorpamplona.quartz.nip51Lists.tags.DescriptionTag import com.vitorpamplona.quartz.nip51Lists.tags.DescriptionTag
import com.vitorpamplona.quartz.nip51Lists.tags.ImageTag import com.vitorpamplona.quartz.nip51Lists.tags.ImageTag
import com.vitorpamplona.quartz.nip51Lists.tags.NameTag import com.vitorpamplona.quartz.nip51Lists.tags.NameTag
import com.vitorpamplona.quartz.nip51Lists.tags.TitleTag
@Deprecated("NIP-51 has deprecated name. Use title instead", ReplaceWith("title()"))
fun TagArrayBuilder<PeopleListEvent>.name(name: String) = addUnique(NameTag.assemble(name)) fun TagArrayBuilder<PeopleListEvent>.name(name: String) = addUnique(NameTag.assemble(name))
fun TagArrayBuilder<PeopleListEvent>.title(name: String) = addUnique(TitleTag.assemble(name))
fun TagArrayBuilder<PeopleListEvent>.description(desc: String) = addUnique(DescriptionTag.assemble(desc)) fun TagArrayBuilder<PeopleListEvent>.description(desc: String) = addUnique(DescriptionTag.assemble(desc))
fun TagArrayBuilder<PeopleListEvent>.image(url: String) = addUnique(ImageTag.assemble(url)) fun TagArrayBuilder<PeopleListEvent>.image(url: String) = addUnique(ImageTag.assemble(url))
@@ -37,8 +37,8 @@ import com.vitorpamplona.quartz.nip51Lists.relayLists.tags.relaySet
import com.vitorpamplona.quartz.nip51Lists.remove import com.vitorpamplona.quartz.nip51Lists.remove
import com.vitorpamplona.quartz.nip51Lists.tags.DescriptionTag import com.vitorpamplona.quartz.nip51Lists.tags.DescriptionTag
import com.vitorpamplona.quartz.nip51Lists.tags.ImageTag import com.vitorpamplona.quartz.nip51Lists.tags.ImageTag
import com.vitorpamplona.quartz.nip51Lists.tags.NameTag
import com.vitorpamplona.quartz.nip51Lists.tags.RelayTag import com.vitorpamplona.quartz.nip51Lists.tags.RelayTag
import com.vitorpamplona.quartz.nip51Lists.tags.TitleTag
import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.TimeUtils
@Immutable @Immutable
@@ -52,7 +52,7 @@ class RelaySetEvent(
) : PrivateTagArrayEvent(id, pubKey, createdAt, KIND, tags, content, sig) { ) : PrivateTagArrayEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
fun relays(): List<NormalizedRelayUrl> = tags.mapNotNull(RelayTag.Companion::parse) fun relays(): List<NormalizedRelayUrl> = tags.mapNotNull(RelayTag.Companion::parse)
fun name() = tags.firstNotNullOfOrNull(NameTag::parse) fun title() = tags.firstNotNullOfOrNull(TitleTag::parse)
fun description() = tags.firstNotNullOfOrNull(DescriptionTag::parse) fun description() = tags.firstNotNullOfOrNull(DescriptionTag::parse)