- Finishes the transition to EventHint objects for building events.

- Removes the "a-tag" dependency on Addressable interface because the `a` can have different names in different objects.
This commit is contained in:
Vitor Pamplona
2026-02-18 09:53:03 -05:00
parent 46b17628ac
commit 2c3ca7f906
23 changed files with 114 additions and 159 deletions
@@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.commons.model.nip18Reposts
import com.vitorpamplona.amethyst.commons.model.Note
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent
import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
@@ -35,34 +35,26 @@ object RepostAction {
/**
* Creates a signed repost event.
*
* @param event The event to repost
* @param eventHint The event to repost
* @param signer The NostrSigner to sign the event
* @param noteHint Optional relay hint where the note was seen
* @param authorHint Optional relay hint for the author's outbox
* @return Signed repost event ready to broadcast
* @throws IllegalStateException if signer is not writeable
*/
suspend fun repost(
event: Event,
eventHint: EventHintBundle<Event>,
signer: NostrSigner,
noteHint: String? = null,
authorHint: String? = null,
): Event {
if (!signer.isWriteable()) {
throw IllegalStateException("Cannot repost: signer is not writeable")
}
// Normalize relay hints
val normalizedNoteHint = noteHint?.let { RelayUrlNormalizer.normalizeOrNull(it) }
val normalizedAuthorHint = authorHint?.let { RelayUrlNormalizer.normalizeOrNull(it) }
// Use NIP-18 RepostEvent (kind 6) for text notes (kind 1)
// Use GenericRepostEvent (kind 16) for all other kinds
val template =
if (event.kind == 1) {
RepostEvent.build(event, normalizedNoteHint, normalizedAuthorHint)
if (eventHint.event.kind == 1) {
RepostEvent.build(eventHint)
} else {
GenericRepostEvent.build(event, normalizedNoteHint, normalizedAuthorHint)
GenericRepostEvent.build(eventHint)
}
return signer.sign(template)
@@ -86,10 +78,8 @@ object RepostAction {
if (!signer.isWriteable()) return null
if (note.hasBoostedInTheLast5Minutes(signer.pubKey)) return null
val noteEvent = note.event ?: return null
val noteHint = note.relayHintUrl()?.url
val authorHint = note.author?.bestRelayHint()?.url
val hint = note.toEventHint<Event>() ?: return null
return repost(noteEvent, signer, noteHint, authorHint)
return repost(hint, signer)
}
}
@@ -24,7 +24,6 @@ import com.vitorpamplona.amethyst.commons.model.Note
import com.vitorpamplona.amethyst.commons.model.User
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
import com.vitorpamplona.quartz.nip17Dm.NIP17Factory
import com.vitorpamplona.quartz.nip17Dm.base.NIP17Group
@@ -49,18 +48,14 @@ object ReactionAction {
* @throws IllegalStateException if signer is not writeable
*/
suspend fun reactTo(
event: Event,
eventHint: EventHintBundle<Event>,
reaction: String,
signer: NostrSigner,
relayHint: String? = null,
): ReactionEvent {
if (!signer.isWriteable()) {
throw IllegalStateException("Cannot react: signer is not writeable")
}
val normalizedRelayHint = relayHint?.let { RelayUrlNormalizer.normalizeOrNull(it) }
val eventHint = EventHintBundle(event, normalizedRelayHint)
// Handle custom emoji reactions (format: ":emoji_name:")
val template =
if (reaction.startsWith(":")) {
@@ -82,10 +77,9 @@ object ReactionAction {
* Creates a "like" reaction ("+").
*/
suspend fun like(
event: Event,
event: EventHintBundle<Event>,
signer: NostrSigner,
relayHint: String? = null,
): ReactionEvent = reactTo(event, "+", signer, relayHint)
): ReactionEvent = reactTo(event, "+", signer)
/**
* Advanced: React to an event with support for NIP-17 private groups.
@@ -102,7 +96,6 @@ object ReactionAction {
* @param onPrivate Callback for private group reactions (returns NIP17Factory.Result)
*/
suspend fun reactToWithGroupSupport(
event: Event,
eventHint: EventHintBundle<Event>,
reaction: String,
signer: NostrSigner,
@@ -113,6 +106,8 @@ object ReactionAction {
throw IllegalStateException("Cannot react: signer is not writeable")
}
val event = eventHint.event
// Check if this is a NIP-17 private group event
if (event is NIP17Group) {
val users = event.groupMembers().toList()
@@ -185,9 +180,8 @@ object ReactionAction {
if (!signer.isWriteable()) return
if (note.hasReacted(by, reaction)) return
val noteEvent = note.event ?: return
val eventHint = note.toEventHint<Event>() ?: return
reactToWithGroupSupport(noteEvent, eventHint, reaction, signer, onPublic, onPrivate)
reactToWithGroupSupport(eventHint, reaction, signer, onPublic, onPrivate)
}
}