mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
fix: address review findings on the event rename branch
- Deprecated aliases for merged classes now keep their old companion API: TokenEvent.build(encryptedContent), NutzapRedemptionEvent.build(nutzap, content), SoftwareReleaseEvent.build(appId, version, channel, assets) and buildDTag resolve to deprecated forwarders instead of an incompatible builder. Covered by DeprecatedMergedEventApiTest. - CashuWalletOps.redeemNutzap now tags the nutzap sender (NIP-61 ["p", sender]), using the notifySender helper from the merge. - TokenReference.parseFromTag requires a 64-char id, like ETag, so redeemedReferences() and redeemedNutzaps() agree; drop the per-tag list allocation. - Kind 30063 search: check content is non-blank before the two NIP-82 tag scans. - SoftwareApp: findAll/findLatest release lookups no longer re-run the NIP-82 and d-tag checks that the addressables scan already applied; cheap d-tag check first. - Deprecate asSoftwareRelease(): EventFactory already builds ReleaseArtifactSetEvent, and re-wrapping another kind breaks its id/sig. - Replace inline fully-qualified names touched by the rename with imports. - nostr-expert event-hierarchy doc: describe the real NIP-51 class hierarchy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015VvJ8XpeYqBe8bYT3bJ7UD
This commit is contained in:
@@ -95,14 +95,22 @@ class LongFormContentEvent(...) : BaseAddressableEvent(...)
|
||||
// Addressable via kind:pubkey:d-tag
|
||||
```
|
||||
|
||||
### Lists (kinds 10000-30004)
|
||||
### Lists (NIP-51)
|
||||
Each list kind is its own class under `nip51Lists/`, not a subtype of a shared list event.
|
||||
Lists with private (NIP-44 encrypted) items extend one of two bases:
|
||||
```kotlin
|
||||
sealed class FollowSetEvent : BaseAddressableEvent {
|
||||
object MuteList : FollowSetEvent(10000)
|
||||
object PinList : FollowSetEvent(10001)
|
||||
object BookmarkList : FollowSetEvent(10003)
|
||||
// ... 18 list types total
|
||||
}
|
||||
// Base for sets (kind 30000-39999); some replaceable lists use it too (MuteListEvent, InterestListEvent)
|
||||
abstract class PrivateTagArrayEvent(...) : BaseAddressableEvent(...)
|
||||
// Replaceable lists (kind 10000-19999)
|
||||
abstract class PrivateReplaceableTagArrayEvent(...) : BaseReplaceableEvent(...)
|
||||
|
||||
class MuteListEvent(...) : PrivateTagArrayEvent(...) // kind 10000
|
||||
class PinListEvent(...) : BaseReplaceableEvent(...) // kind 10001, public only
|
||||
class BookmarkListEvent(...) : PrivateReplaceableTagArrayEvent(...) // kind 10003
|
||||
class InterestListEvent(...) : PrivateTagArrayEvent(...) // kind 10015
|
||||
class FollowSetEvent(...) : PrivateTagArrayEvent(...) // kind 30000 follow sets
|
||||
class BookmarkSetEvent(...) : PrivateTagArrayEvent(...) // kind 30003 bookmark sets
|
||||
class StarterPackEvent(...) : BaseAddressableEvent(...) // kind 39089 starter packs
|
||||
```
|
||||
|
||||
## Event Interfaces
|
||||
|
||||
@@ -242,7 +242,7 @@ fun produceLatestReleaseVersion(app: SoftwareApplicationEvent): State<String?> {
|
||||
return flow.collectAsStateWithLifecycle(initialValue = null)
|
||||
}
|
||||
|
||||
fun findLatestNip82Release(app: SoftwareApplicationEvent): ReleaseArtifactSetEvent? = latestNip82Release(nip82ReleaseNotesFor(app), app)
|
||||
fun findLatestNip82Release(app: SoftwareApplicationEvent): ReleaseArtifactSetEvent? = nip82ReleasesFor(app).maxByOrNull { it.createdAt }
|
||||
|
||||
/** Picks the newest NIP-82 release for [app] out of an already-narrowed [notes] collection. */
|
||||
private fun latestNip82Release(
|
||||
@@ -256,12 +256,13 @@ private fun latestNip82Release(
|
||||
}
|
||||
|
||||
/** kind-30063 addressables authored by [app] whose `d` tag is `<app-id>@<version>`. */
|
||||
private fun nip82ReleaseNotesFor(app: SoftwareApplicationEvent): Set<Note> {
|
||||
private fun nip82ReleasesFor(app: SoftwareApplicationEvent): List<ReleaseArtifactSetEvent> {
|
||||
val prefix = "${app.dTag()}@"
|
||||
return LocalCache.addressables.filterIntoSet(ReleaseArtifactSetEvent.KIND, app.pubKey) { _, addr ->
|
||||
return LocalCache.addressables
|
||||
.filterIntoSet(ReleaseArtifactSetEvent.KIND, app.pubKey) { _, addr ->
|
||||
val ev = addr.event ?: return@filterIntoSet false
|
||||
ev.isNip82SoftwareRelease() && ev.dTag().startsWith(prefix)
|
||||
}
|
||||
ev.dTag().startsWith(prefix) && ev.isNip82SoftwareRelease()
|
||||
}.mapNotNull { it.event as? ReleaseArtifactSetEvent }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,15 +271,10 @@ private fun nip82ReleaseNotesFor(app: SoftwareApplicationEvent): Set<Note> {
|
||||
*/
|
||||
private fun Note.asNip82ReleaseFor(prefix: String): ReleaseArtifactSetEvent? {
|
||||
val ev = event as? ReleaseArtifactSetEvent ?: return null
|
||||
return ev.takeIf { it.isNip82SoftwareRelease() && it.dTag().startsWith(prefix) }
|
||||
return ev.takeIf { it.dTag().startsWith(prefix) && it.isNip82SoftwareRelease() }
|
||||
}
|
||||
|
||||
fun findAllNip82Releases(app: SoftwareApplicationEvent): List<ReleaseArtifactSetEvent> {
|
||||
val prefix = "${app.dTag()}@"
|
||||
return nip82ReleaseNotesFor(app)
|
||||
.mapNotNull { it.asNip82ReleaseFor(prefix) }
|
||||
.sortedByDescending { it.createdAt }
|
||||
}
|
||||
fun findAllNip82Releases(app: SoftwareApplicationEvent): List<ReleaseArtifactSetEvent> = nip82ReleasesFor(app).sortedByDescending { it.createdAt }
|
||||
|
||||
@Composable
|
||||
fun AppIcon(
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ class NewCalendarCollectionViewModel : ViewModel() {
|
||||
private var dTag: String? = null
|
||||
|
||||
/** The full original event in edit mode; needed to publish a NIP-09 deletion. */
|
||||
private var loadedEvent: com.vitorpamplona.quartz.nip52Calendar.calendar.CalendarCollectionEvent? = null
|
||||
private var loadedEvent: CalendarCollectionEvent? = null
|
||||
|
||||
val selectedAddresses = mutableStateListOf<Address>()
|
||||
val availableAppointments = mutableStateOf<List<OwnedAppointmentSummary>>(emptyList())
|
||||
|
||||
+2
-1
@@ -62,6 +62,7 @@ import com.vitorpamplona.quartz.nip47WalletConnect.rpc.Response
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent
|
||||
import com.vitorpamplona.quartz.nip55AndroidSigner.client.NostrSignerExternal
|
||||
import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.ZapRequestEvent
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent
|
||||
import com.vitorpamplona.quartz.nipB1Bolt12Zaps.zap.Bolt12ZapEvent
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
@@ -1787,7 +1788,7 @@ class AmethystAppFunctions {
|
||||
lnAddress: String,
|
||||
sats: Long,
|
||||
comment: String,
|
||||
zapRequest: com.vitorpamplona.quartz.nip57Zaps.ZapRequestEvent,
|
||||
zapRequest: ZapRequestEvent,
|
||||
): String {
|
||||
// Compute the LNURL-pay endpoint so we can ask the privacy-aware
|
||||
// HttpClient builder for the right OkHttpClient for that host.
|
||||
|
||||
+5
-1
@@ -57,6 +57,7 @@ import com.vitorpamplona.quartz.nip60Cashu.wallet.CashuWalletEvent
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.info.NutzapInfoEvent
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.info.tags.NutzapMintTag
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.NutzapEvent
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.redemption.notifySender
|
||||
import com.vitorpamplona.quartz.nip87Ecash.cashu.CashuMintEvent
|
||||
import com.vitorpamplona.quartz.nip87Ecash.recommendation.MintRecommendationEvent
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
@@ -914,7 +915,10 @@ class CashuWalletOps(
|
||||
TokenReference(nutzap.id, null, TokenReference.MARKER_REDEEMED),
|
||||
),
|
||||
signer = signer,
|
||||
)
|
||||
) {
|
||||
// NIP-61: tag the nutzap sender so their client learns it was redeemed.
|
||||
notifySender(EventHintBundle(nutzap))
|
||||
}
|
||||
val historyEvent = signer.sign(historyTemplate)
|
||||
publish(historyEvent)
|
||||
|
||||
|
||||
+2
-1
@@ -45,6 +45,7 @@ import com.vitorpamplona.nestsclient.connectReconnectingNestsSpeaker
|
||||
import com.vitorpamplona.nestsclient.transport.WebTransportFactory
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent
|
||||
import com.vitorpamplona.quartz.nipB1Bolt12Zaps.zap.Bolt12ZapEvent
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import kotlinx.collections.immutable.ImmutableSet
|
||||
@@ -629,7 +630,7 @@ class NestViewModel(
|
||||
* same window so the visual cadence matches the React button.
|
||||
*/
|
||||
fun onZapEvent(
|
||||
event: com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent,
|
||||
event: ZapReceiptEvent,
|
||||
nowSec: Long,
|
||||
windowSec: Long = REACTION_WINDOW_SEC,
|
||||
) {
|
||||
|
||||
@@ -166,6 +166,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.sockets.okhttp.BasicOkHttpWebSocket
|
||||
import com.vitorpamplona.quartz.nip04Dm.messages.EncryptedDmEvent
|
||||
import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable
|
||||
import com.vitorpamplona.quartz.nip17Dm.settings.DmRelayListEvent
|
||||
import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent
|
||||
@@ -1926,7 +1927,7 @@ fun MainContent(
|
||||
|
||||
// Process into chatroomList based on event type
|
||||
when (event) {
|
||||
is com.vitorpamplona.quartz.nip04Dm.messages.EncryptedDmEvent -> {
|
||||
is EncryptedDmEvent -> {
|
||||
iAccount.chatroomList.addMessage(
|
||||
event.chatroomKey(iAccount.pubKey),
|
||||
note,
|
||||
|
||||
+2
-1
@@ -39,6 +39,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.fetchAll
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent
|
||||
import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import kotlinx.coroutines.CancellationException
|
||||
@@ -310,7 +311,7 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
),
|
||||
// Zap receipts (kind 9735) targeting these notes
|
||||
Filter(
|
||||
kinds = listOf(com.vitorpamplona.quartz.nip57Zaps.ZapReceiptEvent.KIND),
|
||||
kinds = listOf(ZapReceiptEvent.KIND),
|
||||
tags = mapOf("e" to noteIds),
|
||||
),
|
||||
// Reposts (kind 6) targeting these notes
|
||||
|
||||
+2
-1
@@ -84,6 +84,7 @@ import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NNote
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NProfile
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NPub
|
||||
import com.vitorpamplona.quartz.nip51Lists.starterPack.StarterPackEvent
|
||||
import java.awt.Toolkit
|
||||
import java.awt.datatransfer.StringSelection
|
||||
import java.net.URI
|
||||
@@ -376,7 +377,7 @@ private fun RenderBechSegment(
|
||||
.NAddress
|
||||
.parse(segment.segmentText)
|
||||
}
|
||||
if (naddr != null && naddr.kind == com.vitorpamplona.quartz.nip51Lists.starterPack.StarterPackEvent.KIND) {
|
||||
if (naddr != null && naddr.kind == StarterPackEvent.KIND) {
|
||||
val followPacks = com.vitorpamplona.amethyst.desktop.ui.deck.LocalFollowPacksState.current
|
||||
val relayManager = com.vitorpamplona.amethyst.desktop.ui.deck.LocalRelayManager.current
|
||||
if (localCache != null && relayManager != null && followPacks != null) {
|
||||
|
||||
+5
@@ -44,4 +44,9 @@ fun Event.isNip82SoftwareRelease() =
|
||||
* Reinterprets `this` as a [ReleaseArtifactSetEvent]. Use [isNip82SoftwareRelease]
|
||||
* to gate the call.
|
||||
*/
|
||||
@Deprecated(
|
||||
"EventFactory already builds kind 30063 as ReleaseArtifactSetEvent, which exposes the NIP-82 fields. " +
|
||||
"Re-wrapping an event of another kind yields one whose kind no longer matches its id and signature.",
|
||||
ReplaceWith("this as ReleaseArtifactSetEvent", "com.vitorpamplona.quartz.nip51Lists.releaseArtifactSet.ReleaseArtifactSetEvent"),
|
||||
)
|
||||
fun Event.asSoftwareRelease() = this as? ReleaseArtifactSetEvent ?: ReleaseArtifactSetEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
|
||||
+32
@@ -20,7 +20,11 @@
|
||||
*/
|
||||
package com.vitorpamplona.quartz.experimental.nip82SoftwareApps.release
|
||||
|
||||
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.asset.SoftwareAssetEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||
import com.vitorpamplona.quartz.nip51Lists.releaseArtifactSet.ReleaseArtifactSetEvent
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
/**
|
||||
* NIP-82 software releases share kind 30063 with NIP-51 release artifact sets, and
|
||||
@@ -32,3 +36,31 @@ import com.vitorpamplona.quartz.nip51Lists.releaseArtifactSet.ReleaseArtifactSet
|
||||
ReplaceWith("ReleaseArtifactSetEvent", "com.vitorpamplona.quartz.nip51Lists.releaseArtifactSet.ReleaseArtifactSetEvent"),
|
||||
)
|
||||
typealias SoftwareReleaseEvent = ReleaseArtifactSetEvent
|
||||
|
||||
/** The old `SoftwareReleaseEvent.buildDTag`. */
|
||||
@Deprecated(
|
||||
"Use ReleaseArtifactSetEvent.buildSoftwareReleaseDTag.",
|
||||
ReplaceWith("ReleaseArtifactSetEvent.buildSoftwareReleaseDTag(appId, version)", "com.vitorpamplona.quartz.nip51Lists.releaseArtifactSet.ReleaseArtifactSetEvent"),
|
||||
)
|
||||
fun ReleaseArtifactSetEvent.Companion.buildDTag(
|
||||
appId: String,
|
||||
version: String,
|
||||
) = buildSoftwareReleaseDTag(appId, version)
|
||||
|
||||
/** The old `SoftwareReleaseEvent.build`: a NIP-82 release, not the NIP-51 set builder. */
|
||||
@Deprecated(
|
||||
"Use ReleaseArtifactSetEvent.buildSoftwareRelease.",
|
||||
ReplaceWith(
|
||||
"ReleaseArtifactSetEvent.buildSoftwareRelease(appId, version, channel, assets, releaseNotes, createdAt, initializer)",
|
||||
"com.vitorpamplona.quartz.nip51Lists.releaseArtifactSet.ReleaseArtifactSetEvent",
|
||||
),
|
||||
)
|
||||
fun ReleaseArtifactSetEvent.Companion.build(
|
||||
appId: String,
|
||||
version: String,
|
||||
channel: String,
|
||||
assets: List<EventHintBundle<SoftwareAssetEvent>>,
|
||||
releaseNotes: String = "",
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<ReleaseArtifactSetEvent>.() -> Unit = {},
|
||||
) = buildSoftwareRelease(appId, version, channel, assets, releaseNotes, createdAt, initializer)
|
||||
|
||||
+3
-2
@@ -82,8 +82,9 @@ class ReleaseArtifactSetEvent(
|
||||
}
|
||||
|
||||
// Only NIP-82 releases carry release notes in `content`. A NIP-51 set may keep
|
||||
// encrypted private items there, which must never reach the index.
|
||||
private fun searchableReleaseNotes() = if (isNip82SoftwareRelease()) content.ifBlank { null } else null
|
||||
// encrypted private items there, which must never reach the index. The blank
|
||||
// check runs first so empty sets skip the two tag scans on every search.
|
||||
private fun searchableReleaseNotes() = if (content.isNotBlank() && isNip82SoftwareRelease()) content else null
|
||||
|
||||
override fun eventHints() = tags.mapNotNull(EventBookmark::parseAsHint)
|
||||
|
||||
|
||||
+4
-2
@@ -43,9 +43,11 @@ data class TokenReference(
|
||||
const val MARKER_REDEEMED = "redeemed"
|
||||
|
||||
fun parseFromTag(tag: Array<String>): TokenReference? {
|
||||
if (tag.size < 4 || tag[0] != "e") return null
|
||||
// Same id rule as ETag.parse, so redeemedReferences() and the NIP-61
|
||||
// redeemedNutzaps() agree on which tags are valid.
|
||||
if (tag.size < 4 || tag[0] != "e" || tag[1].length != 64) return null
|
||||
val marker = tag[3]
|
||||
if (marker !in listOf(MARKER_CREATED, MARKER_DESTROYED, MARKER_REDEEMED)) return null
|
||||
if (marker != MARKER_CREATED && marker != MARKER_DESTROYED && marker != MARKER_REDEEMED) return null
|
||||
return TokenReference(
|
||||
eventId = tag[1],
|
||||
relay = tag.getOrNull(2)?.ifEmpty { null },
|
||||
|
||||
+16
@@ -44,6 +44,22 @@ fun CashuSpendingHistoryEvent.Companion.buildNutzapRedemption(
|
||||
initializer()
|
||||
}
|
||||
|
||||
/** The old `NutzapRedemptionEvent.build`. */
|
||||
@Deprecated(
|
||||
"Use CashuSpendingHistoryEvent.buildNutzapRedemption.",
|
||||
ReplaceWith(
|
||||
"CashuSpendingHistoryEvent.buildNutzapRedemption(nutzap, encryptedContent, createdAt, initializer)",
|
||||
"com.vitorpamplona.quartz.nip60Cashu.history.CashuSpendingHistoryEvent",
|
||||
"com.vitorpamplona.quartz.nip61Nutzaps.redemption.buildNutzapRedemption",
|
||||
),
|
||||
)
|
||||
fun CashuSpendingHistoryEvent.Companion.build(
|
||||
nutzap: EventHintBundle<NutzapEvent>,
|
||||
encryptedContent: String,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<CashuSpendingHistoryEvent>.() -> Unit = {},
|
||||
) = buildNutzapRedemption(nutzap, encryptedContent, createdAt, initializer)
|
||||
|
||||
/**
|
||||
* NIP-61 redemptions are NIP-60 spending history events (kind 7376). This used to be a
|
||||
* second class for the same kind, which `EventFactory` could never instantiate because
|
||||
|
||||
+16
@@ -20,7 +20,10 @@
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip61Nutzaps.token
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip60Cashu.token.CashuTokenEvent
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
/**
|
||||
* NIP-61 does not define its own kind 7375: redeemed nutzap proofs are stored as
|
||||
@@ -32,3 +35,16 @@ import com.vitorpamplona.quartz.nip60Cashu.token.CashuTokenEvent
|
||||
ReplaceWith("CashuTokenEvent", "com.vitorpamplona.quartz.nip60Cashu.token.CashuTokenEvent"),
|
||||
)
|
||||
typealias TokenEvent = CashuTokenEvent
|
||||
|
||||
/** The old `TokenEvent.build` took content that was already encrypted. */
|
||||
@Deprecated(
|
||||
"Use CashuTokenEvent.build(tokenContent, signer), which encrypts the token content.",
|
||||
ReplaceWith("CashuTokenEvent.build(tokenContent, signer)", "com.vitorpamplona.quartz.nip60Cashu.token.CashuTokenEvent"),
|
||||
)
|
||||
fun CashuTokenEvent.Companion.build(
|
||||
encryptedContent: String,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<CashuTokenEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, encryptedContent, createdAt) {
|
||||
initializer()
|
||||
}
|
||||
|
||||
+3
-6
@@ -32,7 +32,6 @@ import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.asset.SoftwareAss
|
||||
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.asset.apkCertificateHash
|
||||
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.asset.platform
|
||||
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.asset.versionCode
|
||||
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.release.asSoftwareRelease
|
||||
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.release.isNip82SoftwareRelease
|
||||
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.shared.Platform
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
@@ -137,13 +136,12 @@ class SoftwareApplicationEventTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun asSoftwareRelease_exposesParsedFields() {
|
||||
val event =
|
||||
Event(
|
||||
fun releaseArtifactSet_exposesParsedNip82Fields() {
|
||||
val release =
|
||||
ReleaseArtifactSetEvent(
|
||||
id = "0".repeat(64),
|
||||
pubKey = "1".repeat(64),
|
||||
createdAt = 0,
|
||||
kind = ReleaseArtifactSetEvent.KIND,
|
||||
tags =
|
||||
arrayOf(
|
||||
arrayOf("d", "com.example.app@1.0.0"),
|
||||
@@ -154,7 +152,6 @@ class SoftwareApplicationEventTest {
|
||||
content = "Initial release",
|
||||
sig = "",
|
||||
)
|
||||
val release = event.asSoftwareRelease()
|
||||
assertEquals("com.example.app", release.appId())
|
||||
assertEquals("1.0.0", release.version())
|
||||
assertEquals("main", release.channel())
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.vitorpamplona.quartz.utils
|
||||
|
||||
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.release.SoftwareReleaseEvent
|
||||
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.release.build
|
||||
import com.vitorpamplona.quartz.experimental.nip82SoftwareApps.release.buildDTag
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||
import com.vitorpamplona.quartz.nip60Cashu.history.CashuSpendingHistoryEvent
|
||||
import com.vitorpamplona.quartz.nip60Cashu.token.CashuTokenEvent
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.nutzap.NutzapEvent
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.redemption.NutzapRedemptionEvent
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.redemption.build
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.token.TokenEvent
|
||||
import com.vitorpamplona.quartz.nip61Nutzaps.token.build
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
/**
|
||||
* The classes merged into another class keep their old companion calls compiling
|
||||
* through the deprecated typealiases. If any of these stop resolving, external
|
||||
* Quartz users break on upgrade.
|
||||
*/
|
||||
class DeprecatedMergedEventApiTest {
|
||||
private val nutzap = NutzapEvent("a".repeat(64), "1".repeat(64), 1, emptyArray(), "", "b".repeat(128))
|
||||
|
||||
@Test
|
||||
fun tokenEventBuildStillTakesEncryptedContent() {
|
||||
val template = TokenEvent.build("encrypted")
|
||||
assertEquals(CashuTokenEvent.KIND, template.kind)
|
||||
assertEquals("encrypted", template.content)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nutzapRedemptionBuildStillAddsRedeemedAndSenderTags() {
|
||||
val template = NutzapRedemptionEvent.build(EventHintBundle(nutzap), "encrypted")
|
||||
assertEquals(CashuSpendingHistoryEvent.KIND, template.kind)
|
||||
assertEquals(listOf("e", "p"), template.tags.map { it[0] })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun softwareReleaseBuildStillBuildsNip82Release() {
|
||||
assertEquals("app@1.0", SoftwareReleaseEvent.buildDTag("app", "1.0"))
|
||||
val template = SoftwareReleaseEvent.build("app", "1.0", "main", emptyList())
|
||||
assertEquals("app@1.0", template.tags.first { it[0] == "d" }[1])
|
||||
assertEquals("1.0", template.tags.first { it[0] == "version" }[1])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user