mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-11-10 11:57:29 +01:00
Draft event refactoring
This commit is contained in:
@@ -67,7 +67,7 @@ import com.vitorpamplona.quartz.nip34Git.reply.GitReplyEvent
|
||||
import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent
|
||||
import com.vitorpamplona.quartz.nip35Torrents.TorrentCommentEvent
|
||||
import com.vitorpamplona.quartz.nip35Torrents.TorrentEvent
|
||||
import com.vitorpamplona.quartz.nip37Drafts.DraftEvent
|
||||
import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent
|
||||
import com.vitorpamplona.quartz.nip37Drafts.privateOutbox.PrivateOutboxRelayListEvent
|
||||
import com.vitorpamplona.quartz.nip38UserStatus.StatusEvent
|
||||
import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent
|
||||
@@ -216,7 +216,7 @@ class EventFactory {
|
||||
CommunityPostApprovalEvent.KIND -> CommunityPostApprovalEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
ContactListEvent.KIND -> ContactListEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
DeletionEvent.KIND -> DeletionEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
DraftEvent.KIND -> DraftEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
DraftWrapEvent.KIND -> DraftWrapEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
EmojiPackEvent.KIND -> EmojiPackEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
EmojiPackSelectionEvent.KIND -> EmojiPackSelectionEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
EphemeralChatEvent.KIND -> EphemeralChatEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.EventReference
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.pTag
|
||||
import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag
|
||||
@@ -121,16 +122,37 @@ class PrivateDmEvent(
|
||||
}
|
||||
}
|
||||
|
||||
fun build(
|
||||
to: PTag,
|
||||
encryptedMessage: String,
|
||||
suspend fun build(
|
||||
toUser: PTag,
|
||||
message: String,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
replyingTo: EventReference? = null,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
signer: NostrSigner,
|
||||
initializer: TagArrayBuilder<PrivateDmEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, encryptedMessage, createdAt) {
|
||||
) = eventTemplate(
|
||||
kind = KIND,
|
||||
description =
|
||||
signer.nip04Encrypt(
|
||||
prepareMessageToEncrypt(message, imetas),
|
||||
toUser.pubKey,
|
||||
),
|
||||
createdAt = createdAt,
|
||||
) {
|
||||
alt(ALT)
|
||||
pTag(to)
|
||||
pTag(toUser)
|
||||
replyingTo?.let { reply(it) }
|
||||
|
||||
initializer()
|
||||
}
|
||||
|
||||
suspend fun create(
|
||||
to: PTag,
|
||||
message: String,
|
||||
imetas: List<IMetaTag>? = null,
|
||||
replyingTo: EventReference?,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
signer: NostrSigner,
|
||||
) = signer.sign(build(to, message, imetas, replyingTo, createdAt, signer))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@ class DraftBuilder {
|
||||
draft: T,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DraftEvent {
|
||||
): DraftWrapEvent {
|
||||
val encryptedContent = signer.nip44Encrypt(draft.toJson(), signer.pubKey)
|
||||
val template =
|
||||
eventTemplate<DraftEvent>(DraftEvent.KIND, encryptedContent, createdAt) {
|
||||
alt(DraftEvent.ALT_DESCRIPTION)
|
||||
eventTemplate<DraftWrapEvent>(DraftWrapEvent.KIND, encryptedContent, createdAt) {
|
||||
alt(DraftWrapEvent.ALT_DESCRIPTION)
|
||||
dTag(dTag)
|
||||
kind(draft.kind)
|
||||
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* 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.nip37Drafts
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.fasterxml.jackson.core.JsonParseException
|
||||
import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryBaseEvent
|
||||
import com.vitorpamplona.quartz.experimental.zapPolls.PollNoteEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.people.PTag
|
||||
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
|
||||
import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent
|
||||
import com.vitorpamplona.quartz.nip34Git.reply.GitReplyEvent
|
||||
import com.vitorpamplona.quartz.nip35Torrents.TorrentCommentEvent
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
@Immutable
|
||||
class DraftEvent(
|
||||
id: HexKey,
|
||||
pubKey: HexKey,
|
||||
createdAt: Long,
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||
EventHintProvider,
|
||||
AddressHintProvider,
|
||||
PubKeyHintProvider {
|
||||
override fun pubKeyHints() = tags.mapNotNull(PTag::parseAsHint)
|
||||
|
||||
override fun linkedPubKeys() = tags.mapNotNull(PTag::parseKey)
|
||||
|
||||
override fun eventHints() = tags.mapNotNull(ETag::parseAsHint)
|
||||
|
||||
override fun linkedEventIds() = tags.mapNotNull(ETag::parseId)
|
||||
|
||||
override fun addressHints() = tags.mapNotNull(ATag::parseAsHint)
|
||||
|
||||
override fun linkedAddressIds() = tags.mapNotNull(ATag::parseAddressId)
|
||||
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
fun isDeleted() = content == ""
|
||||
|
||||
fun canDecrypt(signer: NostrSigner) = signer.pubKey == pubKey
|
||||
|
||||
suspend fun createDeletedEvent(signer: NostrSigner): DraftEvent = signer.sign(createdAt, KIND, tags, "")
|
||||
|
||||
suspend fun decryptInnerEvent(signer: NostrSigner): Event {
|
||||
if (!canDecrypt(signer)) throw SignerExceptions.UnauthorizedDecryptionException()
|
||||
|
||||
val json = signer.nip44Decrypt(content, pubKey)
|
||||
return try {
|
||||
fromJson(json)
|
||||
} catch (e: JsonParseException) {
|
||||
Log.w("DraftEvent", "Unable to parse inner event of a draft: $json")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KIND = 31234
|
||||
const val ALT_DESCRIPTION = "Draft Event"
|
||||
|
||||
fun createAddressTag(
|
||||
pubKey: HexKey,
|
||||
dTag: String,
|
||||
): String = Address.assemble(KIND, pubKey, dTag)
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
suspend fun create(
|
||||
dTag: String,
|
||||
originalNote: TorrentCommentEvent,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DraftEvent {
|
||||
val tagsWithMarkers =
|
||||
originalNote.tags.filter {
|
||||
it.size > 3 && (it[0] == "e" || it[0] == "a") && (it[3] == "root" || it[3] == "reply")
|
||||
}
|
||||
|
||||
return create(dTag, originalNote, tagsWithMarkers, signer, createdAt)
|
||||
}
|
||||
|
||||
suspend fun create(
|
||||
dTag: String,
|
||||
originalNote: InteractiveStoryBaseEvent,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DraftEvent {
|
||||
val tags = mutableListOf<Array<String>>()
|
||||
return create(dTag, originalNote, tags, signer, createdAt)
|
||||
}
|
||||
|
||||
suspend fun create(
|
||||
dTag: String,
|
||||
originalNote: LiveActivitiesChatMessageEvent,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DraftEvent {
|
||||
val tags = mutableListOf<Array<String>>()
|
||||
originalNote.activity()?.let { tags.add(arrayOf("a", it.toTag(), "", "root")) }
|
||||
originalNote.replyingTo()?.let { tags.add(arrayOf("e", it, "", "reply")) }
|
||||
|
||||
return create(dTag, originalNote, tags, signer, createdAt)
|
||||
}
|
||||
|
||||
suspend fun create(
|
||||
dTag: String,
|
||||
originalNote: ChannelMessageEvent,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DraftEvent {
|
||||
val tags = mutableListOf<Array<String>>()
|
||||
originalNote.channelId()?.let { tags.add(arrayOf("e", it)) }
|
||||
|
||||
return create(dTag, originalNote, tags, signer, createdAt)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
suspend fun create(
|
||||
dTag: String,
|
||||
originalNote: GitReplyEvent,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DraftEvent {
|
||||
val tags = mutableListOf<Array<String>>()
|
||||
originalNote.repository()?.let { tags.add(arrayOf("a", it.toTag())) }
|
||||
originalNote.replyingTo()?.let { tags.add(arrayOf("e", it)) }
|
||||
|
||||
return create(dTag, originalNote, tags, signer, createdAt)
|
||||
}
|
||||
|
||||
suspend fun create(
|
||||
dTag: String,
|
||||
originalNote: PollNoteEvent,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DraftEvent {
|
||||
val tagsWithMarkers =
|
||||
originalNote.tags.filter {
|
||||
it.size > 3 && (it[0] == "e" || it[0] == "a") && (it[3] == "root" || it[3] == "reply")
|
||||
}
|
||||
|
||||
return create(dTag, originalNote, tagsWithMarkers, signer, createdAt)
|
||||
}
|
||||
|
||||
suspend fun create(
|
||||
dTag: String,
|
||||
originalNote: CommentEvent,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DraftEvent {
|
||||
val tagsWithMarkers = originalNote.rootScopes() + originalNote.directReplies()
|
||||
|
||||
return create(dTag, originalNote, tagsWithMarkers, signer, createdAt)
|
||||
}
|
||||
|
||||
suspend fun create(
|
||||
dTag: String,
|
||||
originalNote: TextNoteEvent,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DraftEvent {
|
||||
val tagsWithMarkers =
|
||||
originalNote.tags.filter {
|
||||
it.size > 3 && (it[0] == "e" || it[0] == "a") && (it[3] == "root" || it[3] == "reply")
|
||||
}
|
||||
|
||||
return create(dTag, originalNote, tagsWithMarkers, signer, createdAt)
|
||||
}
|
||||
|
||||
suspend fun create(
|
||||
dTag: String,
|
||||
innerEvent: Event,
|
||||
anchorTagArray: List<Array<String>> = emptyList(),
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DraftEvent {
|
||||
val tags = mutableListOf<Array<String>>()
|
||||
tags.add(arrayOf("d", dTag))
|
||||
tags.add(arrayOf("k", "${innerEvent.kind}"))
|
||||
|
||||
if (anchorTagArray.isNotEmpty()) {
|
||||
tags.addAll(anchorTagArray)
|
||||
}
|
||||
|
||||
val draft =
|
||||
signer.sign<DraftEvent>(
|
||||
createdAt = createdAt,
|
||||
kind = KIND,
|
||||
tags = tags.toTypedArray(),
|
||||
content = signer.nip44Encrypt(innerEvent.toJson(), signer.pubKey),
|
||||
)
|
||||
|
||||
return draft
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,8 +29,8 @@ class DraftEventCache(
|
||||
signer: NostrSigner,
|
||||
) {
|
||||
private val decryptionCache =
|
||||
object : LruCache<DraftEvent, DraftEventDecryptCache>(1000) {
|
||||
override fun create(key: DraftEvent): DraftEventDecryptCache? =
|
||||
object : LruCache<DraftWrapEvent, DraftEventDecryptCache>(1000) {
|
||||
override fun create(key: DraftWrapEvent): DraftEventDecryptCache? =
|
||||
if (!key.isDeleted() && key.pubKey == signer.pubKey) {
|
||||
DraftEventDecryptCache(signer)
|
||||
} else {
|
||||
@@ -38,23 +38,23 @@ class DraftEventCache(
|
||||
}
|
||||
}
|
||||
|
||||
fun delete(event: DraftEvent) = decryptionCache.remove(event)
|
||||
fun delete(event: DraftWrapEvent) = decryptionCache.remove(event)
|
||||
|
||||
fun preload(
|
||||
event: DraftEvent,
|
||||
event: DraftWrapEvent,
|
||||
result: Event,
|
||||
) = decryptionCache[event]?.preload(result)
|
||||
|
||||
fun preCachedDraft(event: DraftEvent): Event? = decryptionCache[event]?.cached()
|
||||
fun preCachedDraft(event: DraftWrapEvent): Event? = decryptionCache[event]?.cached()
|
||||
|
||||
suspend fun cachedDraft(event: DraftEvent) = decryptionCache[event]?.decrypt(event)
|
||||
suspend fun cachedDraft(event: DraftWrapEvent) = decryptionCache[event]?.decrypt(event)
|
||||
}
|
||||
|
||||
class DraftEventDecryptCache(
|
||||
signer: NostrSigner,
|
||||
) : DecryptCache<DraftEvent, Event>(signer) {
|
||||
) : DecryptCache<DraftWrapEvent, Event>(signer) {
|
||||
override suspend fun decryptAndParse(
|
||||
event: DraftEvent,
|
||||
event: DraftWrapEvent,
|
||||
signer: NostrSigner,
|
||||
): Event = event.decryptInnerEvent(signer)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* 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.nip37Drafts
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.fasterxml.jackson.core.JsonParseException
|
||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.kinds.kind
|
||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
@Immutable
|
||||
class DraftWrapEvent(
|
||||
id: HexKey,
|
||||
pubKey: HexKey,
|
||||
createdAt: Long,
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
fun isDeleted() = content == ""
|
||||
|
||||
fun canDecrypt(signer: NostrSigner) = signer.pubKey == pubKey
|
||||
|
||||
suspend fun decryptInnerEvent(signer: NostrSigner): Event {
|
||||
if (!canDecrypt(signer)) throw SignerExceptions.UnauthorizedDecryptionException()
|
||||
|
||||
val json = signer.nip44Decrypt(content, pubKey)
|
||||
return try {
|
||||
fromJson(json)
|
||||
} catch (e: JsonParseException) {
|
||||
Log.w("DraftEvent", "Unable to parse inner event of a draft: $json")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KIND = 31234
|
||||
const val ALT_DESCRIPTION = "Draft Event"
|
||||
|
||||
fun createAddress(
|
||||
pubKey: HexKey,
|
||||
dTag: String,
|
||||
): Address = Address(KIND, pubKey, dTag)
|
||||
|
||||
fun createAddressTag(
|
||||
pubKey: HexKey,
|
||||
dTag: String,
|
||||
): String = Address.assemble(KIND, pubKey, dTag)
|
||||
|
||||
suspend fun build(
|
||||
dTag: String,
|
||||
draft: Event,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<DraftWrapEvent>.() -> Unit = {},
|
||||
) = eventTemplate(
|
||||
kind = KIND,
|
||||
description = signer.nip44Encrypt(draft.toJson(), signer.pubKey),
|
||||
createdAt = createdAt,
|
||||
) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTag)
|
||||
kind(draft.kind)
|
||||
|
||||
initializer()
|
||||
}
|
||||
|
||||
suspend fun buildDeleted(
|
||||
dTag: String,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<DraftWrapEvent>.() -> Unit = {},
|
||||
) = eventTemplate(
|
||||
kind = KIND,
|
||||
description = "",
|
||||
createdAt = createdAt,
|
||||
) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
dTag(dTag)
|
||||
initializer()
|
||||
}
|
||||
|
||||
suspend fun create(
|
||||
dTag: String,
|
||||
draft: Event,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
) = signer.sign(build(dTag, draft, signer, createdAt))
|
||||
|
||||
suspend fun createDeletedEvent(
|
||||
dTag: String,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): DraftWrapEvent = signer.sign(buildDeleted(dTag, createdAt))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user