diff --git a/src/components/Embedded/EmbeddedNote.tsx b/src/components/Embedded/EmbeddedNote.tsx
index fe94ed3a..79d14ead 100644
--- a/src/components/Embedded/EmbeddedNote.tsx
+++ b/src/components/Embedded/EmbeddedNote.tsx
@@ -2,7 +2,7 @@ import { Skeleton } from '@/components/ui/skeleton'
import ExternalLink from '@/components/ExternalLink'
import { FAST_READ_RELAY_URLS, SEARCHABLE_RELAY_URLS, ExtendedKind } from '@/constants'
import { getFavoritesFeedRelayUrls } from '@/lib/favorites-feed-relays'
-import { LIVE_ACTIVITY_KINDS, liveActivityKindsEnabledInPicker } from '@/lib/live-activities'
+import { LIVE_ACTIVITY_KINDS } from '@/lib/live-activities'
import { isRenderableNoteKind } from '@/lib/note-renderable-kinds'
import { useFetchEvent } from '@/hooks'
import { normalizeUrl } from '@/lib/url'
@@ -10,7 +10,6 @@ import { cn } from '@/lib/utils'
import client from '@/services/client.service'
import indexedDb from '@/services/indexed-db.service'
import { useFavoriteRelays } from '@/providers/favorite-relays-context'
-import { useKindFilterOrDefaults } from '@/providers/KindFilterProvider'
import { useTranslation } from 'react-i18next'
import { useEffect, useMemo, useState } from 'react'
import { Event, nip19 } from 'nostr-tools'
@@ -327,24 +326,8 @@ function EmbeddedNoteContent({
containingEvent?: Event
showFull?: boolean
}) {
- const { showKinds, feedKindFilterBypass } = useKindFilterOrDefaults()
- const allowLiveEmbeds = liveActivityKindsEnabledInPicker(showKinds, feedKindFilterBypass)
-
- const naddrTargetsLiveActivityOnly = useMemo(() => {
- try {
- const dec = nip19.decode(noteId.trim())
- if (dec.type !== 'naddr') return false
- return LIVE_ACTIVITY_KINDS.includes(dec.data.kind as (typeof LIVE_ACTIVITY_KINDS)[number])
- } catch {
- return false
- }
- }, [noteId])
-
- const skipLiveActivityFetch = naddrTargetsLiveActivityOnly && !allowLiveEmbeds
-
- if (skipLiveActivityFetch) {
- return
- }
+ /** Embeds are contextual to the parent note; home kind picker must not hide NIP-53 live cards here. */
+ const allowLiveEmbeds = true
return (
(
diff --git a/src/components/NoteList/index.tsx b/src/components/NoteList/index.tsx
index 8af05127..b3ad7335 100644
--- a/src/components/NoteList/index.tsx
+++ b/src/components/NoteList/index.tsx
@@ -118,6 +118,25 @@ const LOAD_MORE_IO_ROOT_MARGIN_BOTTOM_PX = 3200
* start load-more (uses viewport height of that container, with a floor).
*/
const LOAD_MORE_SCROLL_PREFETCH_VIEWPORT_MULT = 2.35
+
+/** Same rules as visible-row filtering when the home kind picker applies (not {@link shouldHideEvent}). */
+function eventPassesNoteListKindPicker(
+ event: Event,
+ effectiveShowKinds: readonly number[],
+ showKind1OPs: boolean,
+ showKind1Replies: boolean,
+ showKind1111: boolean
+): boolean {
+ if (!effectiveShowKinds.includes(event.kind)) return false
+ if (event.kind === kinds.ShortTextNote) {
+ const isReply = isReplyNoteEvent(event)
+ if (isReply && !showKind1Replies) return false
+ if (!isReply && !showKind1OPs) return false
+ }
+ if (event.kind === ExtendedKind.COMMENT && !showKind1111) return false
+ if (event.kind === ExtendedKind.GIT_RELEASE && !showKind1OPs) return false
+ return true
+}
const LOAD_MORE_SCROLL_PREFETCH_MIN_PX = 960
/** Min ms between scroll-driven load-more attempts (loadMore also throttles internally). */
const LOAD_MORE_SCROLL_PREFETCH_COOLDOWN_MS = 180
@@ -937,6 +956,12 @@ const NoteList = forwardRef(
showKindsRef.current = showKinds
const effectiveShowKindsRef = useRef(effectiveShowKinds)
effectiveShowKindsRef.current = effectiveShowKinds
+ const showKind1OPsRef = useRef(showKind1OPs)
+ showKind1OPsRef.current = showKind1OPs
+ const showKind1RepliesRef = useRef(showKind1Replies)
+ showKind1RepliesRef.current = showKind1Replies
+ const showKind1111Ref = useRef(showKind1111)
+ showKind1111Ref.current = showKind1111
const progressiveDocumentKindsRef = useRef(progressiveDocumentKinds)
progressiveDocumentKindsRef.current = progressiveDocumentKinds
const progressiveWarmupQueryRef = useRef(progressiveWarmupQuery)
@@ -960,11 +985,13 @@ const NoteList = forwardRef(
/**
* When to apply kind picker + kind-1 OP|reply / 1111 / GitRelease splits to visible rows.
- * Home feeds default to {@link withKindFilter}; relay explorer and KindFilter "All Events" use {@link showAllKinds}.
+ * Home feeds default to {@link withKindFilter}. Relay explorer sets {@link showAllKinds} explicitly (kindless
+ * firehose). {@link seeAllFeedEvents} widens REQ when applicable; merged batches and live rows still respect the
+ * picker unless {@link showAllKinds} is true with kindless explore.
*/
const applyKindPickerInUi = useMemo(
- () => withKindFilter && !showAllKinds && !seeAllFeedEvents,
- [withKindFilter, showAllKinds, seeAllFeedEvents]
+ () => withKindFilter && !showAllKinds,
+ [withKindFilter, showAllKinds]
)
const shouldHideEvent = useCallback(
@@ -1037,14 +1064,9 @@ const NoteList = forwardRef(
for (; i < maxScan && i < timelineEventsForFilter.length && out.length < target; i++) {
const evt = timelineEventsForFilter[i]!
if (applyKindPickerInUi) {
- if (!effectiveShowKinds.includes(evt.kind)) continue
- if (evt.kind === kinds.ShortTextNote) {
- const isReply = isReplyNoteEvent(evt)
- if (isReply && !showKind1Replies) continue
- if (!isReply && !showKind1OPs) continue
+ if (!eventPassesNoteListKindPicker(evt, effectiveShowKinds, showKind1OPs, showKind1Replies, showKind1111)) {
+ continue
}
- if (evt.kind === ExtendedKind.COMMENT && !showKind1111) continue
- if (evt.kind === ExtendedKind.GIT_RELEASE && !showKind1OPs) continue
}
if (shouldHideEvent(evt)) continue
@@ -1118,14 +1140,17 @@ const NoteList = forwardRef(
return newEvents.filter((event: Event) => {
if (applyKindPickerInUi) {
- if (!effectiveShowKinds.includes(event.kind)) return false
- if (event.kind === kinds.ShortTextNote) {
- const isReply = isReplyNoteEvent(event)
- if (isReply && !showKind1Replies) return false
- if (!isReply && !showKind1OPs) return false
+ if (
+ !eventPassesNoteListKindPicker(
+ event,
+ effectiveShowKinds,
+ showKind1OPs,
+ showKind1Replies,
+ showKind1111
+ )
+ ) {
+ return false
}
- if (event.kind === ExtendedKind.COMMENT && !showKind1111) return false
- if (event.kind === ExtendedKind.GIT_RELEASE && !showKind1OPs) return false
}
if (shouldHideEvent(event)) return false
@@ -1676,15 +1701,25 @@ const NoteList = forwardRef(
}
/**
- * Kindless relay REQ: when {@link showAllKinds} is true (explorer / "All Events"), keep the full batch;
- * otherwise narrow to effectiveShowKinds so the merged timeline matches {@link applyKindPickerInUi}.
+ * Relay kindless firehose: keep the full batch. Else when the kind picker applies, narrow like
+ * {@link applyKindPickerInUi}. Remaining spell paths use kinds-only narrowing when client-side kind filter runs.
*/
const narrowLiveBatch = (evs: Event[]) => {
- if (seeAllFeedEventsRef.current) return evs
if (allowKindlessRelayExploreRef.current && showAllKindsRef.current) return evs
+ if (withKindFilterRef.current && !showAllKindsRef.current) {
+ return evs.filter((e) =>
+ eventPassesNoteListKindPicker(
+ e,
+ effectiveShowKindsRef.current,
+ showKind1OPsRef.current,
+ showKind1RepliesRef.current,
+ showKind1111Ref.current
+ )
+ )
+ }
if (!useFilterAsIsRef.current || !clientSideKindFilterRef.current) return evs
if (!withKindFilterRef.current) return evs
- return evs.filter((e) => effectiveShowKinds.includes(e.kind))
+ return evs.filter((e) => effectiveShowKindsRef.current.includes(e.kind))
}
if (oneShotFetch) {
@@ -1746,7 +1781,6 @@ const NoteList = forwardRef(
useFilterAsIs &&
clientSideKindFilter &&
withKindFilter &&
- !seeAllFeedEventsRef.current &&
(!allowKindlessRelayExplore || !showAllKinds)
) {
relayOnly = relayOnly.filter((e) => effectiveShowKinds.includes(e.kind))
@@ -2084,25 +2118,39 @@ const NoteList = forwardRef(
onNew: (event: Event) => {
if (!effectActive) return
feedRelayReturnedAnyEventRef.current = true
- if (!seeAllFeedEventsRef.current && withKindFilterRef.current) {
+ if (withKindFilterRef.current) {
const kindlessFirehose =
allowKindlessRelayExploreRef.current && showAllKindsRef.current
- if (!kindlessFirehose) {
- if (!useFilterAsIsRef.current && !effectiveShowKindsRef.current.includes(event.kind))
- return
- if (
- clientSideKindFilterRef.current &&
- useFilterAsIsRef.current &&
- !effectiveShowKindsRef.current.includes(event.kind)
- )
- return
- if (event.kind === kinds.ShortTextNote) {
- const isReply = isReplyNoteEvent(event)
- if (isReply && !showKind1Replies) return
- if (!isReply && !showKind1OPs) return
+ if (!kindlessFirehose) {
+ if (!showAllKindsRef.current) {
+ if (
+ !eventPassesNoteListKindPicker(
+ event,
+ effectiveShowKindsRef.current,
+ showKind1OPsRef.current,
+ showKind1RepliesRef.current,
+ showKind1111Ref.current
+ )
+ ) {
+ return
+ }
+ } else {
+ if (!useFilterAsIsRef.current && !effectiveShowKindsRef.current.includes(event.kind))
+ return
+ if (
+ clientSideKindFilterRef.current &&
+ useFilterAsIsRef.current &&
+ !effectiveShowKindsRef.current.includes(event.kind)
+ )
+ return
+ if (event.kind === kinds.ShortTextNote) {
+ const isReply = isReplyNoteEvent(event)
+ if (isReply && !showKind1RepliesRef.current) return
+ if (!isReply && !showKind1OPsRef.current) return
+ }
+ if (event.kind === ExtendedKind.COMMENT && !showKind1111Ref.current) return
+ if (event.kind === ExtendedKind.GIT_RELEASE && !showKind1OPsRef.current) return
}
- if (event.kind === ExtendedKind.COMMENT && !showKind1111) return
- if (event.kind === ExtendedKind.GIT_RELEASE && !showKind1OPs) return
}
}
if (shouldHideEventRef.current(event)) return
@@ -2261,8 +2309,18 @@ const NoteList = forwardRef(
: LIMIT
const narrowDeltaBatch = (evs: Event[]) => {
- if (seeAllFeedEventsRef.current) return evs
if (allowKindlessRelayExploreRef.current && showAllKindsRef.current) return evs
+ if (withKindFilterRef.current && !showAllKindsRef.current) {
+ return evs.filter((e) =>
+ eventPassesNoteListKindPicker(
+ e,
+ effectiveShowKindsRef.current,
+ showKind1OPsRef.current,
+ showKind1RepliesRef.current,
+ showKind1111Ref.current
+ )
+ )
+ }
if (!useFilterAsIsRef.current || !clientSideKindFilterRef.current) return evs
if (!withKindFilterRef.current) return evs
return evs.filter((e) => effectiveShowKindsRef.current.includes(e.kind))
@@ -2336,25 +2394,39 @@ const NoteList = forwardRef(
onNew: (event: Event) => {
if (!deltaActive) return
feedRelayReturnedAnyEventRef.current = true
- if (!seeAllFeedEventsRef.current && withKindFilterRef.current) {
+ if (withKindFilterRef.current) {
const kindlessFirehose =
allowKindlessRelayExploreRef.current && showAllKindsRef.current
if (!kindlessFirehose) {
- if (!useFilterAsIsRef.current && !effectiveShowKindsRef.current.includes(event.kind))
- return
- if (
- clientSideKindFilterRef.current &&
- useFilterAsIsRef.current &&
- !effectiveShowKindsRef.current.includes(event.kind)
- )
- return
- if (event.kind === kinds.ShortTextNote) {
- const isReply = isReplyNoteEvent(event)
- if (isReply && !showKind1Replies) return
- if (!isReply && !showKind1OPs) return
+ if (!showAllKindsRef.current) {
+ if (
+ !eventPassesNoteListKindPicker(
+ event,
+ effectiveShowKindsRef.current,
+ showKind1OPsRef.current,
+ showKind1RepliesRef.current,
+ showKind1111Ref.current
+ )
+ ) {
+ return
+ }
+ } else {
+ if (!useFilterAsIsRef.current && !effectiveShowKindsRef.current.includes(event.kind))
+ return
+ if (
+ clientSideKindFilterRef.current &&
+ useFilterAsIsRef.current &&
+ !effectiveShowKindsRef.current.includes(event.kind)
+ )
+ return
+ if (event.kind === kinds.ShortTextNote) {
+ const isReply = isReplyNoteEvent(event)
+ if (isReply && !showKind1RepliesRef.current) return
+ if (!isReply && !showKind1OPsRef.current) return
+ }
+ if (event.kind === ExtendedKind.COMMENT && !showKind1111Ref.current) return
+ if (event.kind === ExtendedKind.GIT_RELEASE && !showKind1OPsRef.current) return
}
- if (event.kind === ExtendedKind.COMMENT && !showKind1111) return
- if (event.kind === ExtendedKind.GIT_RELEASE && !showKind1OPs) return
}
}
if (shouldHideEventRef.current(event)) return
@@ -2694,12 +2766,21 @@ const NoteList = forwardRef(
useFilterAsIsRef.current &&
clientSideKindFilterRef.current &&
withKindFilterRef.current &&
- !seeAllFeedEventsRef.current &&
(!allowKindlessRelayExploreRef.current || !showAllKindsRef.current)
const existingIds = new Set(latestEvents.map((e) => e.id))
- const kindPasses = (e: Event) =>
- !narrowLoadMore || effectiveShowKindsRef.current.includes(e.kind)
+ const kindPasses = (e: Event) => {
+ if (withKindFilterRef.current && !showAllKindsRef.current) {
+ return eventPassesNoteListKindPicker(
+ e,
+ effectiveShowKindsRef.current,
+ showKind1OPsRef.current,
+ showKind1RepliesRef.current,
+ showKind1111Ref.current
+ )
+ }
+ return !narrowLoadMore || effectiveShowKindsRef.current.includes(e.kind)
+ }
const noveltyFromBatch = (batch: Event[]) => {
const out: Event[] = []
diff --git a/src/components/ZapStreamLiveEventEmbed/index.tsx b/src/components/ZapStreamLiveEventEmbed/index.tsx
index 133c1c4b..ced00ba6 100644
--- a/src/components/ZapStreamLiveEventEmbed/index.tsx
+++ b/src/components/ZapStreamLiveEventEmbed/index.tsx
@@ -1,9 +1,7 @@
import { EmbeddedNote } from '@/components/Embedded/EmbeddedNote'
import ExternalLink from '@/components/ExternalLink'
-import { liveActivityKindsEnabledInPicker } from '@/lib/live-activities'
import { naddrFromZapStreamWatchUrl } from '@/lib/zap-stream-url'
import { cn } from '@/lib/utils'
-import { useKindFilterOrDefaults } from '@/providers/KindFilterProvider'
import type { Event } from 'nostr-tools'
/** zap.stream `/naddr1…` → fetch kind 30311 and render as embedded note (LiveEvent), not a full-site iframe. */
@@ -18,10 +16,6 @@ export default function ZapStreamLiveEventEmbed({
containingEvent?: Event
showFull?: boolean
}) {
- const { showKinds, feedKindFilterBypass } = useKindFilterOrDefaults()
- if (!liveActivityKindsEnabledInPicker(showKinds, feedKindFilterBypass)) {
- return
- }
const naddr = naddrFromZapStreamWatchUrl(url)
if (!naddr) {
return
diff --git a/src/lib/live-activities.ts b/src/lib/live-activities.ts
index 1cbd0abf..fb7e5984 100644
--- a/src/lib/live-activities.ts
+++ b/src/lib/live-activities.ts
@@ -36,7 +36,10 @@ export type LiveActivitiesFetchEventsFn = (
/** NIP-53 live streaming (30311), meeting space (30312), meeting (30313). */
export const LIVE_ACTIVITY_KINDS = [30311, 30312, 30313] as const
-/** True when the home kind picker (or “see all events”) allows NIP-53 live activity rows and inline embeds. */
+/**
+ * @deprecated Home embeds no longer consult the kind picker. Kept for callers that still want
+ * “is live activity in the user’s selected kinds?” (e.g. optional UI); prefer inlining that check.
+ */
export function liveActivityKindsEnabledInPicker(
showKinds: readonly number[],
feedKindFilterBypass: boolean
diff --git a/src/providers/KindFilterProvider.tsx b/src/providers/KindFilterProvider.tsx
index eb8bde50..fc728c30 100644
--- a/src/providers/KindFilterProvider.tsx
+++ b/src/providers/KindFilterProvider.tsx
@@ -26,7 +26,7 @@ type TKindFilterContext = {
showKind1OPs: boolean
showKind1Replies: boolean
showKind1111: boolean
- /** When true, main feed omits REQ `kinds` and skips client-side kind filtering (testing). */
+ /** When true, main feed uses wider REQ / merge paths ("see all events"); visible rows still follow the kind picker. */
feedKindFilterBypass: boolean
updateShowKinds: (
kinds: number[],