fix: improve NIP-17 relay connection tracking and UI

Changes:
- Remove incorrect "NIP-10050" text from inbox relays dropdown header
- Ensure inbox relays are monitored by relay state manager
- Add ensureRelayMonitored() calls in gift-wrap service for better connection tracking
- This ensures active user's inbox relays show correct connection status

Note: The dropdown shows ALL participants' inbox relays, but only the
active user's inbox relays are connected via gift-wrap sync. Other
participants' relays correctly show as "disconnected" since we don't
connect to them.
This commit is contained in:
Claude
2026-01-20 12:34:49 +00:00
parent 3321906849
commit 6399d95f99
4 changed files with 37 additions and 15 deletions

View File

@@ -866,6 +866,15 @@ export function ChatViewer({
<div className="flex items-center justify-between gap-3">
<div className="flex flex-1 min-w-0 items-center gap-2">
{headerPrefix}
{/* Show lock icon for encrypted conversations */}
{protocol === "nip-17" && (
<div
className="text-muted-foreground flex-shrink-0"
title="End-to-end encrypted"
>
<Lock className="size-3" />
</div>
)}
<TooltipProvider>
<Tooltip open={tooltipOpen} onOpenChange={setTooltipOpen}>
<TooltipTrigger asChild>
@@ -1015,15 +1024,6 @@ export function ChatViewer({
) : (
<RelaysDropdown conversation={conversation} />
)}
{/* Show lock icon for encrypted conversations */}
{protocol === "nip-17" && (
<div
className="text-muted-foreground"
title="End-to-end encrypted"
>
<Lock className="size-3" />
</div>
)}
<button
onClick={handleNipClick}
className="rounded bg-muted px-1.5 py-0.5 font-mono hover:bg-muted/80 transition-colors cursor-pointer"

View File

@@ -154,6 +154,18 @@ export function InboxViewer(_props: InboxViewerProps) {
_conversationKey: string,
otherPubkeys: string[],
) => {
// Handle self-conversation (saved messages)
if (otherPubkeys.length === 0) {
addWindow("chat", {
protocol: "nip-17",
identifier: {
type: "dm-recipient",
value: pubkey!, // Use current user's pubkey for self-chat
},
});
return;
}
// Open chat window with the other participant(s) using NIP-17
// For group DMs, join pubkeys with commas
const recipientValue =

View File

@@ -111,7 +111,7 @@ export function InboxRelaysDropdown({
>
<div className="px-3 py-2 border-b border-border">
<div className="text-xs font-semibold text-muted-foreground">
Inbox Relays (NIP-10050)
Inbox Relays
</div>
</div>
<div className="p-2 space-y-3">

View File

@@ -11,6 +11,7 @@ import db from "./db";
import pool from "./relay-pool";
import eventStore from "./event-store";
import accountManager from "./accounts";
import relayStateManager from "./relay-state-manager";
/**
* Statistics about gift wrap processing
@@ -29,7 +30,7 @@ export interface GiftWrapStats {
*/
const GIFT_WRAP_CONFIG = {
INITIAL_LIMIT: 500, // Max gift wraps to fetch on initial sync
PAGINATION_SIZE: 200, // Batch size for loading older gift wraps
PAGINATION_SIZE: 500, // Batch size for loading older gift wraps
MAX_STORAGE_DAYS: 90, // Keep gift wraps for 90 days
AUTH_TIMEOUT_MS: 10000, // Wait 10s for auth before proceeding
};
@@ -121,6 +122,11 @@ class GiftWrapManager {
dmRelays,
);
// Ensure relay state manager is monitoring these relays
dmRelays.forEach((relay) => {
relayStateManager.ensureRelayMonitored(relay);
});
// Step 1: Authenticate with relays using dummy REQ
// This triggers NIP-42 AUTH which is required for relays to serve kind 1059
await this.authenticateWithRelays(dmRelays, pubkey);
@@ -387,6 +393,11 @@ class GiftWrapManager {
return 0;
}
// Ensure relay state manager is monitoring these relays
dmRelays.forEach((relay) => {
relayStateManager.ensureRelayMonitored(relay);
});
// Fetch older gift wraps
const filter: Filter = {
kinds: [1059],
@@ -819,10 +830,9 @@ class GiftWrapManager {
throw new Error(`Failed to parse rumor JSON: ${error}`);
}
// Verify it's a kind 14 (message) or kind 15 (file)
if (rumor.kind !== 14 && rumor.kind !== 15) {
throw new Error(`Expected kind 14 or 15 rumor, got kind ${rumor.kind}`);
}
// Accept any kind of private event sent via gift wrap
// This includes kind 14 (DMs), kind 15 (files), kind 7 (reactions),
// kind 25050 (private DM relays), and any other private events
// Verify the rumor's pubkey matches the seal's pubkey (prevent spoofing)
if (rumor.pubkey !== seal.pubkey) {