Files
ttstd-infinite-canvas/web/src/lib/user-session.ts

67 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { getFeatureAvailability, getSystemChannels, type AuthSessionPayload } from "@/services/api/auth";
import { localForageStorage } from "@/lib/localforage-storage";
import { appQueryClient } from "@/lib/query-client";
import { scopedLocalStorage, setActiveUserScope } from "@/lib/user-scope";
import { CANVAS_STORE_KEY, flushCanvasStorePersistence, useCanvasStore } from "@/stores/canvas/use-canvas-store";
import { ASSET_STORE_KEY, useAssetStore } from "@/stores/use-asset-store";
import { CONFIG_STORE_KEY, defaultConfig, normalizeConfigSnapshot, useConfigStore } from "@/stores/use-config-store";
import { useUserStore } from "@/stores/use-user-store";
import { installRemoteUserDataAutoSync, resetRemoteUserDataSync, syncRemoteUserData } from "@/services/user-data-sync";
export async function applyUserSession(payload: AuthSessionPayload) {
const previousUserId = useUserStore.getState().user?.id || "";
const nextUserId = payload.user?.id || "";
useUserStore.getState().setHydrated(false);
try {
// Query key 不携带用户 ID;身份变化时必须取消并清空旧账号请求,避免跨账号复用内存数据。
if (previousUserId !== nextUserId) appQueryClient.clear();
resetRemoteUserDataSync();
await flushCanvasStorePersistence();
setActiveUserScope(payload.user?.id);
const [persistedCanvas, persistedAssets] = await Promise.all([
localForageStorage.getItem(CANVAS_STORE_KEY),
localForageStorage.getItem(ASSET_STORE_KEY),
]);
const persistedConfig = scopedLocalStorage.getItem(CONFIG_STORE_KEY);
useUserStore.getState().setUser(payload.user);
useUserStore.getState().setRuntimeLimits(payload.runtimeLimits);
useUserStore.getState().setDrawingEngine(payload.drawingEngine);
useUserStore.getState().setFeatures(payload.features);
await Promise.all([useCanvasStore.persist.rehydrate(), useAssetStore.persist.rehydrate(), useConfigStore.persist.rehydrate()]);
// Zustand 在目标 scope 没有快照时会保留旧内存,必须显式恢复该 scope 的空状态。
if (!persistedCanvas) useCanvasStore.setState({ projects: [] });
if (!persistedAssets) useAssetStore.setState({ assets: [] });
if (!persistedConfig) {
// 只有首次配置缺失时才生成能力推荐;已有配置中的空数组代表用户明确清空。
const initialSystemConfig = {
...defaultConfig,
channels: payload.systemChannels || [],
imageModels: undefined,
videoModels: undefined,
textModels: undefined,
audioModels: undefined,
};
useConfigStore.getState().replaceConfig(normalizeConfigSnapshot({ config: initialSystemConfig }).config);
} else {
useConfigStore.getState().mergeSystemChannels(payload.systemChannels || []);
}
installRemoteUserDataAutoSync();
if (payload.user?.id) await syncRemoteUserData(payload.user.id);
else resetRemoteUserDataSync();
} finally {
useUserStore.getState().setHydrated(true);
}
}
export async function refreshSystemChannels() {
// 系统模型由后端统一维护,后台变更后只刷新这一层,避免重跑整套用户数据同步。
const payload = await getSystemChannels();
useConfigStore.getState().mergeSystemChannels(payload.channels || []);
}
export async function refreshFeatureAvailability() {
const payload = await getFeatureAvailability();
useUserStore.getState().setFeatures(payload.features);
return payload.features;
}