diff --git a/frontend/components/account/__tests__/authSnapshot.test.ts b/frontend/components/account/__tests__/authSnapshot.test.ts index e506468d..58d167b9 100644 --- a/frontend/components/account/__tests__/authSnapshot.test.ts +++ b/frontend/components/account/__tests__/authSnapshot.test.ts @@ -1,6 +1,7 @@ import { buildAuthMePath, mergeAccountAuthSnapshot, + shouldResolveAccountUnknownWithFullProfile, } from "@/lib/auth-snapshot"; import type { AuthSnapshotLike } from "@/lib/auth-snapshot"; @@ -64,4 +65,33 @@ export function runTests() { inactive.subscription_active === false, "account snapshot merge must still accept a confirmed inactive subscription response", ); + + assert( + shouldResolveAccountUnknownWithFullProfile( + { authenticated: true, subscription_active: null }, + true, + ), + "account center must resolve an unknown local-user subscription snapshot with the full auth profile", + ); + assert( + !shouldResolveAccountUnknownWithFullProfile( + { authenticated: true, subscription_active: false }, + true, + ), + "account center must not re-resolve an explicitly inactive subscription snapshot", + ); + assert( + !shouldResolveAccountUnknownWithFullProfile( + { authenticated: false, subscription_active: null }, + true, + ), + "account center must not re-resolve an unauthenticated backend snapshot", + ); + assert( + !shouldResolveAccountUnknownWithFullProfile( + { authenticated: true, subscription_active: null }, + false, + ), + "account center must only resolve unknown subscription snapshots when a local Supabase user exists", + ); } diff --git a/frontend/components/account/__tests__/paymentShell.test.ts b/frontend/components/account/__tests__/paymentShell.test.ts index df054e90..36bd9950 100644 --- a/frontend/components/account/__tests__/paymentShell.test.ts +++ b/frontend/components/account/__tests__/paymentShell.test.ts @@ -259,6 +259,13 @@ export function runTests() { hookSource.includes("retriedBackendJson"), "account snapshot loader must retry with a refreshed Supabase token when local user exists but /api/auth/me reports unauthenticated", ); + assert( + hookSource.includes("shouldResolveAccountUnknownWithFullProfile") && + hookSource.includes("backendJson = await readAuthSnapshot(latestHeaders);") && + hookSource.indexOf("shouldResolveAccountUnknownWithFullProfile") < + hookSource.indexOf("setBackend((previous) => mergeAccountAuthSnapshot(previous, backendJson))"), + "account snapshot loader must resolve unknown entitlement-scope results through full auth/me before rendering account status", + ); assert( hookSource.includes("refreshEntitlementAfterPayment") && paymentFlowSource.includes("refreshEntitlementAfterPayment") && diff --git a/frontend/components/account/useAccountPayment.ts b/frontend/components/account/useAccountPayment.ts index 98972c22..ec35e518 100644 --- a/frontend/components/account/useAccountPayment.ts +++ b/frontend/components/account/useAccountPayment.ts @@ -6,6 +6,7 @@ import type { User } from "@supabase/supabase-js"; import { buildAuthMePath, mergeAccountAuthSnapshot, + shouldResolveAccountUnknownWithFullProfile, } from "@/lib/auth-snapshot"; import { getSupabaseBrowserClient } from "@/lib/supabase/client"; @@ -244,9 +245,19 @@ export function useAccountPayment(params: UseAccountPaymentParams) { // an unauthenticated backend snapshot as a temporary sync state. } } + let resolvedWithFullProfile = false; + if (shouldResolveAccountUnknownWithFullProfile(backendJson, Boolean(localUser))) { + try { + backendJson = await readAuthSnapshot(latestHeaders); + resolvedWithFullProfile = true; + } catch { + // Keep the explicit unknown state only when the full account profile + // cannot be read; the refresh button can retry the same path. + } + } setBackend((previous) => mergeAccountAuthSnapshot(previous, backendJson)); setUpdatedAt(new Date().toISOString()); - if (backendJson.authenticated !== false) { + if (backendJson.authenticated !== false && !resolvedWithFullProfile) { void readAuthSnapshot(latestHeaders) .then((fullJson) => { setBackend((previous) => diff --git a/frontend/lib/auth-snapshot.ts b/frontend/lib/auth-snapshot.ts index 03b3397c..ed8e35e9 100644 --- a/frontend/lib/auth-snapshot.ts +++ b/frontend/lib/auth-snapshot.ts @@ -40,6 +40,17 @@ export function isUnknownSubscriptionSnapshot( ); } +export function shouldResolveAccountUnknownWithFullProfile( + snapshot: AuthSnapshotLike | null | undefined, + localUserPresent: boolean, +) { + return Boolean( + localUserPresent && + snapshot?.authenticated !== false && + isUnknownSubscriptionSnapshot(snapshot), + ); +} + export function mergeAccountAuthSnapshot( previous: T | null | undefined, next: T,