From 15bf0d0b6befae6c81631c0e5d0dc2947dd3318a Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 11 Feb 2026 09:20:48 +0000 Subject: feat: use fallback relays for bootstrapping only - Add --relay flag to 'ngit account create' allowing users to specify relay URLs (repeatable). Defaults to relay-default-set when not provided. - Remove fallback relays from fetch when repo context exists (repo coordinate provided). Only use them for bootstrapping (profile discovery with no repo context). - Remove fallback relays from publish when repo or user relays exist. Only use them when neither is available (e.g. new account signup). - Update --customize help text to reflect new relay-default-set behavior. --- src/bin/ngit/cli.rs | 2 +- src/bin/ngit/sub_commands/create.rs | 30 +++++++++++++++++++++++------- src/lib/client.rs | 20 ++++++++++++++++++-- src/lib/login/fresh.rs | 17 ++++++++++++----- src/lib/login/user.rs | 2 ++ 5 files changed, 56 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/bin/ngit/cli.rs b/src/bin/ngit/cli.rs index d2246d7..47f4b27 100644 --- a/src/bin/ngit/cli.rs +++ b/src/bin/ngit/cli.rs @@ -53,7 +53,7 @@ ngit settings are managed through the git config. Currently the only settings not reachable through standard commands relate to default hardcoded relays: - nostr.grasp-default-set - only used during `ngit init` - - nostr.relay-default-set - must have at least 1 value, all events send to repo relays, user write and default relays + - nostr.relay-default-set - used for profile discovery and account bootstrapping - nostr.relay-blaster-set - only used for repo announcement events - nostr.relay-signer-fallback-set diff --git a/src/bin/ngit/sub_commands/create.rs b/src/bin/ngit/sub_commands/create.rs index e0d89b5..1c2b8db 100644 --- a/src/bin/ngit/sub_commands/create.rs +++ b/src/bin/ngit/sub_commands/create.rs @@ -16,6 +16,11 @@ pub struct SubCommandArgs { #[arg(long, required = true)] pub name: String, + /// Relay URLs for the new account's relay list (can be specified multiple + /// times). Defaults to the relay-default-set if not provided. + #[arg(long = "relay", value_parser, num_args = 1)] + pub relays: Vec, + /// Don't publish metadata to relays (offline mode) #[arg(long)] pub offline: bool, @@ -28,20 +33,31 @@ pub struct SubCommandArgs { pub async fn launch(_cli: &Cli, args: &SubCommandArgs) -> Result<()> { let git_repo = Repo::discover().ok(); + let params = Params::with_git_config_relay_defaults(&git_repo.as_ref()); + + let relay_urls = if args.relays.is_empty() { + params.relay_default_set.clone() + } else { + args.relays.clone() + }; + let client = if args.offline { None } else { - Some(Client::new(Params::with_git_config_relay_defaults( - &git_repo.as_ref(), - ))) + Some(Client::new(params)) }; let publish = !args.offline; - let (_signer, public_key, _signer_info, keys) = - signup_non_interactive(args.name.clone(), client.as_ref(), args.local, publish) - .await - .context("failed to create account")?; + let (_signer, public_key, _signer_info, keys) = signup_non_interactive( + args.name.clone(), + client.as_ref(), + args.local, + publish, + relay_urls, + ) + .await + .context("failed to create account")?; // Display the generated nsec prominently println!("\n✓ Account created successfully!"); diff --git a/src/lib/client.rs b/src/lib/client.rs index 9c49653..89fcaf7 100644 --- a/src/lib/client.rs +++ b/src/lib/client.rs @@ -1577,7 +1577,14 @@ async fn create_relays_request( }; let relays = { - let mut relays = fallback_relays; + // Only use fallback relays for bootstrapping (no repo context). + // When we have a repo coordinate, rely on repo relays and coordinate + // hint relays instead of always merging in the default set. + let mut relays = if trusted_maintainer_coordinate.is_none() { + fallback_relays + } else { + HashSet::new() + }; if let Some(repo_ref) = &repo_ref { for r in repo_ref.relays.clone() { relays.insert(r); @@ -1588,6 +1595,8 @@ async fn create_relays_request( relays.insert(r.clone()); } } + // When bootstrapping with no repo context and no coordinate hints, + // we need at least the fallback relays to discover the user profile. relays }; @@ -2238,8 +2247,15 @@ pub async fn send_events( animate: bool, silent: bool, ) -> Result<()> { + // Only include default relays as fallback when there are no repo relays + // (bootstrapping case, e.g. new account signup). When repo relays exist, + // trust the repo and user relay configuration. let fallback = [ - client.get_relay_default_set().clone(), + if repo_read_relays.is_empty() && my_write_relays.is_empty() { + client.get_relay_default_set().clone() + } else { + vec![] + }, if events.iter().any(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) { client.get_blaster_relays().clone() } else { diff --git a/src/lib/login/fresh.rs b/src/lib/login/fresh.rs index 886b0e4..8e49085 100644 --- a/src/lib/login/fresh.rs +++ b/src/lib/login/fresh.rs @@ -715,6 +715,7 @@ pub async fn signup_non_interactive( #[cfg(not(test))] client: Option<&Client>, save_local: bool, publish: bool, + relay_urls: Vec, ) -> Result<(Arc, PublicKey, SignerInfo, Keys)> { // Generate new keypair let keys = nostr::Keys::generate(); @@ -783,10 +784,9 @@ pub async fn signup_non_interactive( if let Some(client) = client { let profile = EventBuilder::metadata(&Metadata::new().name(name)).sign_with_keys(&keys)?; let relay_list = EventBuilder::relay_list( - client - .get_relay_default_set() + relay_urls .iter() - .map(|s| (RelayUrl::parse(s).unwrap(), None)), + .filter_map(|s| RelayUrl::parse(s).ok().map(|url| (url, None))), ) .sign_with_keys(&keys)?; @@ -799,7 +799,7 @@ pub async fn signup_non_interactive( client, git_repo_path, vec![profile, relay_list], - client.get_relay_default_set().clone(), + relay_urls, vec![], true, false, @@ -848,12 +848,19 @@ async fn signup( } } - // Call the non-interactive function + // Call the non-interactive function, using relay_default_set as the + // relay list for interactive signup + let relay_urls = if let Some(c) = client { + c.get_relay_default_set().clone() + } else { + vec![] + }; let (signer, public_key, signer_info, _keys) = signup_non_interactive( name.clone(), client, false, // save_local = false (will be saved globally by caller) true, // publish = true (always publish in interactive mode) + relay_urls, ) .await?; diff --git a/src/lib/login/user.rs b/src/lib/login/user.rs index 0b702ef..b273363 100644 --- a/src/lib/login/user.rs +++ b/src/lib/login/user.rs @@ -113,6 +113,8 @@ pub async fn get_user_details( } Ok(user_ref) } else { + // No cached profile found. Fall back to fetching from default relays + // (bootstrapping). let empty = UserRef { public_key: public_key.to_owned(), metadata: extract_user_metadata(public_key, &[])?, -- cgit v1.2.3