UNPKG

bb-inspired

Version:

Core library for BB-inspired NestJS backend

398 lines 16 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var AuthSyncService_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.AuthSyncService = void 0; const common_1 = require("@nestjs/common"); const database_service_1 = require("../../database/database.service"); const messaging_service_1 = require("../../messaging/messaging.service"); const cache_service_1 = require("../../cache/cache.service"); const logger_1 = require("../../../utils/logger"); let AuthSyncService = AuthSyncService_1 = class AuthSyncService { constructor(options, databaseService, messagingService, cacheService) { this.options = options; this.databaseService = databaseService; this.messagingService = messagingService; this.cacheService = cacheService; this.logger = new logger_1.AppLogger(AuthSyncService_1.name); this.isSyncing = false; } onModuleInit() { var _a; if ((_a = this.options.synchronization) === null || _a === void 0 ? void 0 : _a.enabled) { this.logger.log(`Auth synchronization enabled with strategy: ${this.options.synchronization.strategy}`); if (this.options.synchronization.strategy === 'polling') { this.setupPolling(); } else if (this.options.synchronization.strategy === 'events') { this.setupEventListeners(); } } } setupPolling() { const interval = this.options.synchronization.interval || 60000; this.logger.log(`Setting up auth data polling with interval: ${interval}ms`); this.syncInterval = setInterval(() => { this.syncAuthData().catch(error => { this.logger.error(`Auth sync error: ${error.message}`, error.stack); }); }, interval); } setupEventListeners() { if (!this.messagingService) { this.logger.warn('Cannot set up event listeners: MessagingService not provided'); return; } this.logger.log('Setting up auth event listeners'); const authEvents = [ 'auth.user.created', 'auth.user.updated', 'auth.user.deleted', 'auth.role.changed', 'auth.permission.changed', 'auth.logout', 'auth.token.revoked', ]; authEvents.forEach(eventName => { this.messagingService.subscribe(eventName, async (data) => { this.logger.verbose(`Received auth event: ${eventName}`, { metadata: data }); switch (eventName) { case 'auth.user.created': case 'auth.user.updated': await this.syncUser(data.userId); break; case 'auth.user.deleted': await this.removeUser(data.userId); break; case 'auth.role.changed': await this.syncRoles(data.userId); break; case 'auth.permission.changed': await this.syncPermissions(data.userId); break; case 'auth.token.revoked': await this.invalidateToken(data.token); break; default: await this.syncAuthData(data); } }); }); this.logger.log(`Subscribed to ${authEvents.length} auth events`); } async syncAuthData(data) { if (this.isSyncing) { return; } this.isSyncing = true; try { this.logger.log('Starting auth data synchronization'); if (!this.databaseService) { this.logger.warn('Cannot sync auth data: DatabaseService not provided'); return; } if (data === null || data === void 0 ? void 0 : data.userId) { await this.syncUser(data.userId); } else if (data === null || data === void 0 ? void 0 : data.roleId) { await this.syncRole(data.roleId); } else { await this.syncAllAuthData(); } this.logger.log('Auth data synchronization completed'); } catch (error) { this.logger.error(`Auth data synchronization failed: ${error.message}`, error.stack); } finally { this.isSyncing = false; } } async syncAllAuthData() { await Promise.all([ this.syncAllUsers(), this.syncAllRoles(), this.syncAllPermissions(), ]); } async syncUser(userId) { try { const user = await this.databaseService.executeQuery('user', 'findUnique', { where: { id: userId }, include: { roles: true, permissions: true, }, }, { source: 'primary' }); if (!user) { this.logger.warn(`User sync failed: User with ID ${userId} not found`); return; } await this.databaseService.executeQuery('user', 'upsert', { where: { id: userId }, update: { ...user, roles: undefined, permissions: undefined, }, create: { ...user, roles: undefined, permissions: undefined, }, }, { source: 'secondary' }); await this.syncRoles(userId); await this.syncPermissions(userId); this.logger.verbose(`User synchronized: ${userId}`); } catch (error) { this.logger.error(`Error synchronizing user ${userId}: ${error.message}`, error.stack); } } async removeUser(userId) { try { await this.databaseService.executeQuery('user', 'delete', { where: { id: userId }, }, { source: 'secondary' }); this.logger.verbose(`User removed from secondary database: ${userId}`); } catch (error) { this.logger.error(`Error removing user ${userId}: ${error.message}`, error.stack); } } async syncRoles(userId) { try { const userRoles = await this.databaseService.executeQuery('userRole', 'findMany', { where: { userId }, include: { role: true }, }, { source: 'primary' }); await this.databaseService.executeQuery('userRole', 'deleteMany', { where: { userId }, }, { source: 'secondary' }); for (const userRole of userRoles) { await this.syncRole(userRole.roleId); await this.databaseService.executeQuery('userRole', 'create', { data: { userId, roleId: userRole.roleId, }, }, { source: 'secondary' }); } this.logger.verbose(`Roles synchronized for user: ${userId}`); } catch (error) { this.logger.error(`Error synchronizing roles for user ${userId}: ${error.message}`, error.stack); } } async syncPermissions(userId) { try { const userPermissions = await this.databaseService.executeQuery('userPermission', 'findMany', { where: { userId }, include: { permission: true }, }, { source: 'primary' }); const userRoles = await this.databaseService.executeQuery('userRole', 'findMany', { where: { userId }, include: { role: { include: { rolePermissions: { include: { permission: true }, }, }, }, }, }, { source: 'primary' }); await this.databaseService.executeQuery('userPermission', 'deleteMany', { where: { userId }, }, { source: 'secondary' }); for (const userPermission of userPermissions) { await this.databaseService.executeQuery('userPermission', 'create', { data: { userId, permissionId: userPermission.permissionId, }, }, { source: 'secondary' }); } this.logger.verbose(`Permissions synchronized for user: ${userId}`); } catch (error) { this.logger.error(`Error synchronizing permissions for user ${userId}: ${error.message}`, error.stack); } } async syncRole(roleId) { try { const role = await this.databaseService.executeQuery('role', 'findUnique', { where: { id: roleId }, include: { permissions: true, }, }, { source: 'primary' }); if (!role) { this.logger.warn(`Role sync failed: Role with ID ${roleId} not found`); return; } await this.databaseService.executeQuery('role', 'upsert', { where: { id: roleId }, update: { ...role, permissions: undefined, }, create: { ...role, permissions: undefined, }, }, { source: 'secondary' }); this.logger.verbose(`Role synchronized: ${roleId}`); } catch (error) { this.logger.error(`Error synchronizing role ${roleId}: ${error.message}`, error.stack); } } async syncUsersWithRole(roleId) { try { const usersWithRole = await this.databaseService.executeQuery('userRole', 'findMany', { where: { roleId }, include: { user: true }, }, { source: 'primary' }); for (const userRole of usersWithRole) { await this.syncUser(userRole.userId); } this.logger.verbose(`Users with role ${roleId} synchronized`); } catch (error) { this.logger.error(`Error synchronizing users with role ${roleId}: ${error.message}`, error.stack); } } async syncAllUsers() { try { const users = await this.databaseService.executeQuery('user', 'findMany', { include: { roles: true, permissions: true, }, }, { source: 'primary' }); for (const user of users) { await this.databaseService.executeQuery('user', 'upsert', { where: { id: user.id }, update: { ...user, roles: undefined, permissions: undefined, }, create: { ...user, roles: undefined, permissions: undefined, }, }, { source: 'secondary' }); } for (const user of users) { await this.syncRoles(user.id); await this.syncPermissions(user.id); } this.logger.verbose(`All users synchronized (${users.length} users)`); } catch (error) { this.logger.error(`Error synchronizing all users: ${error.message}`, error.stack); } } async syncAllRoles() { try { const roles = await this.databaseService.executeQuery('role', 'findMany', { include: { permissions: true, users: true, }, }, { source: 'primary' }); for (const role of roles) { await this.databaseService.executeQuery('role', 'upsert', { where: { id: role.id }, update: { ...role, permissions: undefined, users: undefined, }, create: { ...role, permissions: undefined, users: undefined, }, }, { source: 'secondary' }); } this.logger.verbose(`All roles synchronized (${roles.length} roles)`); } catch (error) { this.logger.error(`Error synchronizing all roles: ${error.message}`, error.stack); } } async syncAllPermissions() { try { const permissions = await this.databaseService.executeQuery('permission', 'findMany', { include: { roles: true, users: true, }, }, { source: 'primary' }); for (const permission of permissions) { await this.databaseService.executeQuery('permission', 'upsert', { where: { id: permission.id }, update: { ...permission, roles: undefined, users: undefined, }, create: { ...permission, roles: undefined, users: undefined, }, }, { source: 'secondary' }); } this.logger.verbose(`All permissions synchronized (${permissions.length} permissions)`); } catch (error) { this.logger.error(`Error synchronizing all permissions: ${error.message}`, error.stack); } } async invalidateToken(token) { if (!this.cacheService) { return; } try { await this.cacheService.delete(`auth:token:${token}`); this.logger.verbose(`Token invalidated in cache`); } catch (error) { this.logger.error(`Error invalidating token: ${error.message}`, error.stack); } } onModuleDestroy() { if (this.syncInterval) { clearInterval(this.syncInterval); } } }; exports.AuthSyncService = AuthSyncService; exports.AuthSyncService = AuthSyncService = AuthSyncService_1 = __decorate([ (0, common_1.Injectable)(), __param(0, (0, common_1.Inject)('AUTH_OPTIONS')), __param(1, (0, common_1.Optional)()), __param(2, (0, common_1.Optional)()), __param(3, (0, common_1.Optional)()), __metadata("design:paramtypes", [Object, database_service_1.DatabaseService, messaging_service_1.MessagingService, cache_service_1.CacheService]) ], AuthSyncService); //# sourceMappingURL=auth-sync.service.js.map