|
|
|
|
@ -239,29 +239,37 @@ async function publishPinList(eventIds: string[]): Promise<{ success: string[];
@@ -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<string>(); |
|
|
|
|
|
|
|
|
|
// 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<string>(); |
|
|
|
|
// 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<string>(); |
|
|
|
|
const seenFinalEventIds = new Set<string>(); |
|
|
|
|
|
|
|
|
|
for (const tag of tags) { |
|
|
|
|
if (tag[0] === 'a') { |
|
|
|
|
@ -272,9 +280,9 @@ async function publishPinList(eventIds: string[]): Promise<{ success: string[];
@@ -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
@@ -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<string>(); |
|
|
|
|
|
|
|
|
|
// 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<string>(); |
|
|
|
|
// 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<string>(); |
|
|
|
|
const seenFinalEventIds = new Set<string>(); |
|
|
|
|
|
|
|
|
|
for (const tag of tags) { |
|
|
|
|
if (tag[0] === 'a') { |
|
|
|
|
@ -416,9 +432,9 @@ async function publishBookmarkList(eventIds: string[]): Promise<{ success: strin
@@ -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<void> {
@@ -576,13 +592,15 @@ async function publishMuteList(pubkeys: string[]): Promise<void> {
|
|
|
|
|
|
|
|
|
|
// Collect existing p tags
|
|
|
|
|
const existingPubkeys = new Set<string>(); |
|
|
|
|
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<void> {
@@ -594,10 +612,23 @@ async function publishMuteList(pubkeys: string[]): Promise<void> {
|
|
|
|
|
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<string>(); |
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|