diff --git a/neode-ui/src/stores/mesh.ts b/neode-ui/src/stores/mesh.ts index 5ae38b5c..634904c0 100644 --- a/neode-ui/src/stores/mesh.ts +++ b/neode-ui/src/stores/mesh.ts @@ -42,6 +42,11 @@ export type MeshMessageTypeLabel = | 'psbt_hash' | 'coordinate' | 'block_header' + | 'tx_relay' + | 'tx_relay_response' + | 'tx_confirmation' + | 'lightning_relay' + | 'lightning_relay_response' export interface MeshMessage { id: number diff --git a/neode-ui/src/views/Mesh.vue b/neode-ui/src/views/Mesh.vue index bf50dd3a..9d59fe18 100644 --- a/neode-ui/src/views/Mesh.vue +++ b/neode-ui/src/views/Mesh.vue @@ -97,11 +97,20 @@ async function sendArchMessage() { sendingArch.value = true try { const nodes = await rpcClient.federationListNodes() + // Get our own onion address to skip sending to self + let selfOnion: string | null = null + try { + const tor = await rpcClient.getTorAddress() + selfOnion = tor.tor_address + } catch { /* non-fatal */ } const msg = messageText.value.trim() let sent = 0 for (const node of nodes.nodes) { + const nodeOnion = node.onion || node.did + // Skip sending to ourselves (would create duplicate received message) + if (selfOnion && (nodeOnion === selfOnion || nodeOnion === selfOnion.replace('.onion', '') || selfOnion === nodeOnion + '.onion')) continue try { - await rpcClient.sendMessageToPeer(node.onion || node.did, msg) + await rpcClient.sendMessageToPeer(nodeOnion, msg) sent++ } catch { /* some peers may be offline */ } } @@ -109,7 +118,7 @@ async function sendArchMessage() { await rpcClient.call({ method: 'node-store-sent', params: { message: msg } }) } catch { /* non-fatal */ } messageText.value = '' - if (sent === 0) sendError.value = 'No peers reachable — message may arrive when they come online' + if (sent === 0 && nodes.nodes.length <= 1) sendError.value = 'No other peers in federation — add nodes first' await loadArchMessages() } catch (e) { sendError.value = e instanceof Error ? e.message : 'Send failed' @@ -217,7 +226,7 @@ const chatMessages = computed(() => { } else if (m.from_name) { peerName = m.from_name } else if (fedNodeNames.value[m.from_pubkey]) { - peerName = fedNodeNames.value[m.from_pubkey] + peerName = fedNodeNames.value[m.from_pubkey]! } else { peerName = m.from_pubkey.slice(0, 12) + '...' } @@ -642,6 +651,46 @@ function truncatePubkey(hex: string | null): string { {{ msg.typed_payload.message || msg.plaintext }} + +
+ + TX relay #{{ msg.typed_payload.request_id }} ({{ (msg.typed_payload.tx_hex || '').length }} hex chars) +
+ +
+ {{ msg.typed_payload.txid ? '✅' : '❌' }} + + + + +
+ +
+ + {{ msg.typed_payload.confirmations }} conf @ block {{ msg.typed_payload.block_height }} — {{ String(msg.typed_payload.txid || '').substring(0, 12) }}… +
+ +
+
+ + Lightning Relay Request +
+
{{ (msg.typed_payload.amount_sats || 0).toLocaleString() }} sats
+
{{ (msg.typed_payload.bolt11 || '').substring(0, 40) }}…
+
+ +
+
+ {{ msg.typed_payload.preimage ? '✅' : '❌' }} + + + + +
+
hash: {{ String(msg.typed_payload.payment_hash).substring(0, 20) }}…
+
preimage: {{ String(msg.typed_payload.preimage).substring(0, 20) }}…
+
{{ msg.typed_payload.error }}
+
{{ msg.plaintext }}