From 6021e82f7856c9c141bd6e1f301258ed730eddc4 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 12 Feb 2026 21:33:30 +0000 Subject: [PATCH] feat(relay): add wss://relay.zapstore.dev for zapstore app kinds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Include the Zapstore relay when loading kind 32267 (app metadata) events, since they're primarily hosted on relay.zapstore.dev for now. Changes: - Wrap addressLoader in loaders.ts to inject zapstore relay for kind 32267 pointers — covers all code paths (zaps, generic viewers, any a-tag referencing an app) - Add zapstore relay to ZapstoreAppRenderer/DetailRenderer relay lists (for fetching releases related to an app) - Add zapstore relay to ZapstoreAppSetRenderer/DetailRenderer when resolving app references from app collections (kind 30267) https://claude.ai/code/session_016CY1NFzK3AzhvB4e9Vc4Qq --- .../nostr/kinds/ZapstoreAppDetailRenderer.tsx | 10 ++++++--- .../nostr/kinds/ZapstoreAppRenderer.tsx | 10 ++++++--- .../kinds/ZapstoreAppSetDetailRenderer.tsx | 20 ++++++++++++++++-- .../nostr/kinds/ZapstoreAppSetRenderer.tsx | 20 ++++++++++++++++-- src/services/loaders.ts | 21 +++++++++++++++++-- 5 files changed, 69 insertions(+), 12 deletions(-) diff --git a/src/components/nostr/kinds/ZapstoreAppDetailRenderer.tsx b/src/components/nostr/kinds/ZapstoreAppDetailRenderer.tsx index 5b66c5d..8eb607d 100644 --- a/src/components/nostr/kinds/ZapstoreAppDetailRenderer.tsx +++ b/src/components/nostr/kinds/ZapstoreAppDetailRenderer.tsx @@ -169,12 +169,16 @@ export function ZapstoreAppDetailRenderer({ const identifier = getAppIdentifier(event); // Build relay list for fetching releases: - // 1. Seen relays (where we received this app event) - // 2. Publisher's outbox relays (NIP-65) - // 3. Aggregator relays (fallback) + // 1. Zapstore relay (primary source for app events) + // 2. Seen relays (where we received this app event) + // 3. Publisher's outbox relays (NIP-65) + // 4. Aggregator relays (fallback) const relays = useMemo(() => { const relaySet = new Set(); + // Add zapstore relay (primary source for app metadata) + relaySet.add("wss://relay.zapstore.dev/"); + // Add seen relays from the app event const seenRelays = getSeenRelays(event); if (seenRelays) { diff --git a/src/components/nostr/kinds/ZapstoreAppRenderer.tsx b/src/components/nostr/kinds/ZapstoreAppRenderer.tsx index dcfccf3..3b15583 100644 --- a/src/components/nostr/kinds/ZapstoreAppRenderer.tsx +++ b/src/components/nostr/kinds/ZapstoreAppRenderer.tsx @@ -32,12 +32,16 @@ export function ZapstoreAppRenderer({ event }: BaseEventProps) { const platforms = detectPlatforms(event); // Build relay list for fetching releases: - // 1. Seen relays (where we received this app event) - // 2. Publisher's outbox relays (NIP-65) - // 3. Aggregator relays (fallback) + // 1. Zapstore relay (primary source for app events) + // 2. Seen relays (where we received this app event) + // 3. Publisher's outbox relays (NIP-65) + // 4. Aggregator relays (fallback) const relays = useMemo(() => { const relaySet = new Set(); + // Add zapstore relay (primary source for app metadata) + relaySet.add("wss://relay.zapstore.dev/"); + // Add seen relays from the app event const seenRelays = getSeenRelays(event); if (seenRelays) { diff --git a/src/components/nostr/kinds/ZapstoreAppSetDetailRenderer.tsx b/src/components/nostr/kinds/ZapstoreAppSetDetailRenderer.tsx index 7d4e6e5..ddc47bd 100644 --- a/src/components/nostr/kinds/ZapstoreAppSetDetailRenderer.tsx +++ b/src/components/nostr/kinds/ZapstoreAppSetDetailRenderer.tsx @@ -10,8 +10,11 @@ import { } from "@/lib/zapstore-helpers"; import { useNostrEvent } from "@/hooks/useNostrEvent"; import { useGrimoire } from "@/core/state"; +import { useMemo } from "react"; import { UserName } from "../UserName"; import { Package } from "lucide-react"; + +const ZAPSTORE_RELAY = "wss://relay.zapstore.dev/"; import { PlatformIcon } from "./zapstore/PlatformIcon"; interface ZapstoreAppSetDetailRendererProps { @@ -23,11 +26,20 @@ interface ZapstoreAppSetDetailRendererProps { */ function AppCard({ address, + relayHint, }: { address: { kind: number; pubkey: string; identifier: string }; + relayHint?: string; }) { const { addWindow } = useGrimoire(); - const appEvent = useNostrEvent(address); + const pointer = useMemo( + () => ({ + ...address, + relays: [ZAPSTORE_RELAY, ...(relayHint ? [relayHint] : [])], + }), + [address, relayHint], + ); + const appEvent = useNostrEvent(pointer); if (!appEvent) { return ( @@ -139,7 +151,11 @@ export function ZapstoreAppSetDetailRenderer({ ) : (
{apps.map((ref, idx) => ( - + ))}
)} diff --git a/src/components/nostr/kinds/ZapstoreAppSetRenderer.tsx b/src/components/nostr/kinds/ZapstoreAppSetRenderer.tsx index c911a7b..ce69689 100644 --- a/src/components/nostr/kinds/ZapstoreAppSetRenderer.tsx +++ b/src/components/nostr/kinds/ZapstoreAppSetRenderer.tsx @@ -10,15 +10,27 @@ import { } from "@/lib/zapstore-helpers"; import { useNostrEvent } from "@/hooks/useNostrEvent"; import { useGrimoire } from "@/core/state"; +import { useMemo } from "react"; import { Package } from "lucide-react"; +const ZAPSTORE_RELAY = "wss://relay.zapstore.dev/"; + function AppItem({ address, + relayHint, }: { address: { kind: number; pubkey: string; identifier: string }; + relayHint?: string; }) { const { addWindow } = useGrimoire(); - const appEvent = useNostrEvent(address); + const pointer = useMemo( + () => ({ + ...address, + relays: [ZAPSTORE_RELAY, ...(relayHint ? [relayHint] : [])], + }), + [address, relayHint], + ); + const appEvent = useNostrEvent(pointer); const appName = appEvent ? getAppName(appEvent) : address?.identifier || "Unknown App"; @@ -65,7 +77,11 @@ export function ZapstoreAppSetRenderer({ event }: BaseEventProps) { {apps.length > 0 && (
{apps.map((ref, idx) => ( - + ))}
)} diff --git a/src/services/loaders.ts b/src/services/loaders.ts index d3cd7f4..31bfe1c 100644 --- a/src/services/loaders.ts +++ b/src/services/loaders.ts @@ -4,7 +4,7 @@ import { createTimelineLoader, createEventLoaderForStore, } from "applesauce-loaders/loaders"; -import type { EventPointer } from "nostr-tools/nip19"; +import type { EventPointer, AddressPointer } from "nostr-tools/nip19"; import { Observable } from "rxjs"; import { getSeenRelays, @@ -198,12 +198,29 @@ export function eventLoader( return baseEventLoader(enhancedPointer); } +// Kind-specific relay overrides for addressable events +// TODO: Remove once these events are widely replicated +const KIND_ADDRESS_RELAYS: Record = { + 32267: ["wss://relay.zapstore.dev/"], // Zapstore app metadata +}; + // Address loader for replaceable events (profiles, relay lists, etc.) -export const addressLoader = createAddressLoader(pool, { +const baseAddressLoader = createAddressLoader(pool, { eventStore, extraRelays: AGGREGATOR_RELAYS, }); +export function addressLoader(pointer: AddressPointer): Observable { + const kindRelays = KIND_ADDRESS_RELAYS[pointer.kind]; + if (kindRelays) { + return baseAddressLoader({ + ...pointer, + relays: [...kindRelays, ...(pointer.relays || [])], + }); + } + return baseAddressLoader(pointer); +} + // Profile loader with batching - combines multiple profile requests within 200ms export const profileLoader = createAddressLoader(pool, { eventStore,