fix: avoid terminal cold-start paywall race

This commit is contained in:
2569718930@qq.com
2026-05-30 14:48:09 +08:00
parent 1c250906ed
commit c79619898a
4 changed files with 58 additions and 2 deletions
@@ -967,8 +967,13 @@ function ScanTerminalScreen() {
} }
} catch {} } catch {}
setProAccess(createEmptyAccess(false)); setProAccess(createEmptyAccess(false));
} else if (event === "TOKEN_REFRESHED" || event === "SIGNED_IN") { } else if (
event === "INITIAL_SESSION" ||
event === "TOKEN_REFRESHED" ||
event === "SIGNED_IN"
) {
try { try {
if (!session?.access_token) return;
const payload = await loadAuthProfile(session?.access_token); const payload = await loadAuthProfile(session?.access_token);
setProAccess((prev) => mergeAccessStateWithAuthPayload(prev, payload)); setProAccess((prev) => mergeAccessStateWithAuthPayload(prev, payload));
} catch {} } catch {}
@@ -79,4 +79,43 @@ export async function runTests() {
cookieOnlyResult.user_id === "cookie-user", cookieOnlyResult.user_id === "cookie-user",
"terminal auth bootstrap should accept an authenticated cookie profile immediately", "terminal auth bootstrap should accept an authenticated cookie profile immediately",
); );
const delayedBearerSession = deferred<{ data: { session: { access_token: string } } }>();
let coldStartSettled = false;
const coldStartResultPromise = loadTerminalAuthProfile({
hasSupabasePublicEnv: true,
getSession: () => delayedBearerSession.promise,
loadAuthProfile: (accessToken) => {
const token = String(accessToken || "");
if (!token) {
return Promise.resolve({
authenticated: true,
user_id: "cookie-user",
subscription_active: null,
degraded_auth_profile: true,
});
}
return Promise.resolve({
authenticated: true,
user_id: "bearer-paid-user",
subscription_active: true,
});
},
});
coldStartResultPromise.then(() => {
coldStartSettled = true;
});
await flushMicrotasks();
assert(
coldStartSettled === false,
"terminal auth bootstrap must not show a cold-start paywall from a degraded cookie profile before bearer auth has a chance to confirm Pro",
);
delayedBearerSession.resolve({ data: { session: { access_token: "paid-token" } } });
const coldStartResult = await coldStartResultPromise;
assert(
coldStartResult.user_id === "bearer-paid-user" &&
coldStartResult.subscription_active === true,
"terminal auth bootstrap should prefer the bearer-confirmed active Pro profile over a degraded cookie profile",
);
} }
@@ -76,4 +76,10 @@ export function runTests() {
signedOutBlock.indexOf("setProAccess(createEmptyAccess(false))"), signedOutBlock.indexOf("setProAccess(createEmptyAccess(false))"),
"terminal auth listener must re-check the current Supabase session before clearing access on SIGNED_OUT events", "terminal auth listener must re-check the current Supabase session before clearing access on SIGNED_OUT events",
); );
assert(
dashboardSource.includes('event === "INITIAL_SESSION"') &&
dashboardSource.indexOf('event === "INITIAL_SESSION"') <
dashboardSource.indexOf('event === "TOKEN_REFRESHED"'),
"terminal auth listener must hydrate access from Supabase INITIAL_SESSION events during first navigation from the landing page",
);
} }
@@ -41,6 +41,12 @@ function firstKnownProfile(cookieResult: SettledProfile, bearerResult: SettledPr
}; };
} }
function canResolveProfileImmediately(
payload: TerminalAuthProfilePayload | null,
): payload is TerminalAuthProfilePayload {
return payload?.authenticated === true && payload.subscription_active === true;
}
export async function loadTerminalAuthProfile({ export async function loadTerminalAuthProfile({
getSession, getSession,
hasSupabasePublicEnv, hasSupabasePublicEnv,
@@ -56,7 +62,7 @@ export async function loadTerminalAuthProfile({
}); });
const resolveIfAuthenticated = (payload: TerminalAuthProfilePayload | null) => { const resolveIfAuthenticated = (payload: TerminalAuthProfilePayload | null) => {
if (!payload?.authenticated || resolvedAuthenticated) return; if (!canResolveProfileImmediately(payload) || resolvedAuthenticated) return;
resolvedAuthenticated = true; resolvedAuthenticated = true;
resolveAuthenticated?.(payload); resolveAuthenticated?.(payload);
}; };