diff --git a/js/accessControl.js b/js/accessControl.js index 99e09adc..bae6e578 100644 --- a/js/accessControl.js +++ b/js/accessControl.js @@ -81,6 +81,7 @@ class AccessControl { this._refreshPromise = Promise.resolve(); this._hydratedFromCache = false; this._whitelistListeners = new Set(); + this._editorListeners = new Set(); this._hydrateFromCache(); } @@ -100,12 +101,15 @@ class AccessControl { const whitelist = Array.isArray(state?.whitelist) ? state.whitelist : []; const blacklist = Array.isArray(state?.blacklist) ? state.blacklist : []; + const previousEditors = + this.editors instanceof Set ? new Set(this.editors) : new Set(); const previousWhitelist = this.whitelist instanceof Set ? new Set(this.whitelist) : new Set(); this.editors = new Set( dedupeNpubs([...ADMIN_EDITORS_NPUBS, ...editors]) ); + const editorsChanged = !areSetsEqual(previousEditors, this.editors); const normalizedWhitelist = dedupeNpubs(whitelist); this.whitelist = new Set(normalizedWhitelist); const whitelistChanged = !areSetsEqual(previousWhitelist, this.whitelist); @@ -142,6 +146,9 @@ class AccessControl { if (whitelistChanged) { this._emitWhitelistChange(Array.from(this.whitelist)); } + if (editorsChanged) { + this._emitEditorsChange(Array.from(this.editors)); + } } _emitWhitelistChange(whitelistValues) { @@ -162,6 +169,24 @@ class AccessControl { } } + _emitEditorsChange(editorsValues) { + if (!this._editorListeners.size) { + return; + } + + const snapshot = Array.isArray(editorsValues) + ? [...editorsValues] + : this.getEditors(); + + for (const listener of Array.from(this._editorListeners)) { + try { + listener(snapshot); + } catch (error) { + userLogger.error("accessControl editors listener failed", error); + } + } + } + _performRefresh() { if (this._isRefreshing) { return this._refreshPromise; @@ -269,6 +294,18 @@ class AccessControl { }; } + onEditorsChange(listener) { + if (typeof listener !== "function") { + return () => {}; + } + + this._editorListeners.add(listener); + + return () => { + this._editorListeners.delete(listener); + }; + } + async addModerator(requestorNpub, moderatorNpub) { if (!this.isSuperAdmin(requestorNpub)) { return { ok: false, error: "forbidden" }; diff --git a/js/bootstrap.js b/js/bootstrap.js index bc450722..38408f8e 100644 --- a/js/bootstrap.js +++ b/js/bootstrap.js @@ -81,10 +81,16 @@ async function bootstrapTrustedSeeds() { applySeeds(); + const applyOnChange = () => { + applySeeds(); + }; + if (accessControl && typeof accessControl.onWhitelistChange === "function") { - accessControl.onWhitelistChange(() => { - applySeeds(); - }); + accessControl.onWhitelistChange(applyOnChange); + } + + if (accessControl && typeof accessControl.onEditorsChange === "function") { + accessControl.onEditorsChange(applyOnChange); } }