fix(watch-history): allow logged-out (local) removal instead of "disabled"

The logged-out delete error: handleWatchHistoryRemoval threw
"watch-history-disabled" whenever the service wasn't synced (isEnabled() false) —
which is the NORMAL state for a logged-out user — so local deletes errored with
"Watch history sync is not available right now" and never touched the local
queue. It conflated "not synced to relays" with "disabled".

Now it only rejects when neither synced NOR local history is supported. For a
local-only actor it proceeds with the snapshot (replace), which rewrites the
local queue (replaceLocalQueue), and SKIPS the relay publish (gated on synced) so
a session-actor list is never pushed to relays. Success copy reflects local vs
synced.

Tests + mutation-verified: local-only removal isn't rejected, snapshots with
replace, and does NOT publish to relays; synced removal still publishes; truly
disabled (no sync, no local) is still rejected. Reverting the gate fails the
local cases.

Build + full lint green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-06-20 19:00:51 -04:00
1 parent 12440d2f48
commit 0756dd36d8
2 files changed
+125 -23

No files matched your search

+36 -23
View File
@@ -222,7 +222,13 @@ export default class WatchHistoryController {
}
async handleWatchHistoryRemoval(payload = {}) {
if (!this.watchHistoryService?.isEnabled?.()) {
const synced = this.watchHistoryService?.isEnabled?.() === true;
// Logged-out / session actors aren't synced to relays, but their history
// lives in the LOCAL queue — removal must still work there. Only reject when
// neither synced nor local history is available.
const localOnly =
!synced && this.watchHistoryService?.supportsLocalHistory?.() === true;
if (!synced && !localOnly) {
const error = new Error("watch-history-disabled");
error.handled = true;
this.showError("Watch history sync is not available right now.");
@@ -332,31 +338,38 @@ export default class WatchHistoryController {
skipped: snapshotResult?.skipped,
});
try {
const updateResult = await this.nostrClient?.updateWatchHistoryList?.(
normalizedItems,
{
actorPubkey: actorCandidate || undefined,
replace: true,
source: reason,
},
);
logWatchHistoryDebug("watch-history:remove", "info", "list update published", {
ok: updateResult?.ok,
finalItemCount: updateResult?.items?.length,
});
} catch (updateError) {
devLogger.warn(
"[watchHistoryController] Failed to update local watch history list:",
updateError,
);
logWatchHistoryDebug("watch-history:remove", "warn", "list update failed", {
error: updateError?.message || String(updateError),
});
// Only push to relays when synced. For local-only actors the snapshot
// above already rewrote the local queue (replaceLocalQueue); publishing a
// session-actor list to relays would be wrong.
if (synced) {
try {
const updateResult = await this.nostrClient?.updateWatchHistoryList?.(
normalizedItems,
{
actorPubkey: actorCandidate || undefined,
replace: true,
source: reason,
},
);
logWatchHistoryDebug("watch-history:remove", "info", "list update published", {
ok: updateResult?.ok,
finalItemCount: updateResult?.items?.length,
});
} catch (updateError) {
devLogger.warn(
"[watchHistoryController] Failed to update local watch history list:",
updateError,
);
logWatchHistoryDebug("watch-history:remove", "warn", "list update failed", {
error: updateError?.message || String(updateError),
});
}
}
this.showSuccess(
"Removed from encrypted history. Relay sync may take a moment.",
synced
? "Removed from encrypted history. Relay sync may take a moment."
: "Removed from your local history.",
);
return { handledToasts: true, snapshot: snapshotResult };