From db2b08378d422e7c79ed9ab7558d599b46dfbdd2 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Sun, 11 Jan 2026 08:50:22 -0500 Subject: [PATCH] Add session actor hook for moderation sync --- js/app.js | 47 +++++++++++++++++++++++++++++++++++++++++++ js/nostr/client.js | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/js/app.js b/js/app.js index ab045ad1..b1bfaeae 100644 --- a/js/app.js +++ b/js/app.js @@ -508,6 +508,53 @@ class Application { } }; + const handleSessionActorReady = async ({ pubkey, reason } = {}) => { + if (this.pubkey) { + return; + } + + const normalizedPubkey = this.normalizeHexPubkey(pubkey); + if (!normalizedPubkey) { + return; + } + + const triggerLabel = reason ? `session-actor-${reason}` : "session-actor"; + await syncSessionActorBlacklist(triggerLabel); + + const refreshReason = "session-actor-ready"; + if (typeof this.refreshVisibleModerationUi === "function") { + try { + this.refreshVisibleModerationUi({ reason: refreshReason }); + } catch (error) { + devLogger.warn( + "[app.init()] Failed to refresh moderation UI after session actor:", + error, + ); + } + } else { + this.refreshAllVideoGrids({ + reason: refreshReason, + forceMainReload: true, + }).catch((error) => { + devLogger.warn( + "[app.init()] Failed to refresh video grids after session actor:", + error, + ); + }); + } + }; + + if (typeof nostrClient.onSessionActorChange === "function") { + nostrClient.onSessionActorChange((detail) => { + handleSessionActorReady(detail).catch((error) => { + devLogger.warn( + "[app.init()] Failed to process session actor change:", + error, + ); + }); + }); + } + await syncSessionActorBlacklist("post-refresh"); if (typeof accessControl.onBlacklistChange === "function") { diff --git a/js/nostr/client.js b/js/nostr/client.js index 4790e0bd..31210d98 100644 --- a/js/nostr/client.js +++ b/js/nostr/client.js @@ -1247,6 +1247,7 @@ export class NostrClient { this.countUnsupportedRelays = new Set(); this.nip46Client = null; this.remoteSignerListeners = new Set(); + this.sessionActorListeners = new Set(); const storedRemoteSigner = this.getStoredNip46Metadata(); this.remoteSignerStatus = { state: storedRemoteSigner.hasSession ? "stored" : "idle", @@ -1398,6 +1399,53 @@ export class NostrClient { }; } + emitSessionActorChange(actor, context = {}) { + const resolvedActor = + actor && typeof actor === "object" ? actor : this.sessionActor; + const pubkey = + typeof resolvedActor?.pubkey === "string" ? resolvedActor.pubkey.trim() : ""; + if (!pubkey) { + return null; + } + + const reason = + typeof context.reason === "string" && context.reason.trim() + ? context.reason.trim() + : ""; + const createdAt = Number.isFinite(resolvedActor?.createdAt) + ? resolvedActor.createdAt + : null; + const snapshot = { + pubkey, + source: + typeof resolvedActor?.source === "string" ? resolvedActor.source : "", + persisted: resolvedActor?.persisted === true, + createdAt, + reason, + }; + + for (const listener of Array.from(this.sessionActorListeners)) { + try { + listener(snapshot); + } catch (error) { + devLogger.warn("[nostr] Session actor listener threw:", error); + } + } + + return snapshot; + } + + onSessionActorChange(listener) { + if (typeof listener !== "function") { + return () => {}; + } + + this.sessionActorListeners.add(listener); + return () => { + this.sessionActorListeners.delete(listener); + }; + } + async createNip46KeyPair(existingPrivateKey = "", existingPublicKey = "") { let privateKey = typeof existingPrivateKey === "string" && existingPrivateKey.trim() @@ -3167,6 +3215,7 @@ export class NostrClient { const restored = this.restoreSessionActorFromStorage(); if (restored) { this.sessionActor = restored; + this.emitSessionActorChange(restored, { reason: "restored" }); return restored.pubkey; } } @@ -3179,6 +3228,7 @@ export class NostrClient { this.sessionActorCipherClosures = null; this.sessionActorCipherClosuresPrivateKey = null; this.persistSessionActor(minted); + this.emitSessionActorChange(minted, { reason: "minted" }); return minted.pubkey; }