feat: Enter repository as nip5

For example, `4rs.nl/n34` and `_@4rs.nl/n34`

Signed-off-by: Awiteb <a@4rs.nl>
This commit is contained in:
Awiteb
2025-05-24 11:00:37 +00:00
parent f7e837e3ab
commit de68d61c3f
4 changed files with 50 additions and 17 deletions

View File

@@ -39,10 +39,11 @@ use crate::{
) )
)] )]
pub struct NewArgs { pub struct NewArgs {
/// Repository address in `naddr` format. /// Repository address in `naddr` format or `<nip5>/repo_id`. e.g.
/// `4rs.nl/n34` and `_@4rs.nl/n34`
/// ///
/// If not provided, `n34` will look for a `nostr-address` file. /// If not provided, `n34` will look for the `nostr-address` file.
#[arg(short, long, value_parser = parsers::repo_naddr)] #[arg(value_name = "NADDR-OR-NIP05", long = "repo", value_parser = parsers::repo_naddr)]
naddr: Option<Nip19Coordinate>, naddr: Option<Nip19Coordinate>,
/// Markdown content for the issue. Cannot be used together with the /// Markdown content for the issue. Cannot be used together with the
/// `--editor` flag. /// `--editor` flag.

View File

@@ -90,16 +90,17 @@ impl FromStr for NostrEvent {
)] )]
pub struct ReplyArgs { pub struct ReplyArgs {
/// The issue, patch, or comment to reply to /// The issue, patch, or comment to reply to
#[arg(long)] #[arg(long, value_name = "nevent1-or-note1")]
to: NostrEvent, to: NostrEvent,
/// Quote the replied-to event in the editor /// Quote the replied-to event in the editor
#[arg(long)] #[arg(long)]
quote_to: bool, quote_to: bool,
/// Repository address in `naddr` format. /// Repository address in `naddr` format or `<nip5>/repo_id`. e.g.
/// `4rs.nl/n34` and `_@4rs.nl/n34`
/// ///
/// If not provided, `n34` will look for the `nostr-address` file and if not /// If not provided, `n34` will look for the `nostr-address` file and if not
/// found, will get it from the root event if found. /// found, will get it from the root event if found.
#[arg(short, long, value_parser = parsers::repo_naddr)] #[arg(value_name = "NADDR-OR-NIP05", long = "repo", value_parser = parsers::repo_naddr)]
naddr: Option<Nip19Coordinate>, naddr: Option<Nip19Coordinate>,
/// The comment (cannot be used with --editor) /// The comment (cannot be used with --editor)
#[arg(short, long)] #[arg(short, long)]

View File

@@ -28,10 +28,11 @@ use crate::{
/// Arguments for the `repo view` command /// Arguments for the `repo view` command
#[derive(Args, Debug)] #[derive(Args, Debug)]
pub struct ViewArgs { pub struct ViewArgs {
/// Repository address in `naddr` format. /// Repository address in `naddr` format or `<nip5>/repo_id`. e.g.
/// `4rs.nl/n34` and `_@4rs.nl/n34`
/// ///
/// If not provided, `n34` will look for a `nostr-address` file. /// If not provided, `n34` will look for the `nostr-address` file.
#[arg(short, long, value_parser = parsers::repo_naddr)] #[arg(value_name = "NADDR-OR-NIP05", long = "repo", value_parser = parsers::repo_naddr)]
naddr: Option<Nip19Coordinate>, naddr: Option<Nip19Coordinate>,
} }

View File

@@ -16,17 +16,47 @@
use nostr::{ use nostr::{
Kind, Kind,
nips::nip19::{FromBech32, Nip19Coordinate}, nips::{
self,
nip01::Coordinate,
nip19::{FromBech32, Nip19Coordinate},
},
}; };
use tokio::runtime::Handle;
/// Parses a Nostr naddr string into a Git repository announcement coordinate. fn parse_nip5_repo(nip5: &str, repo_id: &str) -> Result<Nip19Coordinate, String> {
let (username, domain) = nip5.split_once("@").unwrap_or(("_", nip5));
let nip5_profile = tokio::task::block_in_place(|| {
Handle::current().block_on(async {
nips::nip05::profile(format!("{username}@{domain}"), None)
.await
.map_err(|err| err.to_string())
})
})?;
Ok(Nip19Coordinate::new(
Coordinate::new(Kind::GitRepoAnnouncement, nip5_profile.public_key).identifier(repo_id),
nip5_profile.relays,
)
.expect("The relays is `RelayUrl`"))
}
/// Parses a Git repository address which can be either:
/// - A bech32-encoded naddr (e.g. "naddr1...") for Git repository announcements
/// (kind 30617)
/// - A NIP-05 identifier with repository ID (e.g. "4rs.nl/n34" or
/// "_@4rs.nl/n34")
/// ///
/// # Errors /// Returns an error for invalid formats, failed bech32 decoding, wrong event
/// Returns an error if: /// kind.
/// - The bech32 decoding fails pub fn repo_naddr(repo_address: &str) -> Result<Nip19Coordinate, String> {
/// - The naddr doesn't represent a Git repository announcement (kind != 30617) if repo_address.contains("/") {
pub fn repo_naddr(naddr: &str) -> Result<Nip19Coordinate, String> { let (nip5, repo_id) = repo_address.split_once("/").expect("There is a `/`");
let naddr = Nip19Coordinate::from_bech32(naddr).map_err(|err| err.to_string())?; return parse_nip5_repo(nip5, repo_id);
}
let naddr = Nip19Coordinate::from_bech32(repo_address).map_err(|err| err.to_string())?;
if naddr.kind != Kind::GitRepoAnnouncement { if naddr.kind != Kind::GitRepoAnnouncement {
return Err("The naddr is not repo announcement address".to_owned()); return Err("The naddr is not repo announcement address".to_owned());
} }