Browse Source
- Add display limits store and utilities - Fix reactivity issues with Svelte 5 - Add max 30040/30041 event controls - Implement fetch if not found functionality - Reorganize settings panel with sections - Add debug logging for troubleshootingmaster
11 changed files with 1183 additions and 113 deletions
@ -0,0 +1,19 @@ |
|||||||
|
import { writable } from 'svelte/store'; |
||||||
|
|
||||||
|
export interface DisplayLimits { |
||||||
|
max30040: number; // -1 for unlimited
|
||||||
|
max30041: number; // -1 for unlimited
|
||||||
|
fetchIfNotFound: boolean; |
||||||
|
} |
||||||
|
|
||||||
|
// Create the store with default values
|
||||||
|
export const displayLimits = writable<DisplayLimits>({ |
||||||
|
max30040: -1, // Show all publication indices by default
|
||||||
|
max30041: -1, // Show all content by default
|
||||||
|
fetchIfNotFound: false // Don't fetch missing events by default
|
||||||
|
}); |
||||||
|
|
||||||
|
// Helper to check if limits are active
|
||||||
|
export function hasActiveLimits(limits: DisplayLimits): boolean { |
||||||
|
return limits.max30040 !== -1 || limits.max30041 !== -1; |
||||||
|
} |
||||||
@ -0,0 +1,2 @@ |
|||||||
|
export * from './relayStore'; |
||||||
|
export * from './displayLimits'; |
||||||
@ -0,0 +1,137 @@ |
|||||||
|
import type { NDKEvent } from '@nostr-dev-kit/ndk'; |
||||||
|
import type { DisplayLimits } from '$lib/stores/displayLimits'; |
||||||
|
|
||||||
|
/** |
||||||
|
* Filters events based on display limits |
||||||
|
* @param events - All available events |
||||||
|
* @param limits - Display limit settings |
||||||
|
* @returns Filtered events that should be displayed |
||||||
|
*/ |
||||||
|
export function filterByDisplayLimits(events: NDKEvent[], limits: DisplayLimits): NDKEvent[] { |
||||||
|
if (limits.max30040 === -1 && limits.max30041 === -1) { |
||||||
|
// No limits, return all events
|
||||||
|
return events; |
||||||
|
} |
||||||
|
|
||||||
|
const result: NDKEvent[] = []; |
||||||
|
let count30040 = 0; |
||||||
|
let count30041 = 0; |
||||||
|
|
||||||
|
for (const event of events) { |
||||||
|
if (event.kind === 30040) { |
||||||
|
if (limits.max30040 === -1 || count30040 < limits.max30040) { |
||||||
|
result.push(event); |
||||||
|
count30040++; |
||||||
|
} |
||||||
|
} else if (event.kind === 30041) { |
||||||
|
if (limits.max30041 === -1 || count30041 < limits.max30041) { |
||||||
|
result.push(event); |
||||||
|
count30041++; |
||||||
|
} |
||||||
|
} else { |
||||||
|
// Other event kinds always pass through
|
||||||
|
result.push(event); |
||||||
|
} |
||||||
|
|
||||||
|
// Early exit optimization if both limits are reached
|
||||||
|
if (limits.max30040 !== -1 && count30040 >= limits.max30040 && |
||||||
|
limits.max30041 !== -1 && count30041 >= limits.max30041) { |
||||||
|
// Add remaining non-limited events
|
||||||
|
const remaining = events.slice(events.indexOf(event) + 1); |
||||||
|
for (const e of remaining) { |
||||||
|
if (e.kind !== 30040 && e.kind !== 30041) { |
||||||
|
result.push(e); |
||||||
|
} |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Detects events that are referenced but not present in the current set |
||||||
|
* @param events - Current events |
||||||
|
* @param existingIds - Set of all known event IDs |
||||||
|
* @returns Set of missing event identifiers |
||||||
|
*/ |
||||||
|
export function detectMissingEvents(events: NDKEvent[], existingIds: Set<string>): Set<string> { |
||||||
|
const missing = new Set<string>(); |
||||||
|
|
||||||
|
for (const event of events) { |
||||||
|
// Check 'a' tags for NIP-33 references (kind:pubkey:d-tag)
|
||||||
|
const aTags = event.getMatchingTags('a'); |
||||||
|
for (const aTag of aTags) { |
||||||
|
if (aTag.length < 2) continue; |
||||||
|
|
||||||
|
const identifier = aTag[1]; |
||||||
|
const parts = identifier.split(':'); |
||||||
|
|
||||||
|
if (parts.length >= 3) { |
||||||
|
const [kind, pubkey, dTag] = parts; |
||||||
|
// Create a synthetic ID for checking
|
||||||
|
const syntheticId = `${kind}:${pubkey}:${dTag}`; |
||||||
|
|
||||||
|
// Check if we have an event matching this reference
|
||||||
|
const hasEvent = Array.from(existingIds).some(id => { |
||||||
|
// This is a simplified check - in practice, you'd need to
|
||||||
|
// check the actual event's d-tag value
|
||||||
|
return id === dTag || id === syntheticId; |
||||||
|
}); |
||||||
|
|
||||||
|
if (!hasEvent) { |
||||||
|
missing.add(dTag); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Check 'e' tags for direct event references
|
||||||
|
const eTags = event.getMatchingTags('e'); |
||||||
|
for (const eTag of eTags) { |
||||||
|
if (eTag.length < 2) continue; |
||||||
|
|
||||||
|
const eventId = eTag[1]; |
||||||
|
if (!existingIds.has(eventId)) { |
||||||
|
missing.add(eventId); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return missing; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Groups events by kind for easier counting and display |
||||||
|
*/ |
||||||
|
export function groupEventsByKind(events: NDKEvent[]): Map<number, NDKEvent[]> { |
||||||
|
const groups = new Map<number, NDKEvent[]>(); |
||||||
|
|
||||||
|
for (const event of events) { |
||||||
|
const kind = event.kind; |
||||||
|
if (kind !== undefined) { |
||||||
|
if (!groups.has(kind)) { |
||||||
|
groups.set(kind, []); |
||||||
|
} |
||||||
|
groups.get(kind)!.push(event); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return groups; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Counts events by kind |
||||||
|
*/ |
||||||
|
export function countEventsByKind(events: NDKEvent[]): Map<number, number> { |
||||||
|
const counts = new Map<number, number>(); |
||||||
|
|
||||||
|
for (const event of events) { |
||||||
|
const kind = event.kind; |
||||||
|
if (kind !== undefined) { |
||||||
|
counts.set(kind, (counts.get(kind) || 0) + 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return counts; |
||||||
|
} |
||||||
Loading…
Reference in new issue