Improve terminal entitlement resilience

This commit is contained in:
2569718930@qq.com
2026-05-30 19:10:19 +08:00
parent 097971f107
commit e864181c3c
7 changed files with 594 additions and 29 deletions
@@ -91,7 +91,13 @@ function createLocalAccess(): ProAccessState {
};
}
function createTransientAccess(error: unknown): ProAccessState {
return {
...createEmptyAccess(true),
authenticated: true,
error: String(error),
};
}
const TERM = {
cityThreshold: { en: "City / Threshold", zh: "城市 / 阈值" },
@@ -931,20 +937,42 @@ function ScanTerminalScreen() {
);
const loadAuthProfile = useCallback(
async (accessToken?: string | null): Promise<AuthProfilePayload> => {
async (
accessToken?: string | null,
options?: { preferSnapshot?: boolean },
): Promise<AuthProfilePayload> => {
const headers: Record<string, string> = { Accept: "application/json" };
const token = String(accessToken || "").trim();
if (token) headers.Authorization = `Bearer ${token}`;
const response = await fetch("/api/auth/me", {
cache: "no-store",
headers,
});
const response = await fetch(
options?.preferSnapshot
? "/api/auth/me?prefer_snapshot=1"
: "/api/auth/me",
{
cache: "no-store",
headers,
},
);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json() as Promise<AuthProfilePayload>;
},
[],
);
const refreshLiveAuthProfile = useCallback(async () => {
const supabaseEnabled = hasSupabasePublicEnv();
const payload = await loadTerminalAuthProfile({
getSession: () =>
supabaseEnabled
? getSupabaseBrowserClient().auth.getSession()
: Promise.resolve({ data: { session: null } }),
hasSupabasePublicEnv: supabaseEnabled,
loadAuthProfile: (accessToken) =>
loadAuthProfile(accessToken, { preferSnapshot: false }),
});
setProAccess((prev) => mergeAccessStateWithAuthPayload(prev, payload));
}, [loadAuthProfile]);
// Listen to Supabase auth events (e.g. token refreshed, signed out)
useEffect(() => {
if (!hasSupabasePublicEnv()) return;
@@ -1064,19 +1092,24 @@ function ScanTerminalScreen() {
.then((payload) => {
if (cancelled) return;
setProAccess((prev) => mergeAccessStateWithAuthPayload(prev, payload));
if (payload.entitlement_snapshot === true) {
window.setTimeout(() => {
if (!cancelled) void refreshLiveAuthProfile();
}, 0);
}
})
.catch((error) => {
if (cancelled) return;
setProAccess((prev) => (
prev.subscriptionActive
? { ...prev, loading: false, error: String(error) }
: { ...createEmptyAccess(false), error: String(error) }
: createTransientAccess(error)
));
});
return () => {
cancelled = true;
};
}, [loadAuthProfile]);
}, [loadAuthProfile, refreshLiveAuthProfile]);
useEffect(() => {
if (