@pagamio/frontend-commons-lib
Version:
Pagamio library for Frontend reusable components like the form engine and table container
99 lines (98 loc) • 3.73 kB
JavaScript
/**
* @fileoverview Logout service that handles cleanup operations during user logout
*/
import { removeLocalStorageItems } from '../../shared';
import { TokenManager } from '../utils';
const defaultLogoutOptions = {
clearStorage: true,
invalidateSession: true,
logoutEndpoint: '/api/auth/logout',
storageKeys: ['user', 'rememberMe'],
};
export class LogoutService {
tokenManager;
options;
baseUrl;
constructor(config) {
this.baseUrl = config.baseUrl;
this.tokenManager = new TokenManager({
baseUrl: this.baseUrl,
refreshEndpoint: '/auth/refresh', // Default refresh endpoint
});
this.options = {
...defaultLogoutOptions,
logoutEndpoint: config.logoutEndpoint ?? defaultLogoutOptions.logoutEndpoint,
storageKeys: config.storageKeys ?? defaultLogoutOptions.storageKeys,
};
}
async logout(options) {
const currentOptions = { ...this.options, ...options };
const { clearStorage, invalidateSession, logoutEndpoint, storageKeys, onLogoutSuccess, onLogoutError, customCleanup, } = currentOptions;
try {
const cleanupTasks = [];
// Clear tokens
this.tokenManager.clearAllTokens();
// Clear localStorage
if (clearStorage && storageKeys?.length) {
removeLocalStorageItems(storageKeys);
}
// Invalidate server session
if (invalidateSession && logoutEndpoint) {
const { token } = this.tokenManager.getAccessToken();
if (token) {
cleanupTasks.push(this.invalidateServerSession(logoutEndpoint, token));
}
}
// Run custom cleanup if provided
if (customCleanup) {
const cleanup = customCleanup();
if (cleanup instanceof Promise) {
cleanupTasks.push(cleanup);
}
}
// Clear browser cache
cleanupTasks.push(this.clearBrowserCache());
await Promise.all(cleanupTasks);
onLogoutSuccess?.();
return true;
}
catch (error) {
const logoutError = error instanceof Error ? error : new Error('Logout failed');
onLogoutError?.(logoutError);
throw logoutError;
}
}
async invalidateServerSession(endpoint, token) {
const fullEndpoint = endpoint.startsWith('http') ? endpoint : `${this.baseUrl}${endpoint}`;
const response = await fetch(fullEndpoint, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
});
if (!response.ok) {
throw new Error(`Failed to invalidate session: ${response.statusText}`);
}
}
async clearBrowserCache() {
if (typeof window === 'undefined')
return;
// Clear service worker registrations
if ('serviceWorker' in navigator) {
const registrations = await navigator.serviceWorker.getRegistrations();
await Promise.all(registrations.map((registration) => registration.unregister()));
}
// Clear browser cache
if ('caches' in window) {
const keys = await caches.keys();
await Promise.all(keys.map((key) => caches.delete(key)));
}
}
}
// Create default instance with baseUrl from window.location.origin
const createLogoutService = (config) => {
return new LogoutService(config);
};
// Export the create function and types
export { createLogoutService };