import { _clearToken, setUserId as setCommonUserId, getUserId as getCommonUserId, XuqmSDK as CommonXuqmSDK } from '@xuqm/rn-common' import { ImSDK } from '@xuqm/rn-im' import { PushSDK } from '@xuqm/rn-push' import type { UserProfile } from '@xuqm/rn-im' export interface UnifiedLoginRefreshResult { userSig: string expiresAt?: number } export interface UnifiedLoginOptions { userId: string userSig: string profile?: Pick expiresAt?: number refreshUserSig?: () => Promise } type SessionState = UnifiedLoginOptions const REFRESH_GRACE_MS = 5 * 60 * 1000 const REFRESH_RETRY_MS = 30 * 1000 let currentSession: SessionState | null = null let refreshTimer: ReturnType | null = null let refreshInFlight = false function clearRefreshTimer(): void { if (refreshTimer) { clearTimeout(refreshTimer) refreshTimer = null } } async function applyLoginSession(session: SessionState): Promise { clearRefreshTimer() setCommonUserId(session.userId) try { await ImSDK.loginWithUserSig(session.userId, session.userSig) } catch (error) { setCommonUserId(null) currentSession = null throw error } currentSession = session try { await PushSDK.initialize(session.userId) } catch (error) { void error } scheduleRefresh() } async function refreshSession(): Promise { const session = currentSession if (refreshInFlight || !session?.refreshUserSig) return refreshInFlight = true try { const refreshed = await session.refreshUserSig() if (currentSession !== session) return await applyLoginSession({ ...session, userSig: refreshed.userSig, expiresAt: refreshed.expiresAt ?? session.expiresAt, }) } catch (error) { clearRefreshTimer() refreshTimer = setTimeout(() => { void refreshSession() }, REFRESH_RETRY_MS) if (CommonXuqmSDK.getUserId() && process.env.NODE_ENV !== 'production') { console.warn('[XuqmSDK] userSig refresh failed, will retry', error) } } finally { refreshInFlight = false } } function scheduleRefresh(): void { clearRefreshTimer() const session = currentSession if (!session?.refreshUserSig || !session.expiresAt) return const delayMs = Math.max(session.expiresAt - Date.now() - REFRESH_GRACE_MS, 0) refreshTimer = setTimeout(() => { void refreshSession() }, delayMs) } async function login(options: UnifiedLoginOptions): Promise { if (currentSession) { await logout() } await applyLoginSession(options) } async function logout(): Promise { clearRefreshTimer() const userId = currentSession?.userId ?? getCommonUserId() currentSession = null refreshInFlight = false setCommonUserId(null) if (userId) { try { await PushSDK.logout(userId) } catch (error) { void error } } ImSDK.disconnect() await _clearToken() } export const XuqmSDK = { ...CommonXuqmSDK, login, logout, }