/** * Tipos e interfaces para el servicio de autenticación de Valtech. * Alineados con el backend AuthV2. */ /** * Configuración para el servicio de autenticación. */ export interface ValtechAuthConfig { /** URL base de la API (ej: 'https://api.myvaltech.com') */ apiUrl: string; /** Prefijo para endpoints de auth (default: '/v2/auth') */ authPrefix?: string; /** Prefijo para las claves de localStorage (default: 'valtech_auth_') */ storagePrefix?: string; /** Tiempo antes de expiración para refrescar token en segundos (default: 60) */ refreshBeforeExpiry?: number; /** Habilitar sincronización entre pestañas (default: true) */ enableTabSync?: boolean; /** Ruta de redirección cuando no autenticado (default: '/login') */ loginRoute?: string; /** Ruta de redirección cuando ya autenticado (default: '/') */ homeRoute?: string; /** Ruta para acceso denegado (default: '/unauthorized') */ unauthorizedRoute?: string; /** Habilitar integración con FirebaseService (default: false) */ enableFirebaseIntegration?: boolean; /** Habilitar registro automático de device tokens para push notifications (default: false) */ enableDeviceRegistration?: boolean; /** * AppID de esta app dentro del factory (ej: 'showcase', 'sigify', 'myvaltech'). * Usado por NotificationActionService para decidir si una notificación * apunta a la app actual o requiere handoff cross-app. */ appId?: string; /** * Mapa appId → baseUrl absoluta para handoff cross-app. * Ej: { sigify: 'https://sigify.com', myvaltech: 'https://app.myvaltech.com' } * NotificationActionService usa este map al disparar handoff a otra app. */ appUrls?: Record; /** * Habilitar sincronización reactiva de permisos via Firestore onSnapshot (default: false). * Requiere enableFirebaseIntegration: true. Cuando un admin asigna o revoca un rol, * el frontend actualiza roles/permisos sin recargar la página (~1-3s latencia). * Requiere que el backend tenga SyncRBACToFirestore activo. */ enableFirestoreRBAC?: boolean; } /** * Estado completo de autenticación. */ export interface AuthState { /** Usuario está autenticado */ isAuthenticated: boolean; /** Estado de carga inicial */ isLoading: boolean; /** Token de acceso actual */ accessToken: string | null; /** Token de refresco actual */ refreshToken: string | null; /** ID del usuario */ userId: string | null; /** Email del usuario */ email: string | null; /** Nombre completo del usuario (poblado tras `getProfile()`) */ name?: string | null; /** Username/handle (poblado tras `getProfile()`) */ handle?: string | null; /** URL del avatar (poblado tras `getProfile()`) */ avatarUrl?: string | null; /** Teléfono (poblado tras `getProfile()`) */ phone?: string | null; /** ID de la organización activa */ activeOrg?: string | null; /** Roles del usuario */ roles: string[]; /** Permisos del usuario (formato 'resource:action') */ permissions: string[]; /** Usuario es super admin */ isSuperAdmin: boolean; /** Usuario tiene suscripción premium activa (no ve ads) */ isPremium: boolean; /** Timestamp de expiración del accessToken (ms) */ expiresAt: number | null; /** Error de autenticación (si existe) */ error: AuthError | null; } /** * Información del usuario autenticado. */ export interface AuthUser { userId: string; email: string; name?: string; phone?: string; /** Username/handle del usuario (ej: @victorv) */ handle?: string; /** ID de la organización activa */ activeOrg?: string; /** URL del avatar del usuario */ avatarUrl?: string; roles: string[]; permissions: string[]; isSuperAdmin: boolean; mfaEnabled?: boolean; mfaMethod?: MFAMethod; } /** * Error de autenticación. */ export interface AuthError { code: string; message: string; } /** * Estado inicial de autenticación. */ export declare const INITIAL_AUTH_STATE: AuthState; /** Métodos de MFA soportados */ export type MFAMethod = 'EMAIL' | 'SMS' | 'TOTP'; /** * Estado de MFA pendiente. */ export interface MFAPendingState { required: boolean; mfaToken: string | null; method: MFAMethod | null; } /** * Estado inicial de MFA. */ export declare const INITIAL_MFA_STATE: MFAPendingState; /** * Resultado de setup de MFA. */ export interface MFASetupResult { codeSent: boolean; message: string; } /** * Estado de MFA del usuario. */ export interface MFAStatus { enabled: boolean; method: MFAMethod | null; } /** * Response de setup de TOTP. */ export interface TOTPSetupResponse { operationId: string; /** Secreto TOTP en base32 (para entrada manual) */ secret: string; /** URL para generar QR code (otpauth://...) */ qrCodeUrl: string; /** Códigos de respaldo de un solo uso */ backupCodes: string[]; message: string; } /** * Request para verificar setup de TOTP. */ export interface TOTPVerifySetupRequest { /** Código TOTP de 6 dígitos */ code: string; } /** * Response de verificación de setup TOTP. */ export interface TOTPVerifySetupResponse { operationId: string; enabled: boolean; message: string; } /** * Request para deshabilitar TOTP. */ export interface TOTPDisableRequest { password: string; } /** * Response de deshabilitar TOTP. */ export interface TOTPDisableResponse { operationId: string; disabled: boolean; message: string; } /** * Response de regenerar códigos de respaldo. */ export interface RegenerateBackupCodesResponse { operationId: string; backupCodes: string[]; message: string; } /** * Response de cantidad de códigos de respaldo. */ export interface BackupCodesCountResponse { operationId: string; count: number; } /** * Request para signup (registro). */ export interface SignupRequest { email: string; password: string; name: string; phone?: string; } /** * Response de signup (registro). */ export interface SignupResponse { operationId: string; userId: string; message: string; } /** * Request para verificar email. */ export interface VerifyEmailRequest { email: string; code: string; } /** * Response de verificación de email. * Si es exitoso, incluye tokens para auto-login. */ export interface VerifyEmailResponse { operationId: string; verified: boolean; accessToken?: string; refreshToken?: string; firebaseToken?: string; expiresIn?: number; tokenType?: string; } /** * Request para reenviar código de verificación. */ export interface ResendCodeRequest { email: string; type: 'EMAIL_VERIFY' | 'PASSWORD_RESET'; } /** * Response de reenvío de código. */ export interface ResendCodeResponse { operationId: string; sent: boolean; } /** * Request para signin. */ export interface SigninRequest { email: string; password: string; /** Plataforma del dispositivo (para detección de nuevo dispositivo) */ platform?: DevicePlatform; /** Navegador (solo web) */ browser?: string; /** Sistema operativo */ os?: string; /** Nombre amigable del dispositivo */ deviceName?: string; } /** * Response de signin. */ export interface SigninResponse { operationId: string; accessToken?: string; refreshToken?: string; firebaseToken?: string; expiresIn?: number; tokenType?: string; mfaRequired?: boolean; mfaToken?: string; mfaMethod?: MFAMethod; roles?: string[]; permissions?: string[]; /** Indica si el login fue desde un dispositivo nuevo/no reconocido */ isNewDevice?: boolean; /** ID del dispositivo usado para el login */ deviceId?: string; /** Idioma preferido del usuario (para sincronizar con i18n) */ language?: string; } /** * Request para verificar MFA. */ export interface MFAVerifyRequest { mfaToken: string; code: string; } /** * Response de verificar MFA. */ export interface MFAVerifyResponse { operationId: string; accessToken: string; refreshToken: string; firebaseToken?: string; expiresIn: number; tokenType: string; roles?: string[]; permissions?: string[]; /** Idioma preferido del usuario (para sincronizar con i18n) */ language?: string; } /** * Request para refrescar token. */ export interface RefreshRequest { refreshToken: string; } /** * Response de refrescar token. * Implementa token rotation: cada refresh genera un nuevo refresh token. */ export interface RefreshResponse { operationId: string; accessToken: string; refreshToken: string; expiresIn: number; firebaseToken?: string; roles?: string[]; permissions?: string[]; } /** * Request para logout. */ export interface LogoutRequest { refreshToken: string; } /** * Response de logout. */ export interface LogoutResponse { operationId: string; success: boolean; } /** * Response de obtener permisos. */ export interface GetPermissionsResponse { operationId: string; roles: string[]; permissions: string[]; isSuperAdmin: boolean; } /** * Request para setup de MFA. */ export interface MFASetupRequest { method: MFAMethod; phone?: string; } /** * Response de setup de MFA. */ export interface MFASetupResponse { operationId: string; codeSent: boolean; message: string; } /** * Request para confirmar MFA. */ export interface MFAConfirmRequest { code: string; } /** * Response de confirmar MFA. */ export interface MFAConfirmResponse { operationId: string; mfaEnabled: boolean; method: MFAMethod; } /** * Request para deshabilitar MFA. */ /** * Acepta `password` (cuenta con contraseña) o `mfaCode` (cuenta OAuth-only * con TOTP que prueba posesión del segundo factor). Uno requerido. */ export interface MFADisableRequest { password?: string; mfaCode?: string; } /** * Response de deshabilitar MFA. */ export interface MFADisableResponse { operationId: string; mfaDisabled: boolean; } /** * Request para iniciar recuperación de contraseña. */ export interface ForgotPasswordRequest { email: string; } /** * Response de forgot password (siempre igual por seguridad). */ export interface ForgotPasswordResponse { operationId: string; message: string; } /** * Request para resetear contraseña con código. */ export interface ResetPasswordRequest { email: string; code: string; newPassword: string; } /** * Response de reset password. */ export interface ResetPasswordResponse { operationId: string; success: boolean; } /** * Request para cambiar contraseña (usuario autenticado). */ export interface ChangePasswordRequest { currentPassword: string; newPassword: string; } /** * Response de cambio de contraseña. */ export interface ChangePasswordResponse { operationId: string; success: boolean; } /** * Request para eliminar cuenta. * Usuarios con contraseña: enviar `password`. * Usuarios OAuth sin contraseña: enviar `code` (obtenido via sendDeleteAccountCode). */ export interface DeleteAccountRequest { password?: string; code?: string; } /** * Response de enviar código de confirmación de eliminación de cuenta. */ export interface SendDeleteAccountCodeResponse { operationId: string; } /** * Response de eliminar cuenta. */ export interface DeleteAccountResponse { operationId: string; deleted: boolean; message: string; } /** * Response de obtener perfil del usuario. */ export interface GetProfileResponse { operationId: string; userId: string; email: string; name: string; phone?: string; /** Username/handle del usuario */ handle?: string; /** URL del avatar del usuario */ avatarUrl?: string; emailVerified: boolean; phoneVerified: boolean; mfaEnabled: boolean; mfaMethod?: MFAMethod; /** True si la cuenta tiene contraseña seteada (false para OAuth-only sin password). */ hasPassword?: boolean; createdAt: string; updatedAt: string; } /** * Request para actualizar perfil. */ export interface UpdateProfileRequest { name?: string; phone?: string; } /** * Response de actualizar perfil. */ export interface UpdateProfileResponse { operationId: string; updated: boolean; } /** * Request para actualizar avatar del usuario. */ export interface UpdateAvatarRequest { /** URL del avatar en Firebase Storage */ avatarUrl: string; /** URL del thumbnail (opcional) */ avatarThumbnail?: string; } /** * Response de actualizar avatar. */ export interface UpdateAvatarResponse { operationId: string; avatarUrl: string; avatarThumbnail?: string; updatedAt: string; } /** * Request para cambiar de organización activa. */ export interface SwitchOrgRequest { organizationId: string; } /** * Response de cambio de organización. */ export interface SwitchOrgResponse { operationId: string; firebaseToken: string; activeOrg: string; /** Nuevo JWT con activeOrg actualizado. El FE lo almacena para que el * bootstrap post-refresh use la org correcta en vez del JWT cacheado. */ accessToken?: string; expiresIn?: number; } /** Tipos de eventos de sincronización entre pestañas */ export type AuthSyncEventType = 'LOGIN' | 'LOGOUT' | 'TOKEN_REFRESH' | 'PERMISSIONS_UPDATE' | 'ORG_SWITCH'; /** * Evento de sincronización entre pestañas. */ export interface AuthSyncEvent { type: AuthSyncEventType; timestamp: number; payload?: { accessToken?: string; refreshToken?: string; expiresAt?: number; activeOrg?: string; }; } /** * Claims del JWT de acceso. */ export interface JWTClaims { /** User ID */ uid: string; /** Email */ email: string; /** Session ID */ sid?: string; /** Usuario tiene suscripción premium activa */ premium?: boolean; /** Active organization ID (JWT claim "org") */ org?: string; /** Issued at */ iat: number; /** Expiration */ exp: number; } /** * Datos persistidos en storage. */ export interface StoredAuthState { accessToken: string; refreshToken: string; roles: string[]; permissions: string[]; isSuperAdmin: boolean; isPremium?: boolean; expiresAt?: number; } /** * Plataformas soportadas para push notifications. */ export type DevicePlatform = 'web' | 'ios' | 'android'; /** * Request para registrar un dispositivo. */ export interface RegisterDeviceRequest { /** FCM token del dispositivo */ token: string; /** Plataforma del dispositivo */ platform: DevicePlatform; /** Navegador (solo web) */ browser?: string; /** Sistema operativo */ os?: string; /** Versión de la aplicación */ appVersion?: string; /** Nombre amigable del dispositivo */ name?: string; /** Metadata adicional */ metadata?: Record; } /** * Response de registro de dispositivo. */ export interface RegisterDeviceResponse { operationId: string; device: { deviceId: string; token: string; platform: DevicePlatform; browser?: string; os?: string; lastActive: string; createdAt: string; }; /** true si es un nuevo dispositivo, false si se actualizó uno existente */ isNew: boolean; } /** * Resultado de habilitar notificaciones. */ export interface EnableNotificationsResult { /** Si se otorgaron los permisos */ granted: boolean; /** FCM token (solo si granted=true) */ token?: string; /** Si el dispositivo fue registrado en el backend */ registered?: boolean; } /** * Estado de permisos de notificación. */ export type NotificationPermissionState = 'granted' | 'denied' | 'default' | 'unsupported'; /** * Resultado del registro manual de dispositivo. */ export interface RegisterDeviceResult { /** Si el dispositivo fue registrado exitosamente */ registered: boolean; /** ID del dispositivo (solo si registered=true) */ deviceId?: string; /** FCM token usado para el registro */ token?: string; /** Mensaje de error (solo si registered=false) */ error?: string; } /** * Estados posibles de un dispositivo. */ export type DeviceStatus = 'active' | 'pending_approval' | 'blocked'; /** * Información completa de un dispositivo registrado. */ export interface DeviceInfo { /** ID único del dispositivo */ deviceId: string; /** Plataforma del dispositivo */ platform: DevicePlatform; /** Navegador (solo web) */ browser?: string; /** Sistema operativo */ os?: string; /** Nombre amigable del dispositivo */ name?: string; /** Estado actual del dispositivo */ status: DeviceStatus; /** Dirección IP del último acceso */ ipAddress?: string; /** Ubicación geográfica aproximada */ location?: string; /** Última actividad */ lastActive: string; /** Fecha de creación/registro */ createdAt: string; /** Fecha de aprobación (si aplica) */ approvedAt?: string; /** Fecha de bloqueo (si aplica) */ blockedAt?: string; } /** * Response de listar dispositivos del usuario. */ export interface ListDevicesResponse { operationId: string; devices: DeviceInfo[]; } /** * Response de acción sobre dispositivo (block/approve/delete). */ export interface DeviceActionResult { operationId: string; success: boolean; message: string; } /** * Información de una sesión activa. */ export interface SessionInfo { /** ID único de la sesión */ sessionId: string; /** ID del dispositivo asociado (si existe) */ deviceId?: string; /** Información del dispositivo (User-Agent) */ deviceInfo?: string; /** Dirección IP de la sesión */ ip?: string; /** Ubicación geográfica aproximada */ location?: string; /** Fecha de creación de la sesión */ createdAt: string; /** Fecha de expiración de la sesión */ expiresAt: string; /** Indica si es la sesión actual del usuario */ isCurrent: boolean; } /** * Response de listar sesiones activas. */ export interface ListSessionsResponse { operationId: string; sessions: SessionInfo[]; } /** * Response de revocar sesión(es). */ export interface RevokeSessionsResponse { operationId: string; success: boolean; /** Número de sesiones revocadas */ sessionsRevoked: number; } /** * Request para ejecutar acción de dispositivo desde email. * El token viene en la URL del email de alerta. */ export interface DeviceActionRequest { /** Token JWT de acción (24h, un solo uso) */ token: string; } /** * Response de ejecutar acción de dispositivo. */ export interface DeviceActionResponse { operationId: string; /** Si la acción fue ejecutada exitosamente */ success: boolean; /** Acción ejecutada (refuse, approve, block) */ action: string; /** ID del dispositivo afectado */ deviceId: string; /** Número de sesiones revocadas (si action=refuse/block) */ sessionsRevoked?: number; /** Mensaje descriptivo */ message: string; } /** * Response de validar token de acción (sin ejecutar). * Usado para mostrar confirmación al usuario antes de ejecutar. */ export interface ValidateActionResponse { operationId: string; /** Si el token es válido */ valid: boolean; /** Tipo de acción (device:refuse, device:approve, etc.) */ actionType?: string; /** Tipo de recurso objetivo (device, document, etc.) */ targetType?: string; /** ID del recurso objetivo */ targetId?: string; /** Mensaje de error (si valid=false) */ message?: string; } /** * Proveedores OAuth soportados. */ export type OAuthProvider = 'google' | 'apple' | 'microsoft'; /** * Resultado exitoso de flujo OAuth. */ export interface OAuthResult { /** Token de acceso JWT */ accessToken: string; /** Token de refresco */ refreshToken: string; /** Token de Firebase (si está habilitado) */ firebaseToken?: string; /** Tiempo de expiración en segundos */ expiresIn: number; /** Roles del usuario */ roles?: string[]; /** Permisos del usuario */ permissions?: string[]; /** Indica si es un usuario nuevo (recién creado) */ isNewUser?: boolean; /** Indica si la cuenta fue vinculada a usuario existente */ linked?: boolean; /** * `true` si el backend exige verificación MFA tras el OAuth. En ese caso * NO vienen `accessToken`/`refreshToken` — el flujo continúa con `mfaToken`. */ mfaRequired?: boolean; /** Token temporal para el challenge MFA (presente si `mfaRequired`). */ mfaToken?: string; /** Método MFA configurado por el usuario (presente si `mfaRequired`). */ mfaMethod?: MFAMethod; } /** * Error de OAuth. */ export interface OAuthError { /** Código de error */ code: string; /** Mensaje descriptivo */ message: string; } /** * Datos enviados desde popup callback via postMessage. */ export interface OAuthCallbackData { /** Tipo de mensaje */ type: 'oauth-callback'; /** Tokens (si éxito) */ tokens?: OAuthResult; /** Error (si falló) */ error?: OAuthError; } /** * Proveedor OAuth vinculado al usuario. */ export interface LinkedProvider { /** Nombre del proveedor */ provider: OAuthProvider; /** Email asociado al proveedor */ email: string; /** Nombre del usuario en el proveedor */ name?: string; /** URL de imagen de perfil */ picture?: string; /** Fecha de vinculación */ linkedAt: string; /** Última vez que se usó para login */ lastUsedAt?: string; } /** * Response de verificar si tiene contraseña. */ export interface HasPasswordResponse { operationId: string; hasPassword: boolean; } /** * Request para actualizar handle (@username). */ export interface UpdateHandleRequest { handle: string; } /** * Response de actualizar handle. */ export interface UpdateHandleResponse { operationId: string; handle: string; updated: boolean; } /** * Request para verificar disponibilidad de handle. */ export interface CheckHandleRequest { handle: string; } /** * Response de verificar disponibilidad de handle. */ export interface CheckHandleResponse { operationId: string; handle: string; available: boolean; } /** * Response de obtener proveedores OAuth vinculados. */ export interface GetLinkedProvidersResponse { operationId: string; providers: LinkedProvider[]; } /** * Request para desvincular un proveedor OAuth. */ export interface UnlinkProviderRequest { provider: OAuthProvider; } /** * Response de desvincular proveedor. */ export interface UnlinkProviderResponse { operationId: string; unlinked: boolean; } export interface InitiateEmailChangeRequest { currentPassword: string; newEmail: string; } export interface InitiateEmailChangeResponse { operationId: string; pendingEmail: string; requestLocation: string; } export interface ConfirmEmailChangeStep1Request { code: string; } export interface ConfirmEmailChangeStep1Response { operationId: string; verified: boolean; } export interface ConfirmEmailChangeStep2Request { code: string; } export interface ConfirmEmailChangeStep2Response { operationId: string; success: boolean; newEmail: string; }