UNPKG

@oxyhq/services

Version:

Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀

191 lines (170 loc) • 6.64 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.deduplicateSessions = deduplicateSessions; exports.deduplicateSessionsByUserId = deduplicateSessionsByUserId; exports.mergeSessions = mergeSessions; exports.normalizeAndSortSessions = normalizeAndSortSessions; exports.normalizeSession = normalizeSession; exports.sessionsArraysEqual = sessionsArraysEqual; exports.sessionsEqual = sessionsEqual; exports.sortSessions = sortSessions; /** * Session management utilities * * Provides consistent session normalization, deduplication, and sorting * to ensure sessions are always displayed in a predictable order. */ /** * Normalize a session to ensure all required fields are present */ function normalizeSession(session) { const now = new Date().toISOString(); return { sessionId: session.sessionId, deviceId: session.deviceId || '', expiresAt: session.expiresAt || now, lastActive: session.lastActive || now, userId: session.userId || '' }; } /** * Compare two sessions for equality */ function sessionsEqual(a, b) { return a.sessionId === b.sessionId; } /** * Sort sessions by lastActive (most recent first), then by sessionId for stability */ function sortSessions(sessions) { return [...sessions].sort((a, b) => { // Sort by lastActive descending (most recent first) const timeA = new Date(a.lastActive).getTime(); const timeB = new Date(b.lastActive).getTime(); if (timeA !== timeB) { return timeB - timeA; // Descending order } // If lastActive is the same, sort by sessionId for stability return a.sessionId.localeCompare(b.sessionId); }); } /** * Deduplicate sessions by sessionId, keeping the most recent version */ function deduplicateSessions(sessions) { const sessionMap = new Map(); for (const session of sessions) { const existing = sessionMap.get(session.sessionId); if (!existing) { sessionMap.set(session.sessionId, session); } else { // Keep the one with more recent lastActive const existingTime = new Date(existing.lastActive).getTime(); const currentTime = new Date(session.lastActive).getTime(); if (currentTime > existingTime) { sessionMap.set(session.sessionId, session); } } } return Array.from(sessionMap.values()); } /** * Deduplicate sessions by userId, keeping only one session per user * Priority: 1) Active session (if provided), 2) Most recent session * This prevents showing duplicate accounts for the same user */ function deduplicateSessionsByUserId(sessions, activeSessionId) { if (!sessions.length) return []; const userSessionMap = new Map(); for (const session of sessions) { if (!session.userId) continue; // Skip sessions without userId const existing = userSessionMap.get(session.userId); if (!existing) { userSessionMap.set(session.userId, session); } else { // Prioritize active session const isCurrentActive = activeSessionId && session.sessionId === activeSessionId; const isExistingActive = activeSessionId && existing.sessionId === activeSessionId; if (isCurrentActive && !isExistingActive) { userSessionMap.set(session.userId, session); } else if (!isCurrentActive && isExistingActive) { // Keep existing (active) session continue; } else { // Neither is active, keep the one with more recent lastActive const existingTime = new Date(existing.lastActive).getTime(); const currentTime = new Date(session.lastActive).getTime(); if (currentTime > existingTime) { userSessionMap.set(session.userId, session); } } } } return Array.from(userSessionMap.values()); } /** * Normalize, deduplicate, and sort sessions * This ensures consistent session ordering across the application * * @param sessions - Array of sessions to normalize * @param activeSessionId - Optional active session ID to prioritize * @param deduplicateByUserId - If true, deduplicate by userId (one account per user). Default: true */ function normalizeAndSortSessions(sessions, activeSessionId, deduplicateByUserId = true) { if (!sessions.length) return []; // Normalize all sessions const normalized = sessions.map(normalizeSession); // First deduplicate by sessionId (exact duplicates) const deduplicatedBySessionId = deduplicateSessions(normalized); // Then deduplicate by userId if requested (one account per user) const finalSessions = deduplicateByUserId ? deduplicateSessionsByUserId(deduplicatedBySessionId, activeSessionId) : deduplicatedBySessionId; // Sort consistently return sortSessions(finalSessions); } /** * Merge two session arrays, prioritizing newer data * Returns normalized, deduplicated, and sorted sessions * * @param existing - Existing sessions array * @param incoming - New sessions to merge in * @param activeSessionId - Optional active session ID to prioritize * @param deduplicateByUserId - If true, deduplicate by userId (one account per user). Default: true */ function mergeSessions(existing, incoming, activeSessionId, deduplicateByUserId = true) { if (!existing.length && !incoming.length) return []; if (!existing.length) return normalizeAndSortSessions(incoming, activeSessionId, deduplicateByUserId); if (!incoming.length) return normalizeAndSortSessions(existing, activeSessionId, deduplicateByUserId); // Normalize both arrays const normalizedExisting = existing.map(normalizeSession); const normalizedIncoming = incoming.map(normalizeSession); // Create a map with existing sessions (by sessionId) const sessionMap = new Map(); // Add existing sessions first for (const session of normalizedExisting) { sessionMap.set(session.sessionId, session); } // Merge incoming sessions - backend data always replaces existing for (const session of normalizedIncoming) { sessionMap.set(session.sessionId, session); } // Convert to array const merged = Array.from(sessionMap.values()); // Apply userId deduplication if requested const finalSessions = deduplicateByUserId ? deduplicateSessionsByUserId(merged, activeSessionId) : merged; // Sort consistently return sortSessions(finalSessions); } /** * Check if two session arrays are equal (same sessionIds in same order) */ function sessionsArraysEqual(a, b) { if (a.length !== b.length) { return false; } const sortedA = sortSessions(a); const sortedB = sortSessions(b); return sortedA.every((session, index) => sessionsEqual(session, sortedB[index])); } //# sourceMappingURL=sessionUtils.js.map