merge dhk-1 yuser login cache

This commit is contained in:
fengxiangdebaozi committed 2026-06-27 19:58:57 +08:00
commit 65449ffd71
1 file changed
+87 -15
+87 -15
View File
@@ -9,6 +9,8 @@ export const EXTERNAL_USER_ID_STORAGE_KEY = "userId";
export const EXTERNAL_USER_INFO_STORAGE_KEY = "userInfo";
export const GENERAL_QA_ROUTE = "/page/workspace/chats/new";
const YUSER_INFO_CACHE_KEY = "deerflow.yuserInfoByYUserId";
type UserDetailResponse = {
data?: {
id?: string;
@@ -34,6 +36,84 @@ function readStoredYUserId(info: Record<string, unknown>): string {
return value == null ? "" : String(value).trim();
}
function isPlainObject(value: unknown): value is Record<string, unknown> {
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}
function isUsableExternalValue(value: unknown): boolean {
if (value == null) return false;
if (typeof value !== "string") return true;
const trimmed = value.trim();
if (!trimmed) return false;
const lowered = trimmed.toLowerCase();
return lowered !== "null" && lowered !== "undefined";
}
function readYUserInfoCache(): Record<string, Record<string, unknown>> {
if (typeof window === "undefined") return {};
try {
const raw = window.localStorage.getItem(YUSER_INFO_CACHE_KEY);
if (!raw) return {};
const parsed = JSON.parse(raw);
if (!isPlainObject(parsed)) return {};
const cache: Record<string, Record<string, unknown>> = {};
for (const [key, value] of Object.entries(parsed)) {
if (isPlainObject(value)) cache[key] = value;
}
return cache;
} catch {
return {};
}
}
function readCachedYUserInfo(yUserId: string): Record<string, unknown> {
return readYUserInfoCache()[yUserId] ?? {};
}
function writeCachedYUserInfo(yUserId: string, info: Record<string, unknown>): void {
if (typeof window === "undefined") return;
try {
const cache = readYUserInfoCache();
cache[yUserId] = info;
window.localStorage.setItem(YUSER_INFO_CACHE_KEY, JSON.stringify(cache));
} catch {
/* noop */
}
}
function buildExternalUserInfo(
yUserId: string,
result: Record<string, unknown>,
previous: Record<string, unknown>,
cached: Record<string, unknown>,
): Record<string, unknown> {
const next: Record<string, unknown> = { ...cached };
for (const [key, value] of Object.entries(result)) {
if (isUsableExternalValue(value)) {
next[key] = value;
}
}
next.yUserId = yUserId;
const incomingAccessToken = normalizeExternalAccessToken(result.accessToken);
if (incomingAccessToken) {
next.accessToken = incomingAccessToken;
return next;
}
const previousYUserId = readStoredYUserId(previous);
const previousAccessToken =
previousYUserId === yUserId ? normalizeExternalAccessToken(previous.accessToken) : "";
const cachedAccessToken = normalizeExternalAccessToken(cached.accessToken);
const fallbackAccessToken = previousAccessToken || cachedAccessToken;
if (fallbackAccessToken) {
next.accessToken = fallbackAccessToken;
} else {
delete next.accessToken;
}
return next;
}
/**
* External login via yUserId + optional token (same flow as web-code Login.tsx):
* persist tools_token, resolve user via consumer API, store userId/userInfo.
@@ -58,22 +138,10 @@ export async function loginByYUserId(
// access_token,故登录流程随后会用 persistAccessToken 覆盖 userInfo.accessToken。
const result = res.data ?? {};
const previous = readExternalUserInfo();
const next: Record<string, unknown> = { ...result, yUserId };
const incomingAccessToken = normalizeExternalAccessToken(result.accessToken);
if (incomingAccessToken) {
next.accessToken = incomingAccessToken;
} else {
const previousAccessToken = normalizeExternalAccessToken(previous.accessToken);
const previousYUserId = readStoredYUserId(previous);
// Do not let an unstable upstream empty/null token wipe a usable token for
// the same external user. Avoid carrying it across different yUserId values.
if (previousAccessToken && previousYUserId === yUserId) {
next.accessToken = previousAccessToken;
} else {
delete next.accessToken;
}
}
const cached = readCachedYUserInfo(yUserId);
const next = buildExternalUserInfo(yUserId, result, previous, cached);
authStorageSet(EXTERNAL_USER_INFO_STORAGE_KEY, JSON.stringify(next));
writeCachedYUserInfo(yUserId, next);
}
export function persistToolsToken(token: string): void {
@@ -93,4 +161,8 @@ export function persistAccessToken(token: string): void {
const info = readExternalUserInfo();
info.accessToken = trimmed;
authStorageSet(EXTERNAL_USER_INFO_STORAGE_KEY, JSON.stringify(info));
const yUserId = readStoredYUserId(info);
if (yUserId) {
writeCachedYUserInfo(yUserId, info);
}
}