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:
google-labs-jules[bot] committed 2026-01-18 02:09:04 +00:00
1 parent 983f67fa1b
commit a2de2b550d
7 files changed
+220 -124

No files matched your search

+42 -14
View File
@@ -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;
}