fix(hashtagPreferences): prevent state reset on transient load failures

Prevents `HashtagPreferencesService` from aggressively resetting local state to empty when a load attempt fails due to transient issues (like empty relay lists or network errors) if valid data is already loaded for the current user. This fixes a race condition where tags would briefly load correctly and then turn gray/disappear during application initialization.
This commit is contained in:
google-labs-jules[bot] committed 2026-01-15 01:23:55 +00:00
1 parent b9171e9e05
commit 48ceed6797
1 file changed
+36 -1
+36 -1
View File
@@ -344,6 +344,11 @@ class HashtagPreferencesService {
async load(pubkey) {
const normalized = normalizeHexPubkey(pubkey);
const wasLoadedForUser =
this.activePubkey &&
this.activePubkey === normalized &&
(this.interests.size > 0 || this.disinterests.size > 0 || this.loaded);
this.activePubkey = normalized;
if (!normalized) {
@@ -360,6 +365,13 @@ class HashtagPreferencesService {
userLogger.warn(
`${LOG_PREFIX} nostrClient.pool.list unavailable; treating preferences as empty.`,
);
// If we already have data for this user, do not reset on transient client issues.
if (wasLoadedForUser) {
userLogger.warn(
`${LOG_PREFIX} Keeping existing preferences despite client unavailability.`,
);
return;
}
this.reset();
this.loaded = true;
return;
@@ -371,6 +383,12 @@ class HashtagPreferencesService {
: nostrClient.writeRelays,
);
if (!relays.length) {
if (wasLoadedForUser) {
userLogger.warn(
`${LOG_PREFIX} Keeping existing preferences; no relays available for refresh.`,
);
return;
}
this.reset();
this.loaded = true;
return;
@@ -393,12 +411,15 @@ class HashtagPreferencesService {
};
let events = [];
let fetchError = null;
try {
const result = await nostrClient.pool.list(relays, [filter]);
if (Array.isArray(result)) {
events = result.filter((event) => event && event.pubkey === normalized);
}
} catch (error) {
fetchError = error;
userLogger.warn(
`${LOG_PREFIX} Failed to load hashtag preferences from relays`,
error,
@@ -407,6 +428,15 @@ class HashtagPreferencesService {
}
if (!events.length) {
// If we failed to fetch (network error) but already have data for this user,
// preserve the existing state instead of wiping it.
if (fetchError && wasLoadedForUser) {
userLogger.warn(
`${LOG_PREFIX} Keeping existing preferences after fetch error.`,
);
return;
}
this.reset();
this.loaded = true;
return;
@@ -440,6 +470,9 @@ class HashtagPreferencesService {
}, null);
if (!latest) {
if (fetchError && wasLoadedForUser) {
return;
}
this.reset();
this.loaded = true;
return;
@@ -451,6 +484,9 @@ class HashtagPreferencesService {
`${LOG_PREFIX} Failed to decrypt hashtag preferences`,
decryptResult.error,
);
// If decryption fails on a reload, we might want to keep old data?
// But typically decryption failure means key mismatch or bad payload.
// Resetting is safer here to avoid stuck state, unless we want to be very conservative.
this.reset();
this.loaded = true;
return;
@@ -795,4 +831,3 @@ const hashtagPreferences = new HashtagPreferencesService();
export default hashtagPreferences;
export { HashtagPreferencesService, hashtagPreferences, EVENTS as HASHTAG_PREFERENCES_EVENTS };