refactor(quartz): rename FavoriteDvmListEvent -> FavoriteAlgoFeedsListEvent

The list event only stores content-discovery feeds (kind-5300 DVMs),
not every DVM, so the old name was misleading. Rename the wire-level
type to reflect what's actually in it.

- Quartz: package nip51Lists.favoriteDvmList -> favoriteAlgoFeedsList;
  class FavoriteDvmListEvent -> FavoriteAlgoFeedsListEvent.
- DSL helpers renamed: favoriteDvm/favoriteDvms builder extensions ->
  favoriteAlgoFeed/favoriteAlgoFeeds; TagArray.favoriteDvmList/Set ->
  favoriteAlgoFeedsList/Set.
- create/add/remove parameter names dvm -> feed, publicDvms/privateDvms
  -> publicFeeds/privateFeeds; public/private accessors
  publicFavoriteDvms/privateFavoriteDvms -> publicFavoriteAlgoFeeds/
  privateFavoriteAlgoFeeds. ALT string updated.
- EventFactory + LocalCache dispatch branches + AccountSettings backup
  field type + FavoriteDvmListState + FavoriteDvmListDecryptionCache all
  import the new type. Internal amethyst-side classes
  (FavoriteDvmListState, FavoriteDvmListDecryptionCache), the top-nav
  filter classes (FavoriteDvm*, AllFavoriteDvms*) and the orchestrator
  keep their names — they still deal with content-discovery DVMs
  specifically, and the narrower rename here is scoped to the Nostr
  wire format the user was asking about.
- Quartz test renamed + rewired. Build + tests green on both modules.
This commit is contained in:
Claude
2026-04-19 17:37:55 +00:00
parent fc284e3cfe
commit 72598026a3
9 changed files with 86 additions and 86 deletions
@@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip51Lists.favoriteDvmList
package com.vitorpamplona.quartz.nip51Lists.favoriteAlgoFeedsList
import androidx.compose.runtime.Immutable
import com.vitorpamplona.quartz.nip01Core.core.Address
@@ -38,7 +38,7 @@ import com.vitorpamplona.quartz.nip51Lists.remove
import com.vitorpamplona.quartz.utils.TimeUtils
@Immutable
class FavoriteDvmListEvent(
class FavoriteAlgoFeedsListEvent(
id: HexKey,
pubKey: HexKey,
createdAt: Long,
@@ -46,72 +46,72 @@ class FavoriteDvmListEvent(
content: String,
sig: HexKey,
) : PrivateTagArrayEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
fun publicFavoriteDvms(): List<AddressBookmark> = tags.mapNotNull(AddressBookmark::parse)
fun publicFavoriteAlgoFeeds(): List<AddressBookmark> = tags.mapNotNull(AddressBookmark::parse)
suspend fun privateFavoriteDvms(signer: NostrSigner): List<AddressBookmark>? = privateTags(signer)?.mapNotNull(AddressBookmark::parse)
suspend fun privateFavoriteAlgoFeeds(signer: NostrSigner): List<AddressBookmark>? = privateTags(signer)?.mapNotNull(AddressBookmark::parse)
companion object {
const val KIND = 10090
const val ALT = "Favorite DVM list"
const val ALT = "Favorite algo-feeds list"
const val FIXED_D_TAG = ""
fun createAddress(pubKey: HexKey) = Address(KIND, pubKey, FIXED_D_TAG)
suspend fun create(
dvm: AddressBookmark,
feed: AddressBookmark,
isPrivate: Boolean,
signer: NostrSigner,
createdAt: Long = TimeUtils.now(),
): FavoriteDvmListEvent =
): FavoriteAlgoFeedsListEvent =
if (isPrivate) {
create(
publicDvms = emptyList(),
privateDvms = listOf(dvm),
publicFeeds = emptyList(),
privateFeeds = listOf(feed),
signer = signer,
createdAt = createdAt,
)
} else {
create(
publicDvms = listOf(dvm),
privateDvms = emptyList(),
publicFeeds = listOf(feed),
privateFeeds = emptyList(),
signer = signer,
createdAt = createdAt,
)
}
suspend fun add(
earlierVersion: FavoriteDvmListEvent,
dvm: AddressBookmark,
earlierVersion: FavoriteAlgoFeedsListEvent,
feed: AddressBookmark,
isPrivate: Boolean,
signer: NostrSigner,
createdAt: Long = TimeUtils.now(),
): FavoriteDvmListEvent =
): FavoriteAlgoFeedsListEvent =
if (isPrivate) {
val privateTags =
earlierVersion.privateTags(signer)
?: throw SignerExceptions.UnauthorizedDecryptionException()
resign(
tags = earlierVersion.tags,
privateTags = privateTags.remove(dvm.toTagIdOnly()) + dvm.toTagArray(),
privateTags = privateTags.remove(feed.toTagIdOnly()) + feed.toTagArray(),
signer = signer,
createdAt = createdAt,
)
} else {
resign(
content = earlierVersion.content,
tags = earlierVersion.tags.remove(dvm.toTagIdOnly()) + dvm.toTagArray(),
tags = earlierVersion.tags.remove(feed.toTagIdOnly()) + feed.toTagArray(),
signer = signer,
createdAt = createdAt,
)
}
suspend fun remove(
earlierVersion: FavoriteDvmListEvent,
dvm: Address,
earlierVersion: FavoriteAlgoFeedsListEvent,
feed: Address,
signer: NostrSigner,
createdAt: Long = TimeUtils.now(),
): FavoriteDvmListEvent {
val idOnly = AddressBookmark.assemble(dvm, null)
): FavoriteAlgoFeedsListEvent {
val idOnly = AddressBookmark.assemble(feed, null)
val privateTags = earlierVersion.privateTags(signer)
return if (privateTags != null) {
resign(
@@ -147,7 +147,7 @@ class FavoriteDvmListEvent(
tags: TagArray,
signer: NostrSigner,
createdAt: Long = TimeUtils.now(),
): FavoriteDvmListEvent {
): FavoriteAlgoFeedsListEvent {
val newTags =
if (tags.fastAny(AltTag::match)) {
tags
@@ -159,32 +159,32 @@ class FavoriteDvmListEvent(
}
suspend fun create(
publicDvms: List<AddressBookmark> = emptyList(),
privateDvms: List<AddressBookmark> = emptyList(),
publicFeeds: List<AddressBookmark> = emptyList(),
privateFeeds: List<AddressBookmark> = emptyList(),
signer: NostrSigner,
createdAt: Long = TimeUtils.now(),
): FavoriteDvmListEvent {
val template = build(publicDvms, privateDvms, signer, createdAt)
): FavoriteAlgoFeedsListEvent {
val template = build(publicFeeds, privateFeeds, signer, createdAt)
return signer.sign(template)
}
suspend fun build(
publicDvms: List<AddressBookmark> = emptyList(),
privateDvms: List<AddressBookmark> = emptyList(),
publicFeeds: List<AddressBookmark> = emptyList(),
privateFeeds: List<AddressBookmark> = emptyList(),
signer: NostrSigner,
createdAt: Long = TimeUtils.now(),
initializer: TagArrayBuilder<FavoriteDvmListEvent>.() -> Unit = {},
) = eventTemplate<FavoriteDvmListEvent>(
initializer: TagArrayBuilder<FavoriteAlgoFeedsListEvent>.() -> Unit = {},
) = eventTemplate<FavoriteAlgoFeedsListEvent>(
kind = KIND,
description =
PrivateTagsInContent.encryptNip44(
privateDvms.map { it.toTagArray() }.toTypedArray(),
privateFeeds.map { it.toTagArray() }.toTypedArray(),
signer,
),
createdAt = createdAt,
) {
alt(ALT)
favoriteDvms(publicDvms)
favoriteAlgoFeeds(publicFeeds)
initializer()
}
@@ -18,11 +18,11 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip51Lists.favoriteDvmList
package com.vitorpamplona.quartz.nip51Lists.favoriteAlgoFeedsList
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark
fun TagArrayBuilder<FavoriteDvmListEvent>.favoriteDvm(app: AddressBookmark) = add(app.toTagArray())
fun TagArrayBuilder<FavoriteAlgoFeedsListEvent>.favoriteAlgoFeed(app: AddressBookmark) = add(app.toTagArray())
fun TagArrayBuilder<FavoriteDvmListEvent>.favoriteDvms(apps: List<AddressBookmark>) = addAll(apps.map { it.toTagArray() })
fun TagArrayBuilder<FavoriteAlgoFeedsListEvent>.favoriteAlgoFeeds(apps: List<AddressBookmark>) = addAll(apps.map { it.toTagArray() })
@@ -18,11 +18,11 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip51Lists.favoriteDvmList
package com.vitorpamplona.quartz.nip51Lists.favoriteAlgoFeedsList
import com.vitorpamplona.quartz.nip01Core.core.TagArray
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark
fun TagArray.favoriteDvmList() = mapNotNull(AddressBookmark::parseAddress)
fun TagArray.favoriteAlgoFeedsList() = mapNotNull(AddressBookmark::parseAddress)
fun TagArray.favoriteDvmSet() = mapNotNullTo(mutableSetOf(), AddressBookmark::parseAddress)
fun TagArray.favoriteAlgoFeedsSet() = mapNotNullTo(mutableSetOf(), AddressBookmark::parseAddress)
@@ -134,7 +134,7 @@ import com.vitorpamplona.quartz.nip51Lists.appCurationSet.AppCurationSetEvent
import com.vitorpamplona.quartz.nip51Lists.articleCurationSet.ArticleCurationSetEvent
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.OldBookmarkListEvent
import com.vitorpamplona.quartz.nip51Lists.favoriteDvmList.FavoriteDvmListEvent
import com.vitorpamplona.quartz.nip51Lists.favoriteAlgoFeedsList.FavoriteAlgoFeedsListEvent
import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent
import com.vitorpamplona.quartz.nip51Lists.geohashList.GeohashListEvent
import com.vitorpamplona.quartz.nip51Lists.gitAuthorList.GitAuthorListEvent
@@ -423,7 +423,7 @@ class EventFactory {
GoodWikiAuthorListEvent.KIND -> GoodWikiAuthorListEvent(id, pubKey, createdAt, tags, content, sig)
GoodWikiRelayListEvent.KIND -> GoodWikiRelayListEvent(id, pubKey, createdAt, tags, content, sig)
GoalEvent.KIND -> GoalEvent(id, pubKey, createdAt, tags, content, sig)
FavoriteDvmListEvent.KIND -> FavoriteDvmListEvent(id, pubKey, createdAt, tags, content, sig)
FavoriteAlgoFeedsListEvent.KIND -> FavoriteAlgoFeedsListEvent(id, pubKey, createdAt, tags, content, sig)
HashtagListEvent.KIND -> HashtagListEvent(id, pubKey, createdAt, tags, content, sig)
HighlightEvent.KIND -> HighlightEvent(id, pubKey, createdAt, tags, content, sig)
HTTPAuthorizationEvent.KIND -> HTTPAuthorizationEvent(id, pubKey, createdAt, tags, content, sig)
@@ -18,7 +18,7 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip51Lists.favoriteDvmList
package com.vitorpamplona.quartz.nip51Lists.favoriteAlgoFeedsList
import com.vitorpamplona.quartz.nip01Core.core.Address
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
@@ -30,7 +30,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class FavoriteDvmListEventTest {
class FavoriteAlgoFeedsListEventTest {
private val signer = NostrSignerInternal("nsec10g0wheggqn9dawlc0yuv6adnat6n09anr7eyykevw2dm8xa5fffs0wsdsr".nsecToKeyPair())
private fun dvm(
@@ -40,12 +40,12 @@ class FavoriteDvmListEventTest {
@Test
fun kindMatchesSpec() {
assertEquals(10090, FavoriteDvmListEvent.KIND)
assertEquals(10090, FavoriteAlgoFeedsListEvent.KIND)
}
@Test
fun addressesAreReplaceableWithFixedDTag() {
val address = FavoriteDvmListEvent.createAddress("a".repeat(64))
val address = FavoriteAlgoFeedsListEvent.createAddress("a".repeat(64))
assertEquals(10090, address.kind)
assertEquals("", address.dTag)
}
@@ -53,11 +53,11 @@ class FavoriteDvmListEventTest {
@Test
fun createStoresDvmAsATag() =
runTest {
val dvm = dvm("a".repeat(64))
val aFeed = dvm("a".repeat(64))
val event =
FavoriteDvmListEvent.create(
dvm = dvm,
FavoriteAlgoFeedsListEvent.create(
feed = aFeed,
isPrivate = false,
signer = signer,
createdAt = 1740669816,
@@ -65,31 +65,31 @@ class FavoriteDvmListEventTest {
assertEquals(10090, event.kind)
assertTrue(
event.tags.any { it.size >= 2 && it[0] == "a" && it[1] == dvm.address.toValue() },
event.tags.any { it.size >= 2 && it[0] == "a" && it[1] == aFeed.address.toValue() },
"public a tag for the favourited DVM should be present",
)
val favorites = event.publicFavoriteDvms()
val favorites = event.publicFavoriteAlgoFeeds()
assertEquals(1, favorites.size)
assertEquals(dvm.address, favorites.first().address)
assertEquals(aFeed.address, favorites.first().address)
}
@Test
fun addAppendsWithoutDuplicatingExistingEntry() =
runTest {
val dvm = dvm("a".repeat(64))
val aFeed = dvm("a".repeat(64))
val initial =
FavoriteDvmListEvent.create(
dvm = dvm,
FavoriteAlgoFeedsListEvent.create(
feed = aFeed,
isPrivate = false,
signer = signer,
createdAt = 1740669816,
)
val afterDupeAdd =
FavoriteDvmListEvent.add(
FavoriteAlgoFeedsListEvent.add(
earlierVersion = initial,
dvm = dvm,
feed = aFeed,
isPrivate = false,
signer = signer,
createdAt = 1740669817,
@@ -97,7 +97,7 @@ class FavoriteDvmListEventTest {
assertEquals(
1,
afterDupeAdd.publicFavoriteDvms().count { it.address == dvm.address },
afterDupeAdd.publicFavoriteAlgoFeeds().count { it.address == aFeed.address },
"re-adding the same DVM must not produce a duplicate tag",
)
}
@@ -109,23 +109,23 @@ class FavoriteDvmListEventTest {
val second = dvm("b".repeat(64))
val initial =
FavoriteDvmListEvent.create(
dvm = first,
FavoriteAlgoFeedsListEvent.create(
feed = first,
isPrivate = false,
signer = signer,
createdAt = 1740669816,
)
val after =
FavoriteDvmListEvent.add(
FavoriteAlgoFeedsListEvent.add(
earlierVersion = initial,
dvm = second,
feed = second,
isPrivate = false,
signer = signer,
createdAt = 1740669817,
)
val addresses = after.publicFavoriteDvms().map { it.address }.toSet()
val addresses = after.publicFavoriteAlgoFeeds().map { it.address }.toSet()
assertTrue(first.address in addresses)
assertTrue(second.address in addresses)
}
@@ -137,22 +137,22 @@ class FavoriteDvmListEventTest {
val second = dvm("b".repeat(64))
val initial =
FavoriteDvmListEvent.create(
publicDvms = listOf(first, second),
privateDvms = emptyList(),
FavoriteAlgoFeedsListEvent.create(
publicFeeds = listOf(first, second),
privateFeeds = emptyList(),
signer = signer,
createdAt = 1740669816,
)
val after =
FavoriteDvmListEvent.remove(
FavoriteAlgoFeedsListEvent.remove(
earlierVersion = initial,
dvm = first.address,
feed = first.address,
signer = signer,
createdAt = 1740669817,
)
val addresses = after.publicFavoriteDvms().map { it.address }.toSet()
val addresses = after.publicFavoriteAlgoFeeds().map { it.address }.toSet()
assertFalse(first.address in addresses, "removed DVM should not survive")
assertTrue(second.address in addresses, "other DVMs should be preserved")
}