mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-03 19:35:28 +00:00
Fix hashtag preferences loading and profile persistence issues
- Migrated Kind 0 profile metadata storage to unified `profileCache.js` with partitioning and persistence. - Added `defaultDTag` for hashtag preferences in `cachePolicies.js` to ensure consistent key resolution. - Updated `hashtagPreferencesService.js` to use `profileCache` and implemented legacy data migration. - Added `handleEvent` to `NostrClient` to centrally ingest Kind 0 events into the cache. - Updated `authService.js` and `cache.js` to delegate profile operations to the unified cache system. - Added `PROFILE_METADATA` schema to `nostrEventSchemas.js`.
This commit is contained in:
1 parent
983f67fa1b
commit
a2de2b550d
7 files changed
+220
-124
No files matched your search
+26
-30
@@ -1060,15 +1060,9 @@ export default class AuthService {
|
||||
});
|
||||
|
||||
const newest = selectNewestEvent(aggregated);
|
||||
if (!newest) {
|
||||
return;
|
||||
if (newest && this.nostrClient && typeof this.nostrClient.handleEvent === "function") {
|
||||
this.nostrClient.handleEvent(newest);
|
||||
}
|
||||
|
||||
const profile = buildProfileFromEvent(newest);
|
||||
this.setProfileCacheEntry(normalized, profile, {
|
||||
persist: true,
|
||||
reason: "load-own-profile:background",
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
this.log("[AuthService] Background profile refresh failed", error);
|
||||
@@ -1096,11 +1090,12 @@ export default class AuthService {
|
||||
if (fastResult?.events?.length) {
|
||||
const newest = selectNewestEvent(fastResult.events);
|
||||
if (newest) {
|
||||
if (this.nostrClient && typeof this.nostrClient.handleEvent === "function") {
|
||||
this.nostrClient.handleEvent(newest);
|
||||
}
|
||||
const profile = buildProfileFromEvent(newest);
|
||||
this.setProfileCacheEntry(normalized, profile, {
|
||||
persist: true,
|
||||
reason: "load-own-profile:fast",
|
||||
});
|
||||
// setProfileCacheEntry now delegates to profileCache.setProfile, but handleEvent also does it.
|
||||
// Doing it here returns the profile object which might be needed immediately.
|
||||
background.catch(() => {});
|
||||
return profile;
|
||||
}
|
||||
@@ -1159,24 +1154,25 @@ export default class AuthService {
|
||||
}
|
||||
}
|
||||
|
||||
if (newest?.content) {
|
||||
const data = JSON.parse(newest.content);
|
||||
const profile = {
|
||||
name: data.display_name || data.name || FALLBACK_PROFILE.name,
|
||||
picture: data.picture || FALLBACK_PROFILE.picture,
|
||||
about: typeof data.about === "string" ? data.about : FALLBACK_PROFILE.about,
|
||||
website:
|
||||
typeof data.website === "string" ? data.website : FALLBACK_PROFILE.website,
|
||||
banner:
|
||||
typeof data.banner === "string" ? data.banner : FALLBACK_PROFILE.banner,
|
||||
lud16: typeof data.lud16 === "string" ? data.lud16 : FALLBACK_PROFILE.lud16,
|
||||
lud06: typeof data.lud06 === "string" ? data.lud06 : FALLBACK_PROFILE.lud06,
|
||||
};
|
||||
this.setProfileCacheEntry(normalized, profile, {
|
||||
persist: true,
|
||||
reason: forceRefresh ? "force-refresh" : "fetch-profile",
|
||||
});
|
||||
return profile;
|
||||
if (newest) {
|
||||
if (this.nostrClient && typeof this.nostrClient.handleEvent === "function") {
|
||||
this.nostrClient.handleEvent(newest);
|
||||
}
|
||||
if (newest.content) {
|
||||
const data = JSON.parse(newest.content);
|
||||
const profile = {
|
||||
name: data.display_name || data.name || FALLBACK_PROFILE.name,
|
||||
picture: data.picture || FALLBACK_PROFILE.picture,
|
||||
about: typeof data.about === "string" ? data.about : FALLBACK_PROFILE.about,
|
||||
website:
|
||||
typeof data.website === "string" ? data.website : FALLBACK_PROFILE.website,
|
||||
banner:
|
||||
typeof data.banner === "string" ? data.banner : FALLBACK_PROFILE.banner,
|
||||
lud16: typeof data.lud16 === "string" ? data.lud16 : FALLBACK_PROFILE.lud16,
|
||||
lud06: typeof data.lud06 === "string" ? data.lud06 : FALLBACK_PROFILE.lud06,
|
||||
};
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.log("[AuthService] Failed to fetch profile", error);
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
publishEventToRelays,
|
||||
assertAnyRelayAccepted,
|
||||
} from "../nostrPublish.js";
|
||||
import { userLogger } from "../utils/logger.js";
|
||||
import { userLogger, devLogger } from "../utils/logger.js";
|
||||
import { profileCache } from "../state/profileCache.js";
|
||||
|
||||
const LOG_PREFIX = "[HashtagPreferences]";
|
||||
@@ -276,28 +276,56 @@ class HashtagPreferencesService {
|
||||
saveToCache() {
|
||||
const interests = this.getInterests();
|
||||
const disinterests = this.getDisinterests();
|
||||
profileCache.set("interests", {
|
||||
const payload = {
|
||||
interests,
|
||||
disinterests,
|
||||
version: this.preferencesVersion,
|
||||
eventId: this.eventId,
|
||||
createdAt: this.eventCreatedAt,
|
||||
});
|
||||
};
|
||||
// Use the note type key directly, though "interests" maps to HASHTAG_PREFERENCES
|
||||
// in profileCache. Using NOTE_TYPES.HASHTAG_PREFERENCES explicitly is safer if we import it,
|
||||
// but relying on the mapped key "interests" is also consistent with current usage.
|
||||
// However, the fix requires us to ensure we use the unified path.
|
||||
// We'll stick to "interests" which maps to NOTE_TYPES.HASHTAG_PREFERENCES in profileCache.js
|
||||
profileCache.set("interests", payload);
|
||||
}
|
||||
|
||||
loadFromCache(pubkey) {
|
||||
// profileCache internally uses activePubkey, but we should verify if it matches
|
||||
const cached = profileCache.get("interests");
|
||||
if (cached && typeof cached === "object") {
|
||||
this.activePubkey = normalizeHexPubkey(pubkey);
|
||||
this.interests = new Set(Array.isArray(cached.interests) ? cached.interests : []);
|
||||
this.disinterests = new Set(Array.isArray(cached.disinterests) ? cached.disinterests : []);
|
||||
this.eventId = cached.eventId || null;
|
||||
this.eventCreatedAt = cached.createdAt || null;
|
||||
this.preferencesVersion = cached.version || DEFAULT_VERSION;
|
||||
this.loaded = true;
|
||||
this.emitChange("cache-load");
|
||||
return true;
|
||||
try {
|
||||
let cached = profileCache.get("interests");
|
||||
|
||||
// Legacy fallback migration
|
||||
if (!cached && typeof localStorage !== "undefined") {
|
||||
try {
|
||||
const legacy = localStorage.getItem(HASHTAG_IDENTIFIER);
|
||||
if (legacy) {
|
||||
const parsed = JSON.parse(legacy);
|
||||
// Migrate to unified profile cache
|
||||
profileCache.set("interests", parsed);
|
||||
localStorage.removeItem(HASHTAG_IDENTIFIER);
|
||||
cached = parsed;
|
||||
devLogger.log(`${LOG_PREFIX} Migrated legacy preferences to profileCache.`);
|
||||
}
|
||||
} catch (err) {
|
||||
devLogger.warn(`${LOG_PREFIX} Legacy migration failed:`, err);
|
||||
}
|
||||
}
|
||||
|
||||
if (cached && typeof cached === "object") {
|
||||
this.activePubkey = normalizeHexPubkey(pubkey);
|
||||
this.interests = new Set(Array.isArray(cached.interests) ? cached.interests : []);
|
||||
this.disinterests = new Set(Array.isArray(cached.disinterests) ? cached.disinterests : []);
|
||||
this.eventId = cached.eventId || null;
|
||||
this.eventCreatedAt = cached.createdAt || null;
|
||||
this.preferencesVersion = cached.version || DEFAULT_VERSION;
|
||||
this.loaded = true;
|
||||
this.emitChange("cache-load");
|
||||
return true;
|
||||
}
|
||||
} catch (err) {
|
||||
devLogger.warn(`${LOG_PREFIX} loadFromCache failed:`, err);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user