Merge pull request #1938 from PR0M3TH3AN/codex/refactor-authservice-for-partial-results

Emit post-login hydration updates without blocking login
This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2026-01-29 12:41:18 -05:00
commit 0cf39bce79
3 files changed
+134 -29

No files matched your search

+53 -7
View File
@@ -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();
+57 -22
View File
@@ -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() {
+24
View File
@@ -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 ||