valtech-components 2.0.902 → 2.0.904

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,7 +31,7 @@ import { Navigation, Pagination, EffectFade, EffectCube, EffectCoverflow, Effect
31
31
  import { takeUntilDestroyed, toSignal, toObservable } from '@angular/core/rxjs-interop';
32
32
  import { SwUpdate } from '@angular/service-worker';
33
33
  import * as i1$5 from '@angular/fire/firestore';
34
- import { provideFirestore, getFirestore, connectFirestoreEmulator, enableIndexedDbPersistence, doc, getDoc, collection, query as query$1, getDocs, getCountFromServer, limit, docData, collectionData, serverTimestamp, addDoc, setDoc, updateDoc, deleteDoc, writeBatch, arrayUnion, arrayRemove, increment, where, orderBy, startAfter, startAt, endBefore, endAt, Timestamp } from '@angular/fire/firestore';
34
+ import { provideFirestore, getFirestore, connectFirestoreEmulator, enableIndexedDbPersistence, doc, getDoc, collection, query as query$1, getDocs, getCountFromServer, limit, docData, collectionData, serverTimestamp, addDoc, setDoc, updateDoc, deleteDoc, writeBatch, arrayUnion, arrayRemove, increment, where, orderBy, startAfter, startAt, endBefore, endAt, Timestamp, onSnapshot } from '@angular/fire/firestore';
35
35
  import { Analytics, logEvent, setUserId, setUserProperties, provideAnalytics, getAnalytics } from '@angular/fire/analytics';
36
36
  import { provideFirebaseApp, initializeApp } from '@angular/fire/app';
37
37
  import * as i1$6 from '@angular/fire/auth';
@@ -53,7 +53,7 @@ import 'prismjs/components/prism-json';
53
53
  * Current version of valtech-components.
54
54
  * This is automatically updated during the publish process.
55
55
  */
56
- const VERSION = '2.0.902';
56
+ const VERSION = '2.0.904';
57
57
 
58
58
  /**
59
59
  * Servicio para gestionar presets de componentes.
@@ -21912,7 +21912,7 @@ class AuthStorageService {
21912
21912
  constructor(config, platformId) {
21913
21913
  this.config = config;
21914
21914
  this.isBrowser = isPlatformBrowser(platformId);
21915
- const prefix = this.config.storagePrefix || 'valtech_auth_';
21915
+ const prefix = this.config?.storagePrefix || 'valtech_auth_';
21916
21916
  this.keys = {
21917
21917
  ACCESS_TOKEN: `${prefix}access_token`,
21918
21918
  REFRESH_TOKEN: `${prefix}refresh_token`,
@@ -22092,7 +22092,7 @@ class AuthSyncService {
22092
22092
  /** Observable de eventos de sincronización */
22093
22093
  this.onEvent$ = this.eventSubject.asObservable();
22094
22094
  this.isBrowser = isPlatformBrowser(platformId);
22095
- const prefix = this.config.storagePrefix || 'valtech_auth_';
22095
+ const prefix = this.config?.storagePrefix || 'valtech_auth_';
22096
22096
  this.channelName = `${prefix}sync_channel`;
22097
22097
  }
22098
22098
  /**
@@ -22100,7 +22100,7 @@ class AuthSyncService {
22100
22100
  * SSR-noop — sync de pestañas solo aplica en browser.
22101
22101
  */
22102
22102
  start() {
22103
- if (!this.config.enableTabSync || !this.isBrowser) {
22103
+ if (!this.config?.enableTabSync || !this.isBrowser) {
22104
22104
  return;
22105
22105
  }
22106
22106
  // Intentar usar BroadcastChannel API (mejor rendimiento)
@@ -22129,7 +22129,7 @@ class AuthSyncService {
22129
22129
  * Envía un evento a otras pestañas.
22130
22130
  */
22131
22131
  broadcast(event) {
22132
- if (!this.config.enableTabSync || !this.isBrowser) {
22132
+ if (!this.config?.enableTabSync || !this.isBrowser) {
22133
22133
  return;
22134
22134
  }
22135
22135
  const fullEvent = {
@@ -22173,7 +22173,7 @@ class AuthSyncService {
22173
22173
  * Inicializa fallback con storage events.
22174
22174
  */
22175
22175
  initStorageEvents() {
22176
- const storageKey = `${this.config.storagePrefix}sync_event`;
22176
+ const storageKey = `${this.config?.storagePrefix}sync_event`;
22177
22177
  this.storageListener = (event) => {
22178
22178
  if (event.key === storageKey && event.newValue) {
22179
22179
  try {
@@ -22191,7 +22191,7 @@ class AuthSyncService {
22191
22191
  * Envía evento via localStorage (fallback).
22192
22192
  */
22193
22193
  broadcastViaStorage(event) {
22194
- const storageKey = `${this.config.storagePrefix}sync_event`;
22194
+ const storageKey = `${this.config?.storagePrefix}sync_event`;
22195
22195
  try {
22196
22196
  // Escribir y luego limpiar para permitir múltiples eventos del mismo tipo
22197
22197
  localStorage.setItem(storageKey, JSON.stringify(event));
@@ -25273,7 +25273,7 @@ class OAuthService {
25273
25273
  return new Observable(observer => {
25274
25274
  // Construir URL de inicio
25275
25275
  const redirectUri = `${window.location.origin}/auth/oauth/callback`;
25276
- const startUrl = `${this.config.apiUrl}/v2/auth/oauth/${provider}/start?redirect_uri=${encodeURIComponent(redirectUri)}`;
25276
+ const startUrl = `${this.config?.apiUrl}/v2/auth/oauth/${provider}/start?redirect_uri=${encodeURIComponent(redirectUri)}`;
25277
25277
  // Abrir popup centrado
25278
25278
  const width = 500;
25279
25279
  const height = 600;
@@ -25378,7 +25378,7 @@ class OAuthService {
25378
25378
  startLinkFlow(provider) {
25379
25379
  return new Observable(observer => {
25380
25380
  const redirectUri = `${window.location.origin}/auth/oauth/callback`;
25381
- const startUrl = `${this.config.apiUrl}/v2/auth/oauth/link/${provider}/start?redirect_uri=${encodeURIComponent(redirectUri)}`;
25381
+ const startUrl = `${this.config?.apiUrl}/v2/auth/oauth/link/${provider}/start?redirect_uri=${encodeURIComponent(redirectUri)}`;
25382
25382
  const width = 500;
25383
25383
  const height = 600;
25384
25384
  const left = window.screenX + (window.outerWidth - width) / 2;
@@ -25429,7 +25429,7 @@ class OAuthService {
25429
25429
  */
25430
25430
  getLinkedProviders() {
25431
25431
  return this.http
25432
- .get(`${this.config.apiUrl}/v2/auth/oauth/providers`)
25432
+ .get(`${this.config?.apiUrl}/v2/auth/oauth/providers`)
25433
25433
  .pipe(catchError(error => throwError(() => ({
25434
25434
  code: error.error?.code || 'FETCH_ERROR',
25435
25435
  message: error.error?.message || 'Error al obtener proveedores vinculados',
@@ -25440,7 +25440,7 @@ class OAuthService {
25440
25440
  */
25441
25441
  unlinkProvider(provider) {
25442
25442
  return this.http
25443
- .post(`${this.config.apiUrl}/v2/auth/oauth/unlink`, { provider })
25443
+ .post(`${this.config?.apiUrl}/v2/auth/oauth/unlink`, { provider })
25444
25444
  .pipe(catchError(error => throwError(() => ({
25445
25445
  code: error.error?.code || 'UNLINK_ERROR',
25446
25446
  message: error.error?.message || 'Error al desvincular proveedor',
@@ -25451,7 +25451,7 @@ class OAuthService {
25451
25451
  */
25452
25452
  setPassword(password) {
25453
25453
  return this.http
25454
- .post(`${this.config.apiUrl}/v2/auth/oauth/set-password`, { password })
25454
+ .post(`${this.config?.apiUrl}/v2/auth/oauth/set-password`, { password })
25455
25455
  .pipe(catchError(error => throwError(() => ({
25456
25456
  code: error.error?.code || 'SET_PASSWORD_ERROR',
25457
25457
  message: error.error?.message || 'Error al establecer contraseña',
@@ -25462,7 +25462,7 @@ class OAuthService {
25462
25462
  */
25463
25463
  hasPassword() {
25464
25464
  return this.http
25465
- .get(`${this.config.apiUrl}/v2/auth/oauth/has-password`)
25465
+ .get(`${this.config?.apiUrl}/v2/auth/oauth/has-password`)
25466
25466
  .pipe(catchError(error => throwError(() => ({
25467
25467
  code: error.error?.code || 'CHECK_PASSWORD_ERROR',
25468
25468
  message: error.error?.message || 'Error al verificar contraseña',
@@ -25759,7 +25759,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
25759
25759
  * ```
25760
25760
  */
25761
25761
  class AuthService {
25762
- constructor(config, http, router, stateService, tokenService, storageService, syncService, firebaseService, oauthService, messagingService, i18nService, confirmationService) {
25762
+ constructor(config, http, router, stateService, tokenService, storageService, syncService, firebaseService, oauthService, messagingService, i18nService, confirmationService, firestoreInstance) {
25763
25763
  this.config = config;
25764
25764
  this.http = http;
25765
25765
  this.router = router;
@@ -25772,9 +25772,11 @@ class AuthService {
25772
25772
  this.messagingService = messagingService;
25773
25773
  this.i18nService = i18nService;
25774
25774
  this.confirmationService = confirmationService;
25775
+ this.firestoreInstance = firestoreInstance;
25775
25776
  // Timer para refresh proactivo
25776
25777
  this.refreshTimerId = null;
25777
25778
  this.syncSubscription = null;
25779
+ this.firestoreRBACUnsubscribe = null;
25778
25780
  // =============================================
25779
25781
  // ESTADO PÚBLICO (Signals readonly)
25780
25782
  // =============================================
@@ -25871,7 +25873,7 @@ class AuthService {
25871
25873
  }
25872
25874
  }
25873
25875
  // 5. Iniciar sincronización entre pestañas
25874
- if (this.config.enableTabSync) {
25876
+ if (this.config?.enableTabSync) {
25875
25877
  this.syncService.start();
25876
25878
  this.syncSubscription = this.syncService.onEvent$.subscribe(event => this.handleSyncEvent(event));
25877
25879
  }
@@ -25880,6 +25882,7 @@ class AuthService {
25880
25882
  ngOnDestroy() {
25881
25883
  this.stopRefreshTimer();
25882
25884
  this.syncSubscription?.unsubscribe();
25885
+ this.teardownFirestoreRBACSync();
25883
25886
  }
25884
25887
  // =============================================
25885
25888
  // AUTENTICACIÓN
@@ -26103,7 +26106,7 @@ class AuthService {
26103
26106
  this.stateService.updateRefreshToken(response.refreshToken); // NUEVO: guardar refresh rotado
26104
26107
  this.storageService.saveAccessToken(response.accessToken, expiresAt);
26105
26108
  this.storageService.saveRefreshToken(response.refreshToken); // NUEVO: persistir refresh rotado
26106
- if (this.config.enableFirebaseIntegration && response.firebaseToken) {
26109
+ if (this.config?.enableFirebaseIntegration && response.firebaseToken) {
26107
26110
  this.signInWithFirebase(response.firebaseToken);
26108
26111
  }
26109
26112
  this.startRefreshTimer();
@@ -26189,7 +26192,7 @@ class AuthService {
26189
26192
  this.signOutFirebase();
26190
26193
  this.clearState();
26191
26194
  this.syncService.broadcast({ type: 'LOGOUT' });
26192
- this.router.navigate([this.config.loginRoute]);
26195
+ this.router.navigate([this.config?.loginRoute]);
26193
26196
  }
26194
26197
  // =============================================
26195
26198
  // MFA SETUP (usuario autenticado)
@@ -26404,7 +26407,7 @@ class AuthService {
26404
26407
  this.signOutFirebase();
26405
26408
  this.clearState();
26406
26409
  this.syncService.broadcast({ type: 'LOGOUT' });
26407
- this.router.navigate([this.config.loginRoute]);
26410
+ this.router.navigate([this.config?.loginRoute]);
26408
26411
  }
26409
26412
  }), catchError(error => this.handleAuthError(error)));
26410
26413
  }
@@ -26481,11 +26484,11 @@ class AuthService {
26481
26484
  // PRIVATE METHODS
26482
26485
  // =============================================
26483
26486
  get baseUrl() {
26484
- return `${this.config.apiUrl}${this.config.authPrefix}`;
26487
+ return `${this.config?.apiUrl}${this.config?.authPrefix}`;
26485
26488
  }
26486
26489
  /** Base for /v2/users endpoints (separate from /v2/auth). */
26487
26490
  get usersBaseUrl() {
26488
- return `${this.config.apiUrl}/v2/users`;
26491
+ return `${this.config?.apiUrl}/v2/users`;
26489
26492
  }
26490
26493
  handleSuccessfulAuth(response) {
26491
26494
  const expiresAt = Date.now() + response.expiresIn * 1000;
@@ -26518,18 +26521,18 @@ class AuthService {
26518
26521
  this.syncService.broadcast({ type: 'LOGIN' });
26519
26522
  // Integración con Firebase
26520
26523
  console.log('[ValtechAuth] handleSuccessfulAuth - Firebase check:', {
26521
- enableFirebaseIntegration: this.config.enableFirebaseIntegration,
26524
+ enableFirebaseIntegration: this.config?.enableFirebaseIntegration,
26522
26525
  hasFirebaseTokenKey: 'firebaseToken' in response,
26523
26526
  firebaseTokenValue: !!response.firebaseToken,
26524
26527
  firebaseTokenLength: response.firebaseToken?.length || 0,
26525
26528
  });
26526
- if (this.config.enableFirebaseIntegration &&
26529
+ if (this.config?.enableFirebaseIntegration &&
26527
26530
  'firebaseToken' in response &&
26528
26531
  response.firebaseToken) {
26529
26532
  console.log('[ValtechAuth] Calling signInWithFirebase with token length:', response.firebaseToken.length);
26530
26533
  this.signInWithFirebase(response.firebaseToken);
26531
26534
  }
26532
- else if (this.config.enableFirebaseIntegration) {
26535
+ else if (this.config?.enableFirebaseIntegration) {
26533
26536
  // El login NO trajo firebaseToken (ej. flujo OAuth que lo perdió). En vez
26534
26537
  // de quedar sin sesión de Firebase, recurrimos al fallback self-healing:
26535
26538
  // /refresh sí devuelve un firebaseToken confiable.
@@ -26540,7 +26543,7 @@ class AuthService {
26540
26543
  console.log('[ValtechAuth] Firebase signin skipped - integración Firebase desactivada');
26541
26544
  }
26542
26545
  // Registro automático de dispositivo para push notifications
26543
- if (this.config.enableDeviceRegistration) {
26546
+ if (this.config?.enableDeviceRegistration) {
26544
26547
  this.registerDeviceIfNeeded(); // fire-and-forget
26545
26548
  }
26546
26549
  // Sincronizar idioma del usuario con i18n
@@ -26552,18 +26555,47 @@ class AuthService {
26552
26555
  console.log(`[ValtechAuth] Language synced to: ${userLang}`);
26553
26556
  }
26554
26557
  }
26558
+ // Listener Firestore RBAC — opt-in via enableFirestoreRBAC: true
26559
+ const userId = this.stateService.state().userId;
26560
+ if (userId) {
26561
+ this.setupFirestoreRBACSync(userId);
26562
+ }
26555
26563
  }
26556
26564
  clearState() {
26557
26565
  this.stopRefreshTimer();
26566
+ this.teardownFirestoreRBACSync();
26558
26567
  this.stateService.reset();
26559
26568
  this.storageService.clear();
26560
26569
  }
26570
+ setupFirestoreRBACSync(userId) {
26571
+ if (!this.config?.enableFirestoreRBAC || !this.firestoreInstance)
26572
+ return;
26573
+ this.teardownFirestoreRBACSync();
26574
+ const docRef = doc(this.firestoreInstance, 'users', userId);
26575
+ this.firestoreRBACUnsubscribe = onSnapshot(docRef, snap => {
26576
+ const rbac = snap.data()?.['rbac'];
26577
+ if (!rbac)
26578
+ return;
26579
+ const activeOrg = this.stateService.state().activeOrg;
26580
+ if (rbac['activeOrg'] && rbac['activeOrg'] !== activeOrg)
26581
+ return;
26582
+ const roles = rbac['roles'] ?? [];
26583
+ const permissions = rbac['permissions'] ?? [];
26584
+ this.stateService.updatePermissions(roles, permissions, permissions.includes('*:*'));
26585
+ });
26586
+ }
26587
+ teardownFirestoreRBACSync() {
26588
+ if (this.firestoreRBACUnsubscribe) {
26589
+ this.firestoreRBACUnsubscribe();
26590
+ this.firestoreRBACUnsubscribe = null;
26591
+ }
26592
+ }
26561
26593
  startRefreshTimer() {
26562
26594
  this.stopRefreshTimer();
26563
26595
  const state = this.stateService.state();
26564
26596
  if (!state.expiresAt)
26565
26597
  return;
26566
- const refreshBeforeMs = (this.config.refreshBeforeExpiry || 60) * 1000;
26598
+ const refreshBeforeMs = (this.config?.refreshBeforeExpiry || 60) * 1000;
26567
26599
  const refreshAt = state.expiresAt - refreshBeforeMs;
26568
26600
  const delay = refreshAt - Date.now();
26569
26601
  if (delay > 0) {
@@ -26608,7 +26640,7 @@ class AuthService {
26608
26640
  case 'LOGOUT':
26609
26641
  this.stateService.reset();
26610
26642
  this.stopRefreshTimer();
26611
- this.router.navigate([this.config.loginRoute]);
26643
+ this.router.navigate([this.config?.loginRoute]);
26612
26644
  break;
26613
26645
  case 'PERMISSIONS_UPDATE': {
26614
26646
  const perms = this.storageService.loadPermissions();
@@ -26654,7 +26686,7 @@ class AuthService {
26654
26686
  }
26655
26687
  }
26656
26688
  async signOutFirebase() {
26657
- if (!this.config.enableFirebaseIntegration)
26689
+ if (!this.config?.enableFirebaseIntegration)
26658
26690
  return;
26659
26691
  try {
26660
26692
  if (this.firebaseService) {
@@ -26685,7 +26717,7 @@ class AuthService {
26685
26717
  * Fire-and-forget: se invoca con `void` para no demorar `initialize()`.
26686
26718
  */
26687
26719
  async ensureFirebaseSessionOnBootstrap() {
26688
- if (!this.config.enableFirebaseIntegration || !this.firebaseService)
26720
+ if (!this.config?.enableFirebaseIntegration || !this.firebaseService)
26689
26721
  return;
26690
26722
  // Dar a la persistencia IndexedDB propia de Firebase Auth una oportunidad
26691
26723
  // de auto-restaurarse (navegador normal). En una PWA standalone de iOS
@@ -26711,7 +26743,7 @@ class AuthService {
26711
26743
  * desde el debug-console qué disparó el fallback.
26712
26744
  */
26713
26745
  async reestablishFirebaseViaRefresh(reason) {
26714
- if (!this.config.enableFirebaseIntegration || !this.firebaseService)
26746
+ if (!this.config?.enableFirebaseIntegration || !this.firebaseService)
26715
26747
  return;
26716
26748
  console.log(`[FBAuth] fallback — re-estableciendo Firebase vía /refresh (motivo: ${reason})`);
26717
26749
  try {
@@ -26784,7 +26816,7 @@ class AuthService {
26784
26816
  if (token) {
26785
26817
  // Eliminar del backend
26786
26818
  await firstValueFrom(this.http
26787
- .request('DELETE', `${this.config.apiUrl}/v2/users/me/devices/by-token`, {
26819
+ .request('DELETE', `${this.config?.apiUrl}/v2/users/me/devices/by-token`, {
26788
26820
  body: { token },
26789
26821
  })
26790
26822
  .pipe(catchError(() => of(null))));
@@ -26854,7 +26886,7 @@ class AuthService {
26854
26886
  }
26855
26887
  // Registrar en backend
26856
26888
  const { platform, browser, os } = this.detectPlatformInfo();
26857
- const response = await firstValueFrom(this.http.post(`${this.config.apiUrl}/v2/users/me/devices`, {
26889
+ const response = await firstValueFrom(this.http.post(`${this.config?.apiUrl}/v2/users/me/devices`, {
26858
26890
  token,
26859
26891
  platform,
26860
26892
  browser,
@@ -26877,7 +26909,7 @@ class AuthService {
26877
26909
  */
26878
26910
  async registerDeviceIfNeeded() {
26879
26911
  // Solo si está habilitado y messaging está disponible
26880
- if (!this.config.enableDeviceRegistration || !this.messagingService) {
26912
+ if (!this.config?.enableDeviceRegistration || !this.messagingService) {
26881
26913
  return false;
26882
26914
  }
26883
26915
  try {
@@ -26897,7 +26929,7 @@ class AuthService {
26897
26929
  }
26898
26930
  // Registrar en backend
26899
26931
  const { platform, browser, os } = this.detectPlatformInfo();
26900
- await firstValueFrom(this.http.post(`${this.config.apiUrl}/v2/users/me/devices`, {
26932
+ await firstValueFrom(this.http.post(`${this.config?.apiUrl}/v2/users/me/devices`, {
26901
26933
  token,
26902
26934
  platform,
26903
26935
  browser,
@@ -26916,7 +26948,7 @@ class AuthService {
26916
26948
  * Elimina el dispositivo del backend y borra el token FCM.
26917
26949
  */
26918
26950
  async unregisterDevice() {
26919
- if (!this.config.enableDeviceRegistration || !this.messagingService) {
26951
+ if (!this.config?.enableDeviceRegistration || !this.messagingService) {
26920
26952
  return;
26921
26953
  }
26922
26954
  try {
@@ -26924,7 +26956,7 @@ class AuthService {
26924
26956
  if (token) {
26925
26957
  // Delete from backend (fire and forget)
26926
26958
  this.http
26927
- .request('DELETE', `${this.config.apiUrl}/v2/users/me/devices/by-token`, {
26959
+ .request('DELETE', `${this.config?.apiUrl}/v2/users/me/devices/by-token`, {
26928
26960
  body: { token },
26929
26961
  })
26930
26962
  .pipe(catchError(() => of(null)))
@@ -26976,7 +27008,7 @@ class AuthService {
26976
27008
  }
26977
27009
  return { platform: 'web', browser, os };
26978
27010
  }
26979
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthService, deps: [{ token: VALTECH_AUTH_CONFIG, optional: true }, { token: i1$8.HttpClient }, { token: i1$1.Router }, { token: AuthStateService }, { token: TokenService }, { token: AuthStorageService }, { token: AuthSyncService }, { token: FirebaseService }, { token: OAuthService }, { token: MessagingService, optional: true }, { token: I18nService, optional: true }, { token: ConfirmationDialogService }], target: i0.ɵɵFactoryTarget.Injectable }); }
27011
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthService, deps: [{ token: VALTECH_AUTH_CONFIG, optional: true }, { token: i1$8.HttpClient }, { token: i1$1.Router }, { token: AuthStateService }, { token: TokenService }, { token: AuthStorageService }, { token: AuthSyncService }, { token: FirebaseService }, { token: OAuthService }, { token: MessagingService, optional: true }, { token: I18nService, optional: true }, { token: ConfirmationDialogService }, { token: i1$5.Firestore, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
26980
27012
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthService, providedIn: 'root' }); }
26981
27013
  }
26982
27014
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthService, decorators: [{
@@ -26991,7 +27023,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
26991
27023
  type: Optional
26992
27024
  }] }, { type: I18nService, decorators: [{
26993
27025
  type: Optional
26994
- }] }, { type: ConfirmationDialogService }] });
27026
+ }] }, { type: ConfirmationDialogService }, { type: i1$5.Firestore, decorators: [{
27027
+ type: Optional
27028
+ }] }] });
26995
27029
 
26996
27030
  addIcons({ checkmarkCircle, closeCircle, alertCircle });
26997
27031
  /**
@@ -30165,7 +30199,7 @@ class DeviceService {
30165
30199
  this.http = http;
30166
30200
  }
30167
30201
  get baseUrl() {
30168
- return `${this.config.apiUrl}/v2/users/me/devices`;
30202
+ return `${this.config?.apiUrl}/v2/users/me/devices`;
30169
30203
  }
30170
30204
  /**
30171
30205
  * Lista todos los dispositivos registrados del usuario.
@@ -30220,7 +30254,7 @@ class DeviceService {
30220
30254
  * ```
30221
30255
  */
30222
30256
  validateAction(token) {
30223
- return this.http.post(`${this.config.apiUrl}/v2/actions/validate`, { token });
30257
+ return this.http.post(`${this.config?.apiUrl}/v2/actions/validate`, { token });
30224
30258
  }
30225
30259
  /**
30226
30260
  * Ejecuta una acción de dispositivo desde un token de email.
@@ -30243,7 +30277,7 @@ class DeviceService {
30243
30277
  */
30244
30278
  executeAction(token) {
30245
30279
  // Usa el endpoint unificado de acciones
30246
- return this.http.post(`${this.config.apiUrl}/v2/actions/execute`, { token }).pipe(map$1(response => ({
30280
+ return this.http.post(`${this.config?.apiUrl}/v2/actions/execute`, { token }).pipe(map$1(response => ({
30247
30281
  operationId: response.operationId,
30248
30282
  success: response.success,
30249
30283
  message: response.message,
@@ -30302,7 +30336,7 @@ class SessionService {
30302
30336
  this.http = http;
30303
30337
  }
30304
30338
  get baseUrl() {
30305
- return `${this.config.apiUrl}/v2/users/me/sessions`;
30339
+ return `${this.config?.apiUrl}/v2/users/me/sessions`;
30306
30340
  }
30307
30341
  /**
30308
30342
  * Lista todas las sesiones activas del usuario.
@@ -30625,7 +30659,7 @@ class HandoffService {
30625
30659
  const tokenParam = options.tokenParam ?? HANDOFF_TOKEN_PARAM;
30626
30660
  const routeParam = options.routeParam ?? HANDOFF_ROUTE_PARAM;
30627
30661
  const defaultRoute = options.defaultRoute ?? '/';
30628
- const errorRoute = options.errorRoute ?? this.config.loginRoute ?? '/login';
30662
+ const errorRoute = options.errorRoute ?? this.config?.loginRoute ?? '/login';
30629
30663
  const params = new URLSearchParams(window.location.search);
30630
30664
  const token = params.get(tokenParam);
30631
30665
  if (!token) {
@@ -30655,7 +30689,7 @@ class HandoffService {
30655
30689
  });
30656
30690
  }
30657
30691
  get baseUrl() {
30658
- return `${this.config.apiUrl}${this.config.authPrefix}`;
30692
+ return `${this.config?.apiUrl}${this.config?.authPrefix}`;
30659
30693
  }
30660
30694
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HandoffService, deps: [{ token: VALTECH_AUTH_CONFIG, optional: true }, { token: i1$8.HttpClient }, { token: AuthService }, { token: i1$1.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
30661
30695
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HandoffService, providedIn: 'root' }); }
@@ -30843,7 +30877,7 @@ class NotificationActionService {
30843
30877
  if (!route) {
30844
30878
  return 'no-action-route';
30845
30879
  }
30846
- const currentApp = this.config.appId;
30880
+ const currentApp = this.config?.appId;
30847
30881
  const targetApp = notif.appId;
30848
30882
  // 2) Cross-app: handoff + full redirect
30849
30883
  //
@@ -30853,7 +30887,7 @@ class NotificationActionService {
30853
30887
  if (targetApp && currentApp && targetApp !== currentApp) {
30854
30888
  try {
30855
30889
  const resp = await firstValueFrom(this.handoff.createHandoff({ targetAppId: targetApp, route }));
30856
- const baseUrl = resp.targetBaseUrl ?? this.config.appUrls?.[targetApp];
30890
+ const baseUrl = resp.targetBaseUrl ?? this.config?.appUrls?.[targetApp];
30857
30891
  if (!baseUrl) {
30858
30892
  console.warn(`[NotificationAction] No baseUrl for app '${targetApp}' — backend did not return targetBaseUrl and no appUrls fallback configured`);
30859
30893
  return 'cross-app-unconfigured';