mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 11:18:24 +00:00
feat(cli): offer discover <nip05> — resolve a profile offer via NIP-05
Mirrors the app's NIP-05 .well-known clink_offer discovery fallback (kind-0 offers are already readable via 'amy profile show'). Reuses the Context's nip05Client.loadClinkOffer and decodes the resolved noffer into its fields. Adds a bad-nip05 validation case to the headless harness; 17/17 pass. https://claude.ai/code/session_01NM2TyJtosLdY5ycjyabSRS
This commit is contained in:
@@ -31,12 +31,14 @@ import com.vitorpamplona.quartz.experimental.clink.offers.OfferResponse
|
||||
import com.vitorpamplona.quartz.experimental.clink.pointers.ClinkPointerParser
|
||||
import com.vitorpamplona.quartz.experimental.clink.pointers.NDebit
|
||||
import com.vitorpamplona.quartz.experimental.clink.pointers.NOffer
|
||||
import com.vitorpamplona.quartz.nip05DnsIdentifiers.Nip05Id
|
||||
|
||||
/**
|
||||
* `amy offer …` — CLINK Offers (`noffer1…`) from the command line, for headless interop
|
||||
* testing against a real offer service.
|
||||
*
|
||||
* - `info <noffer>` decodes a pointer locally (no network).
|
||||
* - `discover <nip05>` resolves a profile's advertised offer from its NIP-05 `.well-known`.
|
||||
* - `request <noffer> [--amount N] [--timeout MS] [--follow]` runs the kind-21001 round-trip:
|
||||
* publishes the request to the pointer's relays and prints the returned BOLT-11. With
|
||||
* `--follow` it chases an "Expired or Moved" (code 3) reply to the `latest` pointer.
|
||||
@@ -54,13 +56,55 @@ object OfferCommands {
|
||||
dataDir: DataDir,
|
||||
tail: Array<String>,
|
||||
): Int {
|
||||
if (tail.isEmpty()) return Output.error("bad_args", "offer <info|request|pay>")
|
||||
if (tail.isEmpty()) return Output.error("bad_args", "offer <info|discover|request|pay>")
|
||||
val rest = tail.drop(1).toTypedArray()
|
||||
return when (tail[0]) {
|
||||
"info" -> info(rest)
|
||||
"discover" -> discover(dataDir, rest)
|
||||
"request" -> request(dataDir, rest)
|
||||
"pay" -> pay(dataDir, rest)
|
||||
else -> Output.error("bad_args", "offer ${tail[0]} (expected info|request|pay)")
|
||||
else -> Output.error("bad_args", "offer ${tail[0]} (expected info|discover|request|pay)")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a profile's advertised offer from its NIP-05 `.well-known/nostr.json` `clink_offer`
|
||||
* (the app's discovery fallback). A profile's kind-0 `clink_offer` is readable via
|
||||
* `amy profile show <user>`.
|
||||
*/
|
||||
private suspend fun discover(
|
||||
dataDir: DataDir,
|
||||
rest: Array<String>,
|
||||
): Int {
|
||||
val args = Args(rest)
|
||||
val id =
|
||||
Nip05Id.parse(args.positional(0, "nip05").trim())
|
||||
?: return Output.error("bad_args", "not a valid NIP-05 address (e.g. bob@example.com)")
|
||||
|
||||
val ctx = Context.open(dataDir)
|
||||
try {
|
||||
ctx.prepare()
|
||||
val noffer = ctx.nip05Client.loadClinkOffer(id)
|
||||
if (noffer == null) {
|
||||
Output.emit(mapOf("nip05" to id.toDisplayValue(), "found" to false))
|
||||
return 0
|
||||
}
|
||||
val offer = ClinkPointerParser.parse(noffer) as? NOffer
|
||||
Output.emit(
|
||||
mapOf(
|
||||
"nip05" to id.toDisplayValue(),
|
||||
"found" to true,
|
||||
"noffer" to noffer,
|
||||
"pubkey" to offer?.pubKey,
|
||||
"relays" to offer?.relays?.map { it.url },
|
||||
"pointer" to offer?.pointer,
|
||||
"price_type" to offer?.priceType?.name?.lowercase(),
|
||||
"price_sats" to offer?.price,
|
||||
),
|
||||
)
|
||||
return 0
|
||||
} finally {
|
||||
ctx.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -146,3 +146,11 @@ if amy_a zap user "$EXPECTED_PUB" 1000 --with "not-an-ndebit" >>"$LOG_FILE" 2>&1
|
||||
else
|
||||
record_result zap.with.bad pass "bad --with exits non-zero"
|
||||
fi
|
||||
|
||||
# --- offer discover: rejects a malformed NIP-05 (validated before any network) ---
|
||||
step "offer discover rejects a non-nip05 address"
|
||||
if amy_a offer discover "not-a-nip05" >>"$LOG_FILE" 2>&1; then
|
||||
record_result offer.discover.bad fail "bad nip05 should exit non-zero"
|
||||
else
|
||||
record_result offer.discover.bad pass "bad nip05 exits non-zero"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user