import { secureSessionStorage, clearMobileSessionStorage, MOBILE_SESSION_STORAGE_KEY } from '@/lib/secureSessionStorage'; import { createMobilePlatformSdk, mobileRuntime } from '@/lib/runtime'; import { createRequestId } from '../../shared/request-id.js'; export interface PlatformAuthUser { id: string; email?: string; role?: string; plan?: string; displayName?: string; } export interface StoredPlatformSession { accessToken: string; refreshToken: string; user: PlatformAuthUser; } class PlatformAuthError extends Error { status?: number; constructor(message: string, status?: number) { super(message); this.name = 'PlatformAuthError'; this.status = status; } } function createPlatformAuthSdk(accessToken: string | null = null) { return createMobilePlatformSdk(() => accessToken); } function normalizeUser(value: any): PlatformAuthUser { return { id: String(value?.id || value?.sub || '').trim(), email: typeof value?.email === 'string' ? value.email : undefined, role: typeof value?.role === 'string' ? value.role : undefined, plan: typeof value?.plan === 'string' ? value.plan : undefined, displayName: typeof value?.displayName === 'string' ? value.displayName : undefined, }; } async function platformRequest( path: string, options?: { method?: string; accessToken?: string; body?: Record; } ): Promise { const sdk = createPlatformAuthSdk(options?.accessToken ?? null); const response = await sdk.fetch(path, { method: options?.method || 'GET', headers: { 'x-request-id': createRequestId('mobile-auth') }, body: options?.body ? JSON.stringify(options.body) : undefined, }); const payload = await response.json().catch(() => ({})); if (!response.ok) { throw new PlatformAuthError( String((payload as { message?: string; error?: string }).message || (payload as { error?: string }).error || `HTTP ${response.status}`), response.status ); } return payload as T; } function isStoredSession(value: unknown): value is StoredPlatformSession { const candidate = value as StoredPlatformSession | null; return Boolean( candidate && typeof candidate.accessToken === 'string' && typeof candidate.refreshToken === 'string' && candidate.user && typeof candidate.user.id === 'string' ); } async function writeSession(session: StoredPlatformSession): Promise { await secureSessionStorage.setItem(MOBILE_SESSION_STORAGE_KEY, JSON.stringify(session)); } export async function persistPlatformSession(session: StoredPlatformSession): Promise { await writeSession(session); } export async function readPlatformSession(): Promise { const raw = await secureSessionStorage.getItem(MOBILE_SESSION_STORAGE_KEY); if (!raw) { return null; } try { const parsed = JSON.parse(raw) as unknown; return isStoredSession(parsed) ? parsed : null; } catch { return null; } } export async function clearPlatformSession(): Promise { await clearMobileSessionStorage(); } export async function getCurrentPlatformUser(accessToken: string): Promise { const me = await platformRequest('/auth/me', { accessToken, }); return normalizeUser(me); } export async function refreshPlatformSession(refreshToken: string): Promise { const refreshed = await platformRequest<{ accessToken: string; refreshToken: string }>('/auth/refresh', { method: 'POST', body: { refreshToken }, }); const user = await getCurrentPlatformUser(refreshed.accessToken); const session: StoredPlatformSession = { accessToken: refreshed.accessToken, refreshToken: refreshed.refreshToken, user, }; await writeSession(session); return session; } export async function syncPlatformSessionFromTokens( accessToken: string, refreshToken: string ): Promise { const user = await getCurrentPlatformUser(accessToken); const session: StoredPlatformSession = { accessToken, refreshToken, user, }; await writeSession(session); return session; } export async function restorePlatformSession(): Promise { const stored = await readPlatformSession(); if (!stored) { return null; } try { const user = await getCurrentPlatformUser(stored.accessToken); const session = { ...stored, user }; await writeSession(session); return session; } catch (error) { if ((error as PlatformAuthError)?.status === 401 || (error as PlatformAuthError)?.status === 403) { try { return await refreshPlatformSession(stored.refreshToken); } catch { await clearPlatformSession(); return null; } } throw error; } } export async function loginPlatformSession(email: string, password: string): Promise { const response = await platformRequest<{ accessToken: string; refreshToken: string; user: PlatformAuthUser; }>('/auth/login', { method: 'POST', body: { email, password, productId: mobileRuntime.productId, }, }); const session: StoredPlatformSession = { accessToken: response.accessToken, refreshToken: response.refreshToken, user: normalizeUser(response.user), }; await writeSession(session); return session; }