From 3013f43a5eac145524f99e7db6d7fecfff3fe091 Mon Sep 17 00:00:00 2001 From: mdschoff Date: Mon, 31 Aug 2026 12:49:40 -0500 Subject: [PATCH] fix(desktop): deliver Pulse mentions live so they notify while unfocused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The home feed poll pauses while the window is unfocused (#5490), and Pulse @mentions (kind 1) are feed-driven: with the poll paused, the notification pipeline never saw them, so no native notification and no Home/Mention badge appeared until the user refocused the app. Approval requests and reminders already had an exception: an always-on live #p subscription that triggers a home-feed refetch when a matching event arrives over the WebSocket. Add kind 1 to that subscription so a Pulse mention refreshes the feed — and flows into the existing badge and desktop-notification pipeline — the moment it arrives, without resuming any background polling. The filter is extracted into buildHomeFeedLivePTagFilter() with regression tests. Fixes #6276 Signed-off-by: mdschoff --- .../src/app/useLiveHomeFeedActions.test.mjs | 29 ++++++++++++++++++ desktop/src/app/useLiveHomeFeedActions.ts | 30 ++++++++++++++----- 2 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 desktop/src/app/useLiveHomeFeedActions.test.mjs diff --git a/desktop/src/app/useLiveHomeFeedActions.test.mjs b/desktop/src/app/useLiveHomeFeedActions.test.mjs new file mode 100644 index 00000000000..4022faca0be --- /dev/null +++ b/desktop/src/app/useLiveHomeFeedActions.test.mjs @@ -0,0 +1,29 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { buildHomeFeedLivePTagFilter } from "./useLiveHomeFeedActions.ts"; +import { + KIND_APPROVAL_REQUEST, + KIND_REMINDER, + KIND_TEXT_NOTE, +} from "../shared/constants/kinds.ts"; + +test("live p-tag filter covers Pulse mentions", () => { + // Regression: the home feed poll pauses while the window is unfocused, so + // Pulse (kind 1) mentions notify in the background only if this always-on + // subscription delivers them. + const filter = buildHomeFeedLivePTagFilter("abc123", 1_000); + assert.ok(filter.kinds.includes(KIND_TEXT_NOTE)); +}); + +test("live p-tag filter keeps approval and reminder coverage", () => { + const filter = buildHomeFeedLivePTagFilter("abc123", 1_000); + assert.ok(filter.kinds.includes(KIND_APPROVAL_REQUEST)); + assert.ok(filter.kinds.includes(KIND_REMINDER)); +}); + +test("live p-tag filter targets the user and is live-only", () => { + const filter = buildHomeFeedLivePTagFilter("abc123", 1_234); + assert.deepEqual(filter["#p"], ["abc123"]); + assert.equal(filter.since, 1_234); +}); diff --git a/desktop/src/app/useLiveHomeFeedActions.ts b/desktop/src/app/useLiveHomeFeedActions.ts index 6829100fa54..4e810648a8f 100644 --- a/desktop/src/app/useLiveHomeFeedActions.ts +++ b/desktop/src/app/useLiveHomeFeedActions.ts @@ -7,9 +7,30 @@ import { KIND_APPROVAL_REQUEST, KIND_EVENT_REMINDER, KIND_REMINDER, + KIND_TEXT_NOTE, } from "@/shared/constants/kinds"; -const HOME_FEED_ACTION_KINDS = [KIND_APPROVAL_REQUEST, KIND_REMINDER] as const; +/** + * Kinds that must trigger a home-feed refresh when they arrive p-tagging the + * user. The home feed poll pauses while the window is unfocused, so any + * feed-driven alert — Pulse mentions (kind 1), approval requests, reminders — + * only reaches the notification pipeline in the background through this + * always-on subscription. + */ +export const HOME_FEED_LIVE_P_TAG_KINDS = [ + KIND_TEXT_NOTE, + KIND_APPROVAL_REQUEST, + KIND_REMINDER, +] as const; + +export function buildHomeFeedLivePTagFilter(pubkey: string, since: number) { + return { + kinds: [...HOME_FEED_LIVE_P_TAG_KINDS], + "#p": [pubkey], + limit: 50, + since, + }; +} const LIVE_HOME_FEED_RETRY_BASE_MS = 1_000; const LIVE_HOME_FEED_RETRY_MAX_MS = 30_000; @@ -64,12 +85,7 @@ export function useLiveHomeFeedActions( void Promise.allSettled([ relayClient.subscribeLive( - { - kinds: [...HOME_FEED_ACTION_KINDS], - "#p": [normalizedPubkey], - limit: 50, - since, - }, + buildHomeFeedLivePTagFilter(normalizedPubkey, since), handleLiveHomeFeedEvent, ), relayClient.subscribeLive(