From 6f5f6df71c619e8c29d8f98264a6e1dfca71c33c Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Tue, 2 Jun 2026 13:37:12 +1000 Subject: [PATCH] fix(serverless): build ChannelInfo locally on create/open_dm (fixes 'nothing happened') MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The serverless create_channel and open_dm re-queried the relay for the kind:39000 they had just published, to build ChannelInfo. On a public relay that immediate round-trip races against propagation/indexing lag and can return empty, throwing 'metadata not yet available' — surfacing as a private channel / DM that silently fails to appear in the UI. Both now derive ChannelInfo directly from the locally-signed metadata event (we created it, so is_member = true), with no relay round-trip and no race. --- desktop/src-tauri/src/commands/channels.rs | 15 ++++++++++++--- desktop/src-tauri/src/commands/dms.rs | 14 ++++++++++---- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/desktop/src-tauri/src/commands/channels.rs b/desktop/src-tauri/src/commands/channels.rs index 6bd85e76cb..d3bed68ee6 100644 --- a/desktop/src-tauri/src/commands/channels.rs +++ b/desktop/src-tauri/src/commands/channels.rs @@ -363,10 +363,12 @@ pub async fn create_channel( if state.is_serverless() { // No relay to process a kind:9007 command — publish the kind:39000 // metadata and a kind:39002 membership (self) directly so the channel - // is discoverable via get_channels. - let my_pubkey = { + // is discoverable via get_channels. Build ChannelInfo from the locally + // signed metadata event rather than re-querying the relay, which can + // race against propagation/indexing lag (the "nothing happened" bug). + let (my_pubkey, keys) = { let keys = state.keys.lock().map_err(|e| e.to_string())?; - keys.public_key().to_hex() + (keys.public_key().to_hex(), keys.clone()) }; let meta = events::build_channel_metadata_serverless( &channel_uuid_string, @@ -376,9 +378,16 @@ pub async fn create_channel( description.as_deref(), &[], )?; + let meta_event = meta + .clone() + .sign_with_keys(&keys) + .map_err(|e| format!("failed to sign channel metadata: {e}"))?; submit_event(meta, &state).await?; let members = events::build_channel_members_serverless(&channel_uuid_string, &[my_pubkey])?; submit_event(members, &state).await?; + // Return ChannelInfo derived from the event we just published (member, + // since we created it). No relay round-trip required. + return nostr_convert::channel_info_from_event(&meta_event, None, Some(true)); } else { let builder = events::build_create_channel( channel_uuid, diff --git a/desktop/src-tauri/src/commands/dms.rs b/desktop/src-tauri/src/commands/dms.rs index b46bdaea23..91ad6368a4 100644 --- a/desktop/src-tauri/src/commands/dms.rs +++ b/desktop/src-tauri/src/commands/dms.rs @@ -36,10 +36,12 @@ pub async fn open_dm( let channel_id = if state.is_serverless() { // No relay to assign a channel id. Derive a deterministic id from the // sorted participant set (including self) so both sides converge on the - // same DM channel, then publish 39000 + 39002 directly. - let my_pubkey = { + // same DM channel, then publish 39000 + 39002 directly. Return + // ChannelInfo from the locally signed event rather than re-querying the + // relay (which races against propagation lag). + let (my_pubkey, keys) = { let keys = state.keys.lock().map_err(|e| e.to_string())?; - keys.public_key().to_hex() + (keys.public_key().to_hex(), keys.clone()) }; let mut participants: Vec = pubkeys .iter() @@ -59,11 +61,15 @@ pub async fn open_dm( None, &participants, )?; + let meta_event = meta + .clone() + .sign_with_keys(&keys) + .map_err(|e| format!("failed to sign DM metadata: {e}"))?; submit_event(meta, &state).await?; let members = events::build_channel_members_serverless(&channel_id, &participants)?; submit_event(members, &state).await?; - channel_id + return nostr_convert::channel_info_from_event(&meta_event, None, Some(true)); } else { // Submit a kind:41010 dm-open event; the relay replies with the channel // id in its OK message payload.