From 95dc380f543455d9ed878f767d67862ad10d8b39 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Thu, 29 Jan 2026 12:40:50 -0500 Subject: [PATCH] Emit post-login hydration events --- js/app.js | 60 ++++++++++++++++++++++---- js/services/authService.js | 79 +++++++++++++++++++++++++---------- js/ui/applicationBootstrap.js | 24 +++++++++++ 3 files changed, 134 insertions(+), 29 deletions(-) diff --git a/js/app.js b/js/app.js index aae92dbc..8d3406cc 100644 --- a/js/app.js +++ b/js/app.js @@ -4104,6 +4104,7 @@ class Application { detail && typeof detail.postLoginPromise?.then === "function" ? detail.postLoginPromise : Promise.resolve(detail?.postLogin ?? null); + const postLoginResult = detail?.postLogin ?? null; if (detail && typeof detail === "object") { try { @@ -4270,13 +4271,6 @@ class Application { devLogger.error("Post-login hydration failed:", error); }); - let postLoginResult = null; - try { - postLoginResult = await postLoginPromise; - } catch (error) { - devLogger.error("Post-login processing failed:", error); - } - await nwcPromise; // We do not await hashtagPreferencesPromise here; it loads in the background. @@ -4366,6 +4360,58 @@ class Application { } } + handleBlocksLoaded(detail = {}) { + if (detail?.blocksLoaded !== true) { + return; + } + + if (this.profileController) { + try { + this.profileController.populateBlockedList(); + } catch (error) { + devLogger.warn( + "[Application] Failed to refresh blocked list after blocks loaded:", + error, + ); + } + } + + try { + void this.onVideosShouldRefresh({ reason: "blocks-loaded" }); + } catch (error) { + devLogger.warn( + "[Application] Failed to refresh videos after blocks loaded:", + error, + ); + } + } + + handleRelaysLoaded(detail = {}) { + if (detail?.relaysLoaded !== true) { + return; + } + + if (this.profileController) { + try { + this.profileController.populateProfileRelays(); + } catch (error) { + devLogger.warn( + "[Application] Failed to refresh profile relays after relays loaded:", + error, + ); + } + + try { + void this.profileController.refreshDmRelayPreferences({ force: true }); + } catch (error) { + devLogger.warn( + "[Application] Failed to refresh DM relay preferences after relays loaded:", + error, + ); + } + } + } + async requestLogout() { const detail = await this.authService.logout(); diff --git a/js/services/authService.js b/js/services/authService.js index 0a6525a9..3dc12d6c 100644 --- a/js/services/authService.js +++ b/js/services/authService.js @@ -622,8 +622,10 @@ export default class AuthService { postLoginError: null, }; - const postLoginPromise = Promise.resolve() - .then(() => this.applyPostLoginState()) + const { detail: postLoginDetail, completionPromise } = this.applyPostLoginState(); + detail.postLogin = postLoginDetail; + + const postLoginPromise = Promise.resolve(completionPromise) .then((postLogin) => { detail.postLogin = postLogin; detail.postLoginError = null; @@ -677,17 +679,19 @@ export default class AuthService { return detail; } - async applyPostLoginState() { + applyPostLoginState() { const activePubkey = this.normalizeHexPubkey(getPubkey()) || getPubkey(); + const cachedEntry = activePubkey ? this.getProfileCacheEntry(activePubkey) : null; + const cachedProfile = cachedEntry?.profile || FALLBACK_PROFILE; const detail = { pubkey: activePubkey || null, blocksLoaded: false, relaysLoaded: false, - profile: null, + profile: cachedProfile, }; if (!activePubkey) { - return detail; + return { detail, completionPromise: Promise.resolve(detail) }; } const schedule = (callback) => Promise.resolve().then(() => callback()); @@ -703,6 +707,13 @@ export default class AuthService { this.log("[AuthService] Failed to load block list", error); return false; }, + emit: (value, error) => { + this.emit("blocksLoaded", { + pubkey: activePubkey, + blocksLoaded: value, + error: error ?? null, + }); + }, }); } @@ -715,37 +726,61 @@ export default class AuthService { this.log("[AuthService] Failed to load relay list", error); return false; }, + emit: (value, error) => { + this.emit("relaysLoaded", { + pubkey: activePubkey, + relaysLoaded: value, + error: error ?? null, + }); + }, }); } operations.push({ name: "profile", promise: schedule(() => this.loadOwnProfile(activePubkey)), - onFulfilled: (value) => value, + onFulfilled: (value) => { + const profile = value || FALLBACK_PROFILE; + this.setProfileCacheEntry(activePubkey, profile, { + persist: true, + reason: "post-login", + }); + return profile; + }, onRejected: (error) => { this.log("[AuthService] Failed to load own profile", error); - return null; + const fallbackProfile = cachedProfile || FALLBACK_PROFILE; + this.setProfileCacheEntry(activePubkey, fallbackProfile, { + persist: true, + reason: "post-login-fallback", + }); + return fallbackProfile; }, }); - const settled = await Promise.allSettled( - operations.map((operation) => operation.promise) + const wrappedPromises = operations.map((operation) => + operation.promise + .then((value) => { + const resolved = operation.onFulfilled(value); + detail[operation.name] = resolved; + if (typeof operation.emit === "function") { + operation.emit(resolved, null); + } + return resolved; + }) + .catch((error) => { + const resolved = operation.onRejected(error); + detail[operation.name] = resolved; + if (typeof operation.emit === "function") { + operation.emit(resolved, error); + } + return resolved; + }), ); - settled.forEach((result, index) => { - const operation = operations[index]; - if (!operation) { - return; - } + const completionPromise = Promise.allSettled(wrappedPromises).then(() => detail); - if (result.status === "fulfilled") { - detail[operation.name] = operation.onFulfilled(result.value); - } else { - detail[operation.name] = operation.onRejected(result.reason); - } - }); - - return detail; + return { detail, completionPromise }; } async logout() { diff --git a/js/ui/applicationBootstrap.js b/js/ui/applicationBootstrap.js index 017d769d..6030f3a5 100644 --- a/js/ui/applicationBootstrap.js +++ b/js/ui/applicationBootstrap.js @@ -409,6 +409,30 @@ export default class ApplicationBootstrap { } }), ); + app.authEventUnsubscribes.push( + app.authService.on("blocksLoaded", (detail) => { + try { + app.handleBlocksLoaded(detail); + } catch (error) { + devLogger.warn( + "Failed to process blocks loaded event:", + error, + ); + } + }), + ); + app.authEventUnsubscribes.push( + app.authService.on("relaysLoaded", (detail) => { + try { + app.handleRelaysLoaded(detail); + } catch (error) { + devLogger.warn( + "Failed to process relays loaded event:", + error, + ); + } + }), + ); app.commentThreadService = this.services.commentThreadService ||