From 3c1f6b635713736503f6656319964fa1eaa3356b Mon Sep 17 00:00:00 2001 From: Silberengel Date: Wed, 11 Feb 2026 11:27:59 +0100 Subject: [PATCH] make sure we don't nuke any lists --- src/lib/services/user-actions.ts | 77 ++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/src/lib/services/user-actions.ts b/src/lib/services/user-actions.ts index 8caa979..f6ae0bf 100644 --- a/src/lib/services/user-actions.ts +++ b/src/lib/services/user-actions.ts @@ -239,29 +239,37 @@ async function publishPinList(eventIds: string[]): Promise<{ success: string[]; return { success: [], failed: [] }; // No changes, cancel operation } - // Build final tags: preserve all a-tags, add/update e-tags + // Build final tags: preserve all a-tags, preserve existing e-tags, add new e-tags const tags: string[][] = []; + const seenEventIds = new Set(); // First, add all existing a-tags (they take precedence) for (const aTag of existingATags) { tags.push(aTag); } - // Then, add e-tags for all event IDs in the final list - // Note: We can't easily check if an a-tag represents a specific event ID without resolving it - // So we'll add e-tags for all eventIds, and rely on clients to prefer a-tags when resolving - const seenETags = new Set(); + // Then, preserve existing e-tags for eventIds we're keeping + for (const eventId of deduplicatedEventIds) { + if (existingETags.has(eventId)) { + // Preserve the full existing e-tag (with relay hints, etc.) + const existingETag = existingETags.get(eventId)!; + tags.push(existingETag); + seenEventIds.add(eventId); + } + } + + // Finally, add new simple e-tags for newly added eventIds for (const eventId of deduplicatedEventIds) { - if (!seenETags.has(eventId)) { + if (!seenEventIds.has(eventId)) { tags.push(['e', eventId]); - seenETags.add(eventId); + seenEventIds.add(eventId); } } // Final deduplication: if we somehow have duplicate e-tags, remove them // (This shouldn't happen, but ensures clean output) const finalTags: string[][] = []; - const seenEventIds = new Set(); + const seenFinalEventIds = new Set(); for (const tag of tags) { if (tag[0] === 'a') { @@ -272,9 +280,9 @@ async function publishPinList(eventIds: string[]): Promise<{ success: string[]; // If an a-tag represents this event, we'd ideally skip the e-tag, // but we can't check that without resolving a-tags // So we'll keep the e-tag and let clients handle the preference - if (!seenEventIds.has(tag[1])) { + if (!seenFinalEventIds.has(tag[1])) { finalTags.push(tag); - seenEventIds.add(tag[1]); + seenFinalEventIds.add(tag[1]); } } else { // Keep other tag types as-is @@ -383,29 +391,37 @@ async function publishBookmarkList(eventIds: string[]): Promise<{ success: strin return { success: [], failed: [] }; // No changes, cancel operation } - // Build final tags: preserve all a-tags, add/update e-tags + // Build final tags: preserve all a-tags, preserve existing e-tags, add new e-tags const tags: string[][] = []; + const seenEventIds = new Set(); // First, add all existing a-tags (they take precedence) for (const aTag of existingATags) { tags.push(aTag); } - // Then, add e-tags for all event IDs in the final list - // Note: We can't easily check if an a-tag represents a specific event ID without resolving it - // So we'll add e-tags for all eventIds, and rely on clients to prefer a-tags when resolving - const seenETags = new Set(); + // Then, preserve existing e-tags for eventIds we're keeping + for (const eventId of deduplicatedEventIds) { + if (existingETags.has(eventId)) { + // Preserve the full existing e-tag (with relay hints, etc.) + const existingETag = existingETags.get(eventId)!; + tags.push(existingETag); + seenEventIds.add(eventId); + } + } + + // Finally, add new simple e-tags for newly added eventIds for (const eventId of deduplicatedEventIds) { - if (!seenETags.has(eventId)) { + if (!seenEventIds.has(eventId)) { tags.push(['e', eventId]); - seenETags.add(eventId); + seenEventIds.add(eventId); } } // Final deduplication: if we somehow have duplicate e-tags, remove them // (This shouldn't happen, but ensures clean output) const finalTags: string[][] = []; - const seenEventIds = new Set(); + const seenFinalEventIds = new Set(); for (const tag of tags) { if (tag[0] === 'a') { @@ -416,9 +432,9 @@ async function publishBookmarkList(eventIds: string[]): Promise<{ success: strin // If an a-tag represents this event, we'd ideally skip the e-tag, // but we can't check that without resolving a-tags // So we'll keep the e-tag and let clients handle the preference - if (!seenEventIds.has(tag[1])) { + if (!seenFinalEventIds.has(tag[1])) { finalTags.push(tag); - seenEventIds.add(tag[1]); + seenFinalEventIds.add(tag[1]); } } else { // Keep other tag types as-is @@ -576,13 +592,15 @@ async function publishMuteList(pubkeys: string[]): Promise { // Collect existing p tags const existingPubkeys = new Set(); + const existingPTags: string[][] = []; // Store full p tags to preserve relay hints and petnames if (existingLists.length > 0) { const existingList = existingLists[0]; for (const tag of existingList.tags) { if (tag[0] === 'p' && tag[1]) { existingPubkeys.add(tag[1]); - } + existingPTags.push(tag); + } } } @@ -594,10 +612,23 @@ async function publishMuteList(pubkeys: string[]): Promise { return; // No changes, cancel operation } - // Build final tags: all p tags for muted pubkeys + // Build final tags: preserve existing p tags for pubkeys we're keeping, add new ones const tags: string[][] = []; + const seenPubkeys = new Set(); + + // First, add existing p tags for pubkeys we're keeping + for (const tag of existingPTags) { + if (tag[1] && deduplicatedPubkeys.includes(tag[1])) { + tags.push(tag); + seenPubkeys.add(tag[1]); + } + } + + // Then, add new p tags for pubkeys we're adding (without relay hints or petnames) for (const pubkey of deduplicatedPubkeys) { - tags.push(['p', pubkey]); + if (!seenPubkeys.has(pubkey)) { + tags.push(['p', pubkey]); + } } // Create new mute list event