shared-lib-angular 2.0.2 → 2.0.3

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.
@@ -20,14 +20,14 @@ import { CommonModule } from '@angular/common';
20
20
  * Versión actual de la librería @dinafi/frmk
21
21
  * Sincronizada con package.json
22
22
  */
23
- const VERSION = '2.0.2';
23
+ const VERSION = '2.0.3';
24
24
  /**
25
25
  * Información completa de la versión
26
26
  */
27
27
  const VERSION_INFO = {
28
- version: '2.0.2',
28
+ version: '2.0.3',
29
29
  name: 'shared-lib-angular',
30
- buildDate: '2026-02-05T20:47:48.315Z',
30
+ buildDate: '2026-02-05T21:05:38.248Z',
31
31
  angular: '^20.0.0'
32
32
  };
33
33
 
@@ -340,19 +340,160 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
340
340
  args: [{ providedIn: 'root' }]
341
341
  }] });
342
342
 
343
+ /**
344
+ * Keys de tokens OAuth/OIDC manejados por angular-oauth2-oidc y Keycloak.
345
+ * Única fuente de verdad — elimina listas duplicadas e inconsistentes.
346
+ */
347
+ const TOKEN_KEYS = [
348
+ 'access_token',
349
+ 'refresh_token',
350
+ 'id_token',
351
+ 'token_type',
352
+ 'expires_at',
353
+ 'nonce',
354
+ 'PKCE_verifier',
355
+ 'code_verifier',
356
+ 'session_state',
357
+ 'id_token_claims_obj',
358
+ 'id_token_expires_at',
359
+ 'id_token_stored_at',
360
+ 'access_token_stored_at'
361
+ ];
362
+ /**
363
+ * Keys de estado OAuth que deben preservarse durante un callback
364
+ * (necesarias para validar code + state en el intercambio PKCE).
365
+ */
366
+ const STATE_KEYS = new Set([
367
+ 'nonce',
368
+ 'PKCE_verifier',
369
+ 'code_verifier',
370
+ 'session_state',
371
+ 'state'
372
+ ]);
373
+ /**
374
+ * Servicio centralizado para gestión de tokens en localStorage / sessionStorage.
375
+ *
376
+ * - Elimina las 4+ listas de keys duplicadas e inconsistentes que existían en AuthService.
377
+ * - Opera simétricamente sobre ambos storages.
378
+ * - Soporta la key dinámica `refresh_token_{clientId}` que usa angular-oauth2-oidc.
379
+ * - Expone métodos públicos para que la plantilla pueda leer tokens sin acceder a storage directamente.
380
+ *
381
+ * @example
382
+ * // Desde la librería (AuthService):
383
+ * this.tokenStorage.clearAll();
384
+ *
385
+ * // Desde la plantilla (skeleton):
386
+ * const expired = this.tokenStorage.isTokenExpired();
387
+ */
388
+ class TokenStorageService {
389
+ // ── Limpieza ──────────────────────────────────────────────────────
390
+ /**
391
+ * Limpia TODOS los tokens y estado OAuth de ambos storages.
392
+ * Incluye la key dinámica `refresh_token_{clientId}` si se proporciona.
393
+ *
394
+ * @param clientId — clientId de OAuth para limpiar `refresh_token_{clientId}` (opcional)
395
+ */
396
+ clearAll(clientId) {
397
+ TOKEN_KEYS.forEach(key => {
398
+ localStorage.removeItem(key);
399
+ sessionStorage.removeItem(key);
400
+ });
401
+ // Key dinámica de angular-oauth2-oidc
402
+ if (clientId) {
403
+ localStorage.removeItem(`refresh_token_${clientId}`);
404
+ sessionStorage.removeItem(`refresh_token_${clientId}`);
405
+ }
406
+ // También limpiar 'state' que no está en TOKEN_KEYS pero puede persistir
407
+ localStorage.removeItem('state');
408
+ sessionStorage.removeItem('state');
409
+ }
410
+ /**
411
+ * Limpia tokens pero MANTIENE las keys de estado OAuth necesarias para
412
+ * validar el callback (nonce, PKCE_verifier, code_verifier, session_state, state).
413
+ *
414
+ * Usar durante un callback OAuth antes de procesar el authorization code.
415
+ */
416
+ clearTokensKeepState() {
417
+ TOKEN_KEYS.forEach(key => {
418
+ if (!STATE_KEYS.has(key)) {
419
+ localStorage.removeItem(key);
420
+ sessionStorage.removeItem(key);
421
+ }
422
+ });
423
+ console.log('[TokenStorageService] Cleared tokens, kept state/nonce/PKCE for callback validation');
424
+ }
425
+ // ── Lectura ───────────────────────────────────────────────────────
426
+ /**
427
+ * Lee un valor de localStorage o sessionStorage (en ese orden de prioridad).
428
+ */
429
+ getItem(key) {
430
+ return localStorage.getItem(key) ?? sessionStorage.getItem(key);
431
+ }
432
+ /**
433
+ * Obtiene el refresh_token, incluyendo la variante dinámica `refresh_token_{clientId}`.
434
+ *
435
+ * @param clientId — clientId de OAuth (opcional)
436
+ */
437
+ getRefreshToken(clientId) {
438
+ const token = this.getItem('refresh_token');
439
+ if (token)
440
+ return token;
441
+ if (clientId) {
442
+ return localStorage.getItem(`refresh_token_${clientId}`)
443
+ ?? sessionStorage.getItem(`refresh_token_${clientId}`)
444
+ ?? null;
445
+ }
446
+ return null;
447
+ }
448
+ /**
449
+ * Obtiene el access_token de cualquier storage.
450
+ */
451
+ getAccessToken() {
452
+ return this.getItem('access_token');
453
+ }
454
+ // ── Estado ────────────────────────────────────────────────────────
455
+ /**
456
+ * Verifica si hay un token almacenado y está expirado.
457
+ * Retorna `false` si no existe `expires_at` (no hay token, no está "expirado").
458
+ */
459
+ isTokenExpired() {
460
+ const expiresAt = this.getItem('expires_at');
461
+ if (!expiresAt) {
462
+ return false;
463
+ }
464
+ return parseInt(expiresAt, 10) < Date.now();
465
+ }
466
+ // ── Utilidades ────────────────────────────────────────────────────
467
+ /**
468
+ * Elimina una key específica de ambos storages.
469
+ */
470
+ removeItem(key) {
471
+ localStorage.removeItem(key);
472
+ sessionStorage.removeItem(key);
473
+ }
474
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: TokenStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
475
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: TokenStorageService, providedIn: 'root' });
476
+ }
477
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: TokenStorageService, decorators: [{
478
+ type: Injectable,
479
+ args: [{ providedIn: 'root' }]
480
+ }] });
481
+
343
482
  class AuthService {
344
483
  oauthService;
345
484
  router;
346
485
  store;
486
+ tokenStorage;
347
487
  isAuthenticatedSubject$ = new BehaviorSubject(false);
348
488
  isAuthenticated$ = this.isAuthenticatedSubject$.asObservable();
349
489
  isDoneLoadingSubject$ = new BehaviorSubject(false);
350
490
  isDoneLoading$ = this.isDoneLoadingSubject$.asObservable();
351
491
  isInitialLogin = true;
352
- constructor(oauthService, router, store) {
492
+ constructor(oauthService, router, store, tokenStorage) {
353
493
  this.oauthService = oauthService;
354
494
  this.router = router;
355
495
  this.store = store;
496
+ this.tokenStorage = tokenStorage;
356
497
  // IMPORTANTE: Limpiar tokens expirados ANTES de cualquier otra operación
357
498
  this.clearExpiredTokensOnStartup();
358
499
  this.oauthService.events
@@ -392,48 +533,11 @@ class AuthService {
392
533
  return;
393
534
  }
394
535
  // Verificar si hay un token y si está expirado
395
- const expiresAt = localStorage.getItem('expires_at') || sessionStorage.getItem('expires_at');
396
- if (expiresAt) {
397
- const expirationTime = parseInt(expiresAt, 10);
398
- const now = Date.now();
399
- if (expirationTime < now) {
400
- console.log('[AuthService] Expired token detected, clearing storage');
401
- this.clearAllTokens();
402
- }
536
+ if (this.tokenStorage.isTokenExpired()) {
537
+ console.log('[AuthService] Expired token detected, clearing storage');
538
+ this.tokenStorage.clearAll();
403
539
  }
404
540
  }
405
- /**
406
- * Limpia todos los tokens del storage
407
- */
408
- clearAllTokens() {
409
- const keysToRemove = [
410
- 'access_token', 'refresh_token', 'id_token', 'token_type',
411
- 'expires_at', 'nonce', 'PKCE_verifier', 'session_state',
412
- 'id_token_claims_obj', 'id_token_expires_at', 'id_token_stored_at',
413
- 'access_token_stored_at'
414
- ];
415
- keysToRemove.forEach(key => {
416
- localStorage.removeItem(key);
417
- sessionStorage.removeItem(key);
418
- });
419
- }
420
- /**
421
- * Limpia tokens antiguos pero MANTIENE state, nonce y PKCE_verifier
422
- * que son necesarios para validar el callback OAuth
423
- */
424
- clearOldTokensKeepState() {
425
- // Solo limpiar tokens, NO state/nonce/PKCE_verifier
426
- const keysToRemove = [
427
- 'access_token', 'refresh_token', 'id_token', 'token_type',
428
- 'expires_at', 'id_token_claims_obj', 'id_token_expires_at',
429
- 'id_token_stored_at', 'access_token_stored_at'
430
- ];
431
- keysToRemove.forEach(key => {
432
- localStorage.removeItem(key);
433
- sessionStorage.removeItem(key);
434
- });
435
- console.log('[AuthService] Cleared old tokens, kept state/nonce/PKCE for callback validation');
436
- }
437
541
  handleSuccessfulAuthentication() {
438
542
  if (this.oauthService.hasValidAccessToken()) {
439
543
  this.isAuthenticatedSubject$.next(true);
@@ -484,28 +588,23 @@ class AuthService {
484
588
  this.isDoneLoadingSubject$.next(true);
485
589
  }
486
590
  /**
487
- * Limpia todos los tokens del storage
591
+ * Limpia todos los tokens del storage y resetea OAuthService
488
592
  */
489
593
  clearTokenStorage() {
490
594
  this.oauthService.logOut(true); // true = no redirect, solo limpiar
491
- localStorage.removeItem('access_token');
492
- localStorage.removeItem('refresh_token');
493
- localStorage.removeItem('id_token');
494
- localStorage.removeItem('nonce');
495
- localStorage.removeItem('expires_at');
496
- sessionStorage.removeItem('access_token');
497
- sessionStorage.removeItem('refresh_token');
498
- sessionStorage.removeItem('id_token');
595
+ this.tokenStorage.clearAll();
499
596
  }
500
597
  /**
501
598
  * Verifica si el token actual está expirado
502
599
  */
503
600
  isTokenExpired() {
601
+ // Primero verificar vía OAuthService (tokens en memoria)
504
602
  const expiresAt = this.oauthService.getAccessTokenExpiration();
505
- if (!expiresAt) {
506
- return false; // Si no hay token, no está "expirado", simplemente no existe
603
+ if (expiresAt) {
604
+ return expiresAt < Date.now();
507
605
  }
508
- return expiresAt < Date.now();
606
+ // Fallback: verificar en storage
607
+ return this.tokenStorage.isTokenExpired();
509
608
  }
510
609
  async runInitialLoginSequence() {
511
610
  try {
@@ -529,7 +628,7 @@ class AuthService {
529
628
  if (isOAuthCallback) {
530
629
  console.log('[AuthService] OAuth callback detected, clearing old tokens before processing');
531
630
  // Limpiar solo tokens, NO el state/nonce que necesitamos para validar el callback
532
- this.clearOldTokensKeepState();
631
+ this.tokenStorage.clearTokensKeepState();
533
632
  this.isInitialLogin = true;
534
633
  await this.oauthService.tryLoginCodeFlow();
535
634
  }
@@ -571,18 +670,16 @@ class AuthService {
571
670
  if (hasCode) {
572
671
  console.log('[AuthService] OAuth callback detected: resetting OAuthService state');
573
672
  // Limpiar storage EXCEPTO state/nonce/PKCE
574
- this.clearOldTokensKeepState();
673
+ this.tokenStorage.clearTokensKeepState();
575
674
  // CRÍTICO: Resetear propiedades internas de OAuthService
576
675
  // para que no valide tokens viejos en memoria
577
676
  this.resetOAuthServiceInternalState();
578
677
  }
579
678
  else {
580
679
  // No es callback - verificar si hay tokens expirados
581
- const expiresAt = localStorage.getItem('expires_at');
582
- const isExpired = expiresAt && parseInt(expiresAt, 10) < Date.now();
583
- if (isExpired) {
680
+ if (this.tokenStorage.isTokenExpired()) {
584
681
  console.log('[AuthService] Clearing all expired tokens before configure');
585
- this.clearAllTokens();
682
+ this.tokenStorage.clearAll();
586
683
  this.resetOAuthServiceInternalState();
587
684
  }
588
685
  }
@@ -640,9 +737,7 @@ class AuthService {
640
737
  const logoutUrl = authConfig.logoutUrl;
641
738
  let refreshToken = this.oauthService.getRefreshToken();
642
739
  if (!refreshToken) {
643
- refreshToken = localStorage.getItem('refresh_token')
644
- || localStorage.getItem('refresh_token_' + authConfig.clientId)
645
- || sessionStorage.getItem('refresh_token');
740
+ refreshToken = this.tokenStorage.getRefreshToken(authConfig.clientId);
646
741
  }
647
742
  if (!logoutUrl) {
648
743
  console.warn('Logout URL not configured, skipping Keycloak logout');
@@ -675,20 +770,9 @@ class AuthService {
675
770
  }
676
771
  }
677
772
  performLocalLogout() {
773
+ const authConfig = this.store.authConfig();
678
774
  this.oauthService.logOut(true);
679
- // Limpiar tokens del localStorage
680
- localStorage.removeItem('access_token');
681
- localStorage.removeItem('id_token');
682
- localStorage.removeItem('refresh_token');
683
- localStorage.removeItem('code_verifier');
684
- localStorage.removeItem('nonce');
685
- localStorage.removeItem('PKCE_verifier');
686
- // Limpiar tokens del sessionStorage
687
- sessionStorage.removeItem('access_token');
688
- sessionStorage.removeItem('id_token');
689
- sessionStorage.removeItem('refresh_token');
690
- sessionStorage.removeItem('nonce');
691
- sessionStorage.removeItem('PKCE_verifier');
775
+ this.tokenStorage.clearAll(authConfig.clientId);
692
776
  this.isAuthenticatedSubject$.next(false);
693
777
  this.isDoneLoadingSubject$.next(true);
694
778
  const currentUrl = this.router.url;
@@ -812,7 +896,7 @@ class AuthService {
812
896
  return {};
813
897
  }
814
898
  }
815
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AuthService, deps: [{ token: i1.OAuthService }, { token: i4.Router }, { token: FrmkConfigStore }], target: i0.ɵɵFactoryTarget.Injectable });
899
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AuthService, deps: [{ token: i1.OAuthService }, { token: i4.Router }, { token: FrmkConfigStore }, { token: TokenStorageService }], target: i0.ɵɵFactoryTarget.Injectable });
816
900
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AuthService, providedIn: 'root' });
817
901
  }
818
902
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AuthService, decorators: [{
@@ -820,7 +904,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
820
904
  args: [{
821
905
  providedIn: 'root'
822
906
  }]
823
- }], ctorParameters: () => [{ type: i1.OAuthService }, { type: i4.Router }, { type: FrmkConfigStore }] });
907
+ }], ctorParameters: () => [{ type: i1.OAuthService }, { type: i4.Router }, { type: FrmkConfigStore }, { type: TokenStorageService }] });
824
908
 
825
909
  class ConfigService {
826
910
  http;
@@ -1425,5 +1509,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1425
1509
  * Generated bundle index. Do not edit.
1426
1510
  */
1427
1511
 
1428
- export { AuthService, AuthorizationService, ConfigService, DEFAULT_DASHBOARD_CONFIG, DEFAULT_LIBRARY_CONFIG, DEFAULT_LOGIN_CONFIG, DashboardComponent, FrmkConfigStore, LoginComponent, VERSION, VERSION_INFO, authGuard };
1512
+ export { AuthService, AuthorizationService, ConfigService, DEFAULT_DASHBOARD_CONFIG, DEFAULT_LIBRARY_CONFIG, DEFAULT_LOGIN_CONFIG, DashboardComponent, FrmkConfigStore, LoginComponent, TokenStorageService, VERSION, VERSION_INFO, authGuard };
1429
1513
  //# sourceMappingURL=shared-lib-angular.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-lib-angular.mjs","sources":["../../src/lib/version.ts","../../src/lib/models/login-config.interface.ts","../../src/lib/models/dashboard-config.interface.ts","../../src/lib/models/library-config.interface.ts","../../src/lib/services/frmk-config-store.service.ts","../../src/lib/services/authentication.service.ts","../../src/lib/services/config.service.ts","../../src/lib/services/authorization.service.ts","../../src/lib/guards/authorization.guard.ts","../../src/lib/components/login/login.component.ts","../../src/lib/components/login/login.component.html","../../src/lib/components/dashboard/dashboard.component.ts","../../src/lib/components/dashboard/dashboard.component.html","../../src/public-api.ts","../../src/shared-lib-angular.ts"],"sourcesContent":["// ========================================\n// VERSION - Auto-generado por sync-version.js\n// ========================================\n// Ejecutar 'npm run sync-version' para actualizar manualmente\n// Se sincroniza automáticamente en prebuild\n\n/**\n * Versión actual de la librería @dinafi/frmk\n * Sincronizada con package.json\n */\nexport const VERSION = '2.0.2';\n\n/**\n * Información completa de la versión\n */\nexport const VERSION_INFO = {\n version: '2.0.2',\n name: 'shared-lib-angular',\n buildDate: '2026-02-05T20:47:48.315Z',\n angular: '^20.0.0'\n} as const;\n","/**\r\n * Interface for configuring the LoginComponent appearance and behavior\r\n */\r\nexport interface LoginConfig {\r\n // === IDENTITY ===\r\n /** URL of the logo image. Defaults to the Ministerio de Hacienda logo */\r\n logoUrl: string;\r\n /** Alt text for the logo image */\r\n logoAlt: string;\r\n /** Width of the logo (CSS value, e.g., '120px') */\r\n logoWidth: string;\r\n /** Height of the logo (CSS value, e.g., '120px') */\r\n logoHeight: string;\r\n\r\n // === TEXTS ===\r\n /** Main title displayed on the login page */\r\n title: string;\r\n /** Optional subtitle displayed below the title */\r\n subtitle?: string;\r\n /** Institution name displayed in the footer */\r\n institutionName: string;\r\n /** Text for the login button */\r\n loginButtonText: string;\r\n /** Text for the logout button */\r\n logoutButtonText: string;\r\n /** Text for the \"go to dashboard\" button when already authenticated */\r\n dashboardButtonText: string;\r\n\r\n // === VERSION ===\r\n /** Whether to show the version number */\r\n showVersion: boolean;\r\n /** Version string to display */\r\n version: string;\r\n\r\n // === COLORS (CSS custom properties override) ===\r\n /** Primary color (overrides --color-primary) */\r\n primaryColor?: string;\r\n /** Background color of the container */\r\n backgroundColor?: string;\r\n /** Text color */\r\n textColor?: string;\r\n\r\n // === BEHAVIOR ===\r\n /** URL to redirect after successful login */\r\n redirectUrl: string;\r\n /** Whether to show the logout button when authenticated */\r\n showLogoutButton: boolean;\r\n\r\n // === FOOTER ===\r\n /** Custom footer text */\r\n footerText?: string;\r\n /** Whether to show the footer */\r\n showFooter: boolean;\r\n}\r\n\r\n/**\r\n * Default configuration for the LoginComponent\r\n */\r\nexport const DEFAULT_LOGIN_CONFIG: LoginConfig = {\r\n logoUrl: 'assets/@dinafi/frmk/logo-mh.png',\r\n logoAlt: 'Logo',\r\n logoWidth: '120px',\r\n logoHeight: '120px',\r\n title: 'Sistema de Autenticación',\r\n institutionName: 'Ministerio de Hacienda de El Salvador',\r\n loginButtonText: 'Iniciar Sesión con OIDC',\r\n logoutButtonText: 'Cerrar Sesión',\r\n dashboardButtonText: 'Ir al Dashboard',\r\n showVersion: true,\r\n version: '1.0.0',\r\n redirectUrl: '/home',\r\n showLogoutButton: true,\r\n showFooter: true\r\n};\r\n","/**\r\n * Interface for configuring the DashboardComponent appearance and behavior\r\n */\r\nexport interface DashboardConfig {\r\n /** Application title displayed in the header */\r\n title: string;\r\n /** Optional subtitle */\r\n subtitle?: string;\r\n /** Logo URL */\r\n logoUrl: string;\r\n /** Logo alt text */\r\n logoAlt: string;\r\n /** Footer text */\r\n footerText: string;\r\n /** Whether to show the version in the footer */\r\n showVersion: boolean;\r\n /** Version string */\r\n version: string;\r\n /** Whether to show static menu items (Inicio, Página Ejemplo, Componentes UI) */\r\n showStaticMenu: boolean;\r\n}\r\n\r\n/**\r\n * Default configuration for the DashboardComponent\r\n */\r\nexport const DEFAULT_DASHBOARD_CONFIG: DashboardConfig = {\r\n title: 'Sistema',\r\n logoUrl: 'assets/@dinafi/frmk/logo-mh.png',\r\n logoAlt: 'Logo',\r\n footerText: 'Ministerio de Hacienda, El Salvador',\r\n showVersion: true,\r\n version: '1.0.0',\r\n showStaticMenu: true\r\n};\r\n","import { LoginConfig } from './login-config.interface';\r\nimport { DashboardConfig } from './dashboard-config.interface';\r\n\r\n/**\r\n * Configuración de la librería que debe ser proporcionada por la aplicación consumidora.\r\n * Estos valores son críticos y deben ser configurados al inicializar la librería\r\n * mediante `FrmkConfigStore.initialize()` en el APP_INITIALIZER.\r\n */\r\nexport interface FrmkLibraryConfig {\r\n /**\r\n * URL del servidor de configuración (Config Server)\r\n * Ejemplo: 'config-server.example.com' o 'localhost:8080'\r\n */\r\n configServerHost: string;\r\n\r\n /**\r\n * Identificador del frontend en el Config Server\r\n * Este valor identifica la aplicación para obtener su configuración específica\r\n * Ejemplo: 'mi-aplicacion-frontend'\r\n */\r\n frontendId: string;\r\n\r\n /**\r\n * Ruta del servicio de configuración (opcional)\r\n * Por defecto: '/api/v1/config/service'\r\n */\r\n configServicePath?: string;\r\n\r\n /**\r\n * Realm de autenticación (opcional)\r\n * Por defecto se obtiene del Config Server\r\n */\r\n realm?: string;\r\n\r\n /**\r\n * Si es ambiente de producción (opcional)\r\n * Por defecto: false\r\n */\r\n production?: boolean;\r\n\r\n /**\r\n * Si requiere HTTPS (opcional)\r\n * Por defecto: true\r\n */\r\n requireHttps?: boolean;\r\n\r\n /**\r\n * Mostrar información de debug (opcional)\r\n * Por defecto: false\r\n */\r\n showDebugInformation?: boolean;\r\n\r\n /**\r\n * Configuración del componente de Login (opcional)\r\n * Permite personalizar textos, logos y comportamiento del login\r\n */\r\n loginConfig?: Partial<LoginConfig>;\r\n\r\n /**\r\n * Configuración del componente Dashboard (opcional)\r\n * Permite personalizar el layout principal de la aplicación\r\n */\r\n dashboardConfig?: Partial<DashboardConfig>;\r\n}\r\n\r\n/**\r\n * Configuración por defecto de la librería\r\n */\r\nexport const DEFAULT_LIBRARY_CONFIG: Partial<FrmkLibraryConfig> = {\r\n configServicePath: '/api/v1/config/service',\r\n production: false,\r\n requireHttps: true,\r\n showDebugInformation: false\r\n};\r\n","import { Injectable, signal, computed } from '@angular/core';\r\nimport { AuthConfig } from 'angular-oauth2-oidc';\r\nimport { AppConfiguration, ConfigServerResponse } from '../models/app-config.interface';\r\nimport { FrmkLibraryConfig, DEFAULT_LIBRARY_CONFIG } from '../models/library-config.interface';\r\nimport { LoginConfig, DEFAULT_LOGIN_CONFIG } from '../models/login-config.interface';\r\nimport { DashboardConfig, DEFAULT_DASHBOARD_CONFIG } from '../models/dashboard-config.interface';\r\n\r\n/**\r\n * Store centralizado de configuración del framework.\r\n *\r\n * Reemplaza las variables globales mutables (`currentAppConfig`, `libraryConfig`)\r\n * con un servicio inyectable basado en signals de Angular.\r\n *\r\n * Ciclo de vida:\r\n * 1. `initialize(config)` — llamado en APP_INITIALIZER con FrmkLibraryConfig\r\n * 2. `applyServerConfig(data)` — llamado por ConfigService tras obtener datos del Config Server\r\n *\r\n * Todas las propiedades computadas lanzan error si se leen antes de `initialize()`.\r\n *\r\n * @example\r\n * // En APP_INITIALIZER:\r\n * const store = inject(FrmkConfigStore);\r\n * store.initialize(myLibraryConfig);\r\n * await configService.loadConfig(); // internamente llama store.applyServerConfig()\r\n * authService.initializeAuth(store.authConfig());\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class FrmkConfigStore {\r\n\r\n // ── Signals internos ──────────────────────────────────────────────\r\n\r\n private readonly _libraryConfig = signal<FrmkLibraryConfig | null>(null);\r\n private readonly _serverConfig = signal<ConfigServerResponse | null>(null);\r\n\r\n // ── Estado público (read-only) ────────────────────────────────────\r\n\r\n /** Indica si la librería ha sido inicializada con `initialize()`. */\r\n readonly isConfigured = computed(() => this._libraryConfig() !== null);\r\n\r\n /** Configuración de la librería (merged con defaults). Lanza si no inicializada. */\r\n readonly libraryConfig = computed(() => {\r\n const cfg = this._libraryConfig();\r\n if (!cfg) {\r\n throw new Error(\r\n '[FRMK] La librería no ha sido configurada. ' +\r\n 'Llame a FrmkConfigStore.initialize() en su APP_INITIALIZER.'\r\n );\r\n }\r\n return cfg;\r\n });\r\n\r\n /** Configuración del componente Login (defaults + libraryConfig.loginConfig). */\r\n readonly loginConfig = computed<LoginConfig>(() => {\r\n const lib = this.libraryConfig();\r\n return { ...DEFAULT_LOGIN_CONFIG, ...(lib.loginConfig || {}) };\r\n });\r\n\r\n /** Configuración del componente Dashboard (defaults + libraryConfig.dashboardConfig). */\r\n readonly dashboardConfig = computed<DashboardConfig>(() => {\r\n const lib = this.libraryConfig();\r\n return { ...DEFAULT_DASHBOARD_CONFIG, ...(lib.dashboardConfig || {}) };\r\n });\r\n\r\n /**\r\n * Configuración completa de la aplicación.\r\n * Si hay datos del Config Server se aplican; en caso contrario se usan solo los defaults + libraryConfig.\r\n */\r\n readonly appConfig = computed<AppConfiguration>(() => {\r\n const lib = this.libraryConfig(); // lanza si no inicializada\r\n let config = this.createDefaultAppConfig(lib);\r\n\r\n const serverData = this._serverConfig();\r\n if (serverData) {\r\n const mapped = this.mapConfigServerResponse(serverData, config);\r\n config = this.mergeConfigurations(config, mapped);\r\n }\r\n\r\n return this.buildDynamicUrls(config);\r\n });\r\n\r\n /** AuthConfig de angular-oauth2-oidc derivada de appConfig. */\r\n readonly authConfig = computed<AuthConfig>(() => {\r\n const app = this.appConfig();\r\n return {\r\n issuer: app.auth.issuer,\r\n loginUrl: app.auth.loginUrl,\r\n tokenEndpoint: app.auth.tokenEndpoint,\r\n userinfoEndpoint: app.auth.userinfoEndpoint,\r\n logoutUrl: app.auth.logoutUrl,\r\n redirectUri: app.auth.redirectUri,\r\n postLogoutRedirectUri: app.auth.postLogoutRedirectUri,\r\n clientId: app.auth.clientId,\r\n responseType: 'code',\r\n scope: app.auth.scope,\r\n disableAtHashCheck: true,\r\n requireHttps: app.environment.requireHttps,\r\n showDebugInformation: app.environment.showDebugInformation,\r\n strictDiscoveryDocumentValidation: false,\r\n skipIssuerCheck: true,\r\n requestAccessToken: true,\r\n customQueryParams: {},\r\n silentRefreshTimeout: 5000,\r\n timeoutFactor: 0.25,\r\n sessionChecksEnabled: false,\r\n clearHashAfterLogin: true,\r\n oidc: true,\r\n clockSkewInSec: 30,\r\n disableIdTokenTimer: true\r\n };\r\n });\r\n\r\n // ── Métodos públicos ──────────────────────────────────────────────\r\n\r\n /**\r\n * Inicializa la librería con la configuración proporcionada por la app consumidora.\r\n * Debe llamarse UNA vez dentro del APP_INITIALIZER, antes de cualquier otro uso.\r\n *\r\n * @param config Configuración de la librería (se fusiona con DEFAULT_LIBRARY_CONFIG)\r\n */\r\n initialize(config: FrmkLibraryConfig): void {\r\n this._libraryConfig.set({\r\n ...DEFAULT_LIBRARY_CONFIG,\r\n ...config\r\n } as FrmkLibraryConfig);\r\n\r\n // Resetear server config para que appConfig se recalcule con los nuevos defaults\r\n this._serverConfig.set(null);\r\n }\r\n\r\n /**\r\n * Aplica los datos devueltos por el Config Server.\r\n * Llamado por `ConfigService.loadConfig()` después de la petición HTTP.\r\n *\r\n * @param data Respuesta del Config Server (o undefined si falló la carga)\r\n */\r\n applyServerConfig(data?: ConfigServerResponse): void {\r\n this._serverConfig.set(data ?? null);\r\n }\r\n\r\n // ── Lógica privada (migrada de app.config.ts) ─────────────────────\r\n\r\n private createDefaultAppConfig(lib: FrmkLibraryConfig): AppConfiguration {\r\n return {\r\n hosts: {\r\n configServer: lib.configServerHost,\r\n authServer: '',\r\n keycloak: '',\r\n localApp: ''\r\n },\r\n paths: {\r\n configService: lib.configServicePath || '/api/v1/config/service',\r\n realm: lib.realm || 'realm-to-create'\r\n },\r\n configServer: {\r\n url: '',\r\n frontend: lib.frontendId\r\n },\r\n auth: {\r\n issuer: '',\r\n loginUrl: '',\r\n tokenEndpoint: '',\r\n userinfoEndpoint: '',\r\n logoutUrl: '',\r\n clientId: '',\r\n redirectUri: '',\r\n postLogoutRedirectUri: '',\r\n silentRefreshRedirectUri: '',\r\n scope: 'openid email profile'\r\n },\r\n authorization: {\r\n baseUrl: '',\r\n verifyEndpoint: '/api/v1/authz/verify-groups',\r\n hierarchyEndpoint: '/api/v1/authz/hierarchy-by-component-and-groups'\r\n },\r\n environment: {\r\n production: lib.production ?? false,\r\n requireHttps: lib.requireHttps ?? true,\r\n showDebugInformation: lib.showDebugInformation ?? false\r\n }\r\n };\r\n }\r\n\r\n private mapConfigServerResponse(\r\n data: ConfigServerResponse,\r\n defaultConfig: AppConfiguration\r\n ): Partial<AppConfiguration> {\r\n const mapped: Partial<AppConfiguration> = {};\r\n\r\n if (data['security.url.auth']) {\r\n mapped.hosts = {\r\n ...defaultConfig.hosts,\r\n ...(mapped.hosts || {}),\r\n authServer: data['security.url.auth']\r\n };\r\n }\r\n\r\n if (data['quarkus.oidc.client-id']) {\r\n mapped.auth = {\r\n ...defaultConfig.auth,\r\n ...(mapped.auth || {}),\r\n clientId: data['quarkus.oidc.client-id']\r\n };\r\n }\r\n\r\n if (data['security.realm']) {\r\n mapped.paths = {\r\n ...defaultConfig.paths,\r\n ...(mapped.paths || {}),\r\n realm: data['security.realm']\r\n };\r\n }\r\n\r\n if (data['security.url.authz']) {\r\n mapped.authorization = {\r\n ...defaultConfig.authorization,\r\n ...(mapped.authorization || {}),\r\n baseUrl: data['security.url.authz']\r\n };\r\n }\r\n\r\n if (data['security.scope']) {\r\n mapped.auth = {\r\n ...defaultConfig.auth,\r\n ...(mapped.auth || {}),\r\n scope: data['security.scope']\r\n };\r\n }\r\n\r\n if (data['security.url.keycloak']) {\r\n mapped.hosts = {\r\n ...defaultConfig.hosts,\r\n ...(mapped.hosts || {}),\r\n keycloak: data['security.url.keycloak']\r\n };\r\n }\r\n\r\n if (data['security.url.callback']) {\r\n mapped.hosts = {\r\n ...defaultConfig.hosts,\r\n ...(mapped.hosts || {}),\r\n localApp: data['security.url.callback']\r\n };\r\n }\r\n\r\n if (data['security.url.https'] !== undefined) {\r\n mapped.environment = {\r\n ...defaultConfig.environment,\r\n ...(mapped.environment || {}),\r\n requireHttps: data['security.url.https']\r\n };\r\n }\r\n\r\n return mapped;\r\n }\r\n\r\n private mergeConfigurations(\r\n base: AppConfiguration,\r\n override: Partial<AppConfiguration>\r\n ): AppConfiguration {\r\n const merged = { ...base };\r\n\r\n if (override.hosts) {\r\n merged.hosts = { ...merged.hosts, ...override.hosts };\r\n }\r\n if (override.paths) {\r\n merged.paths = { ...merged.paths, ...override.paths };\r\n }\r\n if (override.configServer) {\r\n merged.configServer = { ...merged.configServer, ...override.configServer };\r\n }\r\n if (override.auth) {\r\n merged.auth = { ...merged.auth, ...override.auth };\r\n }\r\n if (override.authorization) {\r\n merged.authorization = { ...merged.authorization, ...override.authorization };\r\n }\r\n if (override.environment) {\r\n merged.environment = { ...merged.environment, ...override.environment };\r\n }\r\n\r\n return merged;\r\n }\r\n\r\n private buildDynamicUrls(config: AppConfiguration): AppConfiguration {\r\n const c = { ...config };\r\n const proto = c.environment.requireHttps ? 'https' : 'http';\r\n\r\n // Config Server URL\r\n c.configServer = { ...c.configServer };\r\n c.configServer.url = `${proto}://${c.hosts.configServer}${c.paths.configService}`;\r\n\r\n // Auth URLs\r\n c.auth = { ...c.auth };\r\n c.auth.issuer = `${proto}://${c.hosts.keycloak}/realms/${c.paths.realm}`;\r\n c.auth.loginUrl = `${proto}://${c.hosts.keycloak}/realms/${c.paths.realm}/protocol/openid-connect/auth`;\r\n c.auth.tokenEndpoint = `${proto}://${c.hosts.authServer}/oidc/realm/${c.paths.realm}/protocol/openid-connect/token`;\r\n c.auth.userinfoEndpoint = `${proto}://${c.hosts.authServer}/oidc/realm/${c.paths.realm}/protocol/openid-connect/userinfo`;\r\n c.auth.logoutUrl = `${proto}://${c.hosts.authServer}/oidc/realm/${c.paths.realm}/protocol/openid-connect/logout`;\r\n\r\n // Redirect URLs (locales)\r\n const currentOrigin = globalThis.window?.location?.origin ?? c.hosts.localApp;\r\n c.auth.redirectUri = `${currentOrigin}/login`;\r\n c.auth.postLogoutRedirectUri = `${currentOrigin}/login`;\r\n\r\n // Authorization URL\r\n c.authorization = { ...c.authorization };\r\n c.authorization.baseUrl = `${proto}://${c.authorization.baseUrl}`;\r\n\r\n return c;\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { AuthConfig, OAuthService, OAuthEvent } from 'angular-oauth2-oidc';\r\nimport { BehaviorSubject } from 'rxjs';\r\nimport { FrmkConfigStore } from './frmk-config-store.service';\r\n\r\n@Injectable({ \r\n providedIn: 'root'\r\n})\r\nexport class AuthService {\r\n private readonly isAuthenticatedSubject$ = new BehaviorSubject<boolean>(false);\r\n public isAuthenticated$ = this.isAuthenticatedSubject$.asObservable();\r\n\r\n private readonly isDoneLoadingSubject$ = new BehaviorSubject<boolean>(false);\r\n public isDoneLoading$ = this.isDoneLoadingSubject$.asObservable();\r\n\r\n private isInitialLogin = true;\r\n\r\n constructor(\r\n private readonly oauthService: OAuthService,\r\n private readonly router: Router,\r\n private readonly store: FrmkConfigStore\r\n ) {\r\n // IMPORTANTE: Limpiar tokens expirados ANTES de cualquier otra operación\r\n this.clearExpiredTokensOnStartup();\r\n \r\n this.oauthService.events \r\n .subscribe((event) => {\r\n if (event instanceof OAuthEvent) {\r\n if (event.type === 'token_received') {\r\n this.handleSuccessfulAuthentication();\r\n }\r\n if (event.type === 'logout') {\r\n this.handleLogout();\r\n }\r\n if (event.type === 'token_error') {\r\n this.isDoneLoadingSubject$.next(true);\r\n }\r\n if (event.type === 'silently_refreshed') {\r\n this.handleSilentRefresh();\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Limpia tokens expirados al iniciar la aplicación\r\n * Solo limpia si NO estamos en un callback OAuth\r\n */\r\n private clearExpiredTokensOnStartup(): void {\r\n const urlParams = new URLSearchParams(window.location.search);\r\n \r\n // Detectar TODOS los parámetros que indican un callback OAuth\r\n // Keycloak puede enviar: code, state, session_state, iss (RFC 9207)\r\n const isOAuthCallback = urlParams.has('code') || \r\n urlParams.has('iss') || \r\n urlParams.has('session_state') ||\r\n urlParams.has('state') ||\r\n window.location.hash.includes('access_token') ||\r\n window.location.hash.includes('code');\r\n \r\n if (isOAuthCallback) {\r\n console.log('[AuthService] OAuth callback detected, skipping token cleanup');\r\n return;\r\n }\r\n\r\n // Verificar si hay un token y si está expirado\r\n const expiresAt = localStorage.getItem('expires_at') || sessionStorage.getItem('expires_at');\r\n if (expiresAt) {\r\n const expirationTime = parseInt(expiresAt, 10);\r\n const now = Date.now();\r\n \r\n if (expirationTime < now) {\r\n console.log('[AuthService] Expired token detected, clearing storage');\r\n this.clearAllTokens();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Limpia todos los tokens del storage\r\n */\r\n private clearAllTokens(): void {\r\n const keysToRemove = [\r\n 'access_token', 'refresh_token', 'id_token', 'token_type',\r\n 'expires_at', 'nonce', 'PKCE_verifier', 'session_state',\r\n 'id_token_claims_obj', 'id_token_expires_at', 'id_token_stored_at',\r\n 'access_token_stored_at'\r\n ];\r\n \r\n keysToRemove.forEach(key => {\r\n localStorage.removeItem(key);\r\n sessionStorage.removeItem(key);\r\n });\r\n }\r\n\r\n /**\r\n * Limpia tokens antiguos pero MANTIENE state, nonce y PKCE_verifier\r\n * que son necesarios para validar el callback OAuth\r\n */\r\n private clearOldTokensKeepState(): void {\r\n // Solo limpiar tokens, NO state/nonce/PKCE_verifier\r\n const keysToRemove = [\r\n 'access_token', 'refresh_token', 'id_token', 'token_type',\r\n 'expires_at', 'id_token_claims_obj', 'id_token_expires_at', \r\n 'id_token_stored_at', 'access_token_stored_at'\r\n ];\r\n \r\n keysToRemove.forEach(key => {\r\n localStorage.removeItem(key);\r\n sessionStorage.removeItem(key);\r\n });\r\n \r\n console.log('[AuthService] Cleared old tokens, kept state/nonce/PKCE for callback validation');\r\n }\r\n\r\n private handleSuccessfulAuthentication(): void {\r\n if (this.oauthService.hasValidAccessToken()) {\r\n this.isAuthenticatedSubject$.next(true);\r\n this.isDoneLoadingSubject$.next(true);\r\n \r\n // Limpiar parámetros OAuth de la URL para evitar problemas al refrescar\r\n this.cleanupOAuthParams();\r\n \r\n if (this.isInitialLogin) {\r\n this.isInitialLogin = false;\r\n }\r\n } else {\r\n this.isDoneLoadingSubject$.next(true);\r\n }\r\n }\r\n\r\n /**\r\n * Limpia los parámetros OAuth de la URL después del login exitoso\r\n * Esto evita problemas cuando el usuario refresca la página\r\n */\r\n private cleanupOAuthParams(): void {\r\n try {\r\n const url = new URL(window.location.href);\r\n const paramsToRemove = ['code', 'state', 'session_state', 'iss'];\r\n let hasOAuthParams = false;\r\n \r\n paramsToRemove.forEach(param => {\r\n if (url.searchParams.has(param)) {\r\n url.searchParams.delete(param);\r\n hasOAuthParams = true;\r\n }\r\n });\r\n \r\n if (hasOAuthParams) {\r\n // Reemplazar URL sin recargar la página\r\n window.history.replaceState({}, document.title, url.toString());\r\n console.log('[AuthService] OAuth params cleaned from URL');\r\n }\r\n } catch (error) {\r\n console.warn('[AuthService] Error cleaning OAuth params:', error);\r\n }\r\n }\r\n\r\n private handleSilentRefresh(): void {\r\n if (this.oauthService.hasValidAccessToken()) {\r\n this.isAuthenticatedSubject$.next(true);\r\n this.isDoneLoadingSubject$.next(true);\r\n }\r\n }\r\n\r\n private handleLogout(): void {\r\n this.isAuthenticatedSubject$.next(false);\r\n this.isDoneLoadingSubject$.next(true);\r\n }\r\n\r\n /**\r\n * Limpia todos los tokens del storage\r\n */\r\n private clearTokenStorage(): void {\r\n this.oauthService.logOut(true); // true = no redirect, solo limpiar\r\n localStorage.removeItem('access_token');\r\n localStorage.removeItem('refresh_token');\r\n localStorage.removeItem('id_token');\r\n localStorage.removeItem('nonce');\r\n localStorage.removeItem('expires_at');\r\n sessionStorage.removeItem('access_token');\r\n sessionStorage.removeItem('refresh_token');\r\n sessionStorage.removeItem('id_token');\r\n }\r\n\r\n /**\r\n * Verifica si el token actual está expirado\r\n */\r\n private isTokenExpired(): boolean {\r\n const expiresAt = this.oauthService.getAccessTokenExpiration();\r\n if (!expiresAt) {\r\n return false; // Si no hay token, no está \"expirado\", simplemente no existe\r\n }\r\n return expiresAt < Date.now();\r\n }\r\n\r\n private async runInitialLoginSequence(): Promise<void> {\r\n try {\r\n const urlParams = new URLSearchParams(window.location.search);\r\n const hasCode = urlParams.has('code');\r\n const hasState = urlParams.has('state');\r\n const hasIss = urlParams.has('iss');\r\n const hasSessionState = urlParams.has('session_state');\r\n const hasFragment = window.location.hash.includes('access_token') || window.location.hash.includes('code');\r\n \r\n // Detectar si estamos en un callback OAuth (Keycloak envía code, state, session_state, iss)\r\n const isOAuthCallback = hasCode || hasFragment || (hasState && (hasIss || hasSessionState));\r\n\r\n // Si NO estamos en callback OAuth y hay tokens expirados, limpiar y terminar\r\n if (!isOAuthCallback && this.isTokenExpired()) {\r\n console.log('[AuthService] No OAuth callback detected and token expired, clearing storage');\r\n this.clearTokenStorage();\r\n this.isDoneLoadingSubject$.next(true);\r\n return;\r\n }\r\n\r\n // Si estamos en callback OAuth, SIEMPRE limpiar tokens anteriores para evitar conflictos\r\n // Esto es crítico: angular-oauth2-oidc valida tokens existentes antes de procesar el código nuevo\r\n if (isOAuthCallback) {\r\n console.log('[AuthService] OAuth callback detected, clearing old tokens before processing');\r\n // Limpiar solo tokens, NO el state/nonce que necesitamos para validar el callback\r\n this.clearOldTokensKeepState();\r\n \r\n this.isInitialLogin = true;\r\n await this.oauthService.tryLoginCodeFlow();\r\n } \r\n\r\n const hasValidToken = this.oauthService.hasValidAccessToken();\r\n \r\n if (hasValidToken) {\r\n if (!hasCode && !hasFragment) {\r\n this.isInitialLogin = false;\r\n }\r\n this.handleSuccessfulAuthentication();\r\n } else {\r\n this.isDoneLoadingSubject$.next(true);\r\n }\r\n \r\n } catch (error: any) {\r\n console.error('[AuthService] Error during authentication initialization:', error);\r\n \r\n // Si el error es por token expirado, limpiar y permitir nuevo login\r\n if (error?.message?.includes('expired') || error?.reason?.includes('expired')) {\r\n this.clearTokenStorage();\r\n }\r\n \r\n this.isDoneLoadingSubject$.next(true);\r\n } \r\n }\r\n\r\n private setupManualConfiguration(): void {\r\n const authConfig = this.store.authConfig();\r\n this.oauthService.tokenEndpoint = authConfig.tokenEndpoint!;\r\n this.oauthService.userinfoEndpoint = authConfig.userinfoEndpoint!;\r\n this.oauthService.loginUrl = authConfig.loginUrl!;\r\n this.oauthService.logoutUrl = authConfig.logoutUrl!;\r\n this.oauthService.clientId = authConfig.clientId!;\r\n this.oauthService.redirectUri = authConfig.redirectUri!;\r\n this.oauthService.scope = authConfig.scope!;\r\n this.oauthService.responseType = authConfig.responseType!;\r\n }\r\n\r\n public initializeAuth(authConfig: AuthConfig): void {\r\n const urlParams = new URLSearchParams(window.location.search);\r\n const hasCode = urlParams.has('code');\r\n \r\n // Si es callback OAuth, resetear TODO el estado de OAuthService\r\n if (hasCode) {\r\n console.log('[AuthService] OAuth callback detected: resetting OAuthService state');\r\n \r\n // Limpiar storage EXCEPTO state/nonce/PKCE\r\n this.clearOldTokensKeepState();\r\n \r\n // CRÍTICO: Resetear propiedades internas de OAuthService\r\n // para que no valide tokens viejos en memoria\r\n this.resetOAuthServiceInternalState();\r\n } else {\r\n // No es callback - verificar si hay tokens expirados\r\n const expiresAt = localStorage.getItem('expires_at');\r\n const isExpired = expiresAt && parseInt(expiresAt, 10) < Date.now();\r\n \r\n if (isExpired) {\r\n console.log('[AuthService] Clearing all expired tokens before configure');\r\n this.clearAllTokens();\r\n this.resetOAuthServiceInternalState();\r\n }\r\n }\r\n \r\n // Ahora es seguro configurar OAuthService\r\n this.oauthService.configure(authConfig);\r\n this.setupManualConfiguration();\r\n this.runInitialLoginSequence();\r\n }\r\n\r\n /**\r\n * Resetea las propiedades internas de OAuthService\r\n * Esto es necesario porque la librería guarda tokens en memoria\r\n * que no se limpian con localStorage/sessionStorage\r\n */\r\n private resetOAuthServiceInternalState(): void {\r\n try {\r\n const oauth = this.oauthService as any;\r\n oauth._accessToken = null;\r\n oauth._idToken = null;\r\n oauth._idTokenClaims = null;\r\n oauth.idTokenClaimsJson = null;\r\n oauth._refreshToken = null;\r\n console.log('[AuthService] OAuthService internal state reset');\r\n } catch (e) {\r\n console.warn('[AuthService] Could not reset internal state:', e);\r\n }\r\n }\r\n\r\n public getAuthConfig(): AuthConfig {\r\n return this.store.authConfig();\r\n }\r\n\r\n public login(targetUrl?: string): void {\r\n this.isInitialLogin = true;\r\n \r\n if (!this.oauthService.clientId) {\r\n return;\r\n }\r\n if (!this.oauthService.redirectUri) {\r\n return;\r\n }\r\n\r\n this.oauthService.initLoginFlow(targetUrl || undefined);\r\n }\r\n\r\n public async logout(): Promise<void> {\r\n try {\r\n await this.callKeycloakLogoutEndpoint().catch(err => {\r\n console.warn('Keycloak logout endpoint failed, but will continue with local cleanup:', err);\r\n });\r\n \r\n this.performLocalLogout();\r\n \r\n } catch (error) {\r\n console.error('Error during logout:', error);\r\n this.performLocalLogout();\r\n }\r\n }\r\n\r\n private async callKeycloakLogoutEndpoint(): Promise<void> {\r\n const authConfig = this.store.authConfig();\r\n const logoutUrl = authConfig.logoutUrl;\r\n \r\n let refreshToken: string | null = this.oauthService.getRefreshToken();\r\n \r\n if (!refreshToken) {\r\n refreshToken = localStorage.getItem('refresh_token') \r\n || localStorage.getItem('refresh_token_' + authConfig.clientId)\r\n || sessionStorage.getItem('refresh_token');\r\n }\r\n \r\n if (!logoutUrl) {\r\n console.warn('Logout URL not configured, skipping Keycloak logout');\r\n return;\r\n }\r\n\r\n if (!refreshToken) {\r\n console.warn('No refresh token found, logout endpoint may fail');\r\n }\r\n\r\n const body = new URLSearchParams();\r\n body.set('client_id', authConfig.clientId!);\r\n \r\n if (refreshToken) {\r\n body.set('refresh_token', refreshToken);\r\n }\r\n\r\n const headers: HeadersInit = {\r\n 'Content-Type': 'application/x-www-form-urlencoded'\r\n };\r\n\r\n try {\r\n const response = await fetch(logoutUrl, {\r\n method: 'POST',\r\n headers,\r\n body: body.toString()\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text();\r\n console.warn('Keycloak logout returned error, but local cleanup completed:', errorText);\r\n }\r\n } catch (error) {\r\n console.warn('Failed to call Keycloak logout endpoint:', error);\r\n }\r\n }\r\n\r\n private performLocalLogout(): void {\r\n this.oauthService.logOut(true);\r\n \r\n // Limpiar tokens del localStorage\r\n localStorage.removeItem('access_token');\r\n localStorage.removeItem('id_token');\r\n localStorage.removeItem('refresh_token');\r\n localStorage.removeItem('code_verifier');\r\n localStorage.removeItem('nonce');\r\n localStorage.removeItem('PKCE_verifier');\r\n \r\n // Limpiar tokens del sessionStorage\r\n sessionStorage.removeItem('access_token');\r\n sessionStorage.removeItem('id_token');\r\n sessionStorage.removeItem('refresh_token');\r\n sessionStorage.removeItem('nonce');\r\n sessionStorage.removeItem('PKCE_verifier');\r\n \r\n this.isAuthenticatedSubject$.next(false);\r\n this.isDoneLoadingSubject$.next(true);\r\n \r\n const currentUrl = this.router.url;\r\n if (currentUrl !== '/login' && !currentUrl.includes('/login')) {\r\n this.router.navigate(['/login']);\r\n }\r\n }\r\n\r\n public logoutAndRedirect(targetUrl: string = '/login'): void {\r\n this.logout();\r\n this.router.navigate([targetUrl]);\r\n }\r\n\r\n public hasValidToken(): boolean {\r\n return this.oauthService.hasValidAccessToken();\r\n }\r\n\r\n public get identityClaims(): any {\r\n return this.oauthService.getIdentityClaims();\r\n }\r\n\r\n public get accessToken(): string {\r\n return this.oauthService.getAccessToken();\r\n }\r\n\r\n public getUserRoles(): string[] {\r\n const claims = this.identityClaims;\r\n if (claims?.roles) {\r\n return Array.isArray(claims.roles) ? claims.roles : [claims.roles];\r\n }\r\n \r\n if (claims) {\r\n const roles: string[] = [];\r\n \r\n if (claims.realm_access?.roles) {\r\n roles.push(...claims.realm_access.roles);\r\n }\r\n \r\n const authConfig = this.store.authConfig();\r\n if (claims.resource_access?.[authConfig.clientId!]?.roles) {\r\n roles.push(...claims.resource_access[authConfig.clientId!].roles);\r\n }\r\n \r\n return roles;\r\n }\r\n return [];\r\n }\r\n\r\n public hasRole(role: string): boolean {\r\n return this.getUserRoles().includes(role);\r\n }\r\n\r\n public hasAnyRole(roles: string[]): boolean {\r\n const userRoles = this.getUserRoles();\r\n return roles.some(role => userRoles.includes(role));\r\n }\r\n\r\n public getUserGroups(): string[] {\r\n const claims = this.identityClaims;\r\n const groups: string[] = [];\r\n\r\n // First, try to get groups from identity claims (ID token)\r\n if (claims) {\r\n if (claims.groups) {\r\n if (Array.isArray(claims.groups)) {\r\n groups.push(...claims.groups);\r\n } else {\r\n groups.push(claims.groups);\r\n }\r\n }\r\n\r\n if (claims.accessTokenGroups) {\r\n if (Array.isArray(claims.accessTokenGroups)) {\r\n groups.push(...claims.accessTokenGroups);\r\n } else {\r\n groups.push(claims.accessTokenGroups);\r\n }\r\n }\r\n\r\n if (claims.realm_access?.groups) {\r\n groups.push(...claims.realm_access.groups);\r\n }\r\n }\r\n\r\n // If no groups found in ID token, try to decode access token\r\n if (groups.length === 0) {\r\n const accessToken = this.accessToken;\r\n if (accessToken) {\r\n try {\r\n const payload = this.decodeJwtPayload(accessToken);\r\n console.log('[AuthService] Access token payload:', payload);\r\n\r\n // Extract groups from access token\r\n if (payload.groups) {\r\n if (Array.isArray(payload.groups)) {\r\n groups.push(...payload.groups);\r\n } else {\r\n groups.push(payload.groups);\r\n }\r\n }\r\n\r\n // Also check realm_access.roles as groups (Keycloak pattern)\r\n if (payload.realm_access?.roles) {\r\n groups.push(...payload.realm_access.roles);\r\n }\r\n\r\n // Check resource_access for client-specific roles\r\n if (payload.resource_access) {\r\n Object.values(payload.resource_access).forEach((resource: any) => {\r\n if (resource.roles && Array.isArray(resource.roles)) {\r\n groups.push(...resource.roles);\r\n }\r\n });\r\n }\r\n } catch (error) {\r\n console.error('[AuthService] Error decoding access token:', error);\r\n }\r\n }\r\n }\r\n\r\n const uniqueGroups = [...new Set(groups)];\r\n console.log('[AuthService] getUserGroups result:', uniqueGroups);\r\n return uniqueGroups;\r\n }\r\n\r\n private decodeJwtPayload(token: string): any {\r\n try {\r\n const parts = token.split('.');\r\n if (parts.length !== 3) {\r\n throw new Error('Invalid JWT format');\r\n }\r\n const payload = parts[1];\r\n const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));\r\n return JSON.parse(decoded);\r\n } catch (error) {\r\n console.error('[AuthService] Failed to decode JWT:', error);\r\n return {};\r\n }\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { firstValueFrom } from 'rxjs';\r\nimport { AppConfiguration, ConfigServerResponse } from '../models/app-config.interface';\r\nimport { FrmkConfigStore } from './frmk-config-store.service';\r\n\r\n@Injectable({ \r\n providedIn: 'root' \r\n})\r\nexport class ConfigService {\r\n private configServerData: ConfigServerResponse | null = null;\r\n private isLoaded = false;\r\n\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly store: FrmkConfigStore\r\n ) {}\r\n\r\n /**\r\n * Carga la configuración desde el config-server\r\n */\r\n async loadConfig(): Promise<void> {\r\n try {\r\n const appConfig = this.store.appConfig();\r\n const url = `${appConfig.configServer.url}/${appConfig.configServer.frontend}`;\r\n \r\n this.configServerData = await firstValueFrom(\r\n this.http.get<ConfigServerResponse>(url)\r\n );\r\n \r\n // Aplicar datos del server al store — todos los computeds se recalculan automáticamente\r\n this.store.applyServerConfig(this.configServerData);\r\n \r\n this.isLoaded = true;\r\n } catch (error) {\r\n console.log(`Exception while loading config: ${error}`);\r\n this.store.applyServerConfig();\r\n this.isLoaded = true;\r\n }\r\n }\r\n\r\n /**\r\n * Obtiene un valor de configuración por clave del config server\r\n */\r\n get(key: string): string | boolean | undefined {\r\n return this.configServerData?.[key as keyof ConfigServerResponse];\r\n }\r\n\r\n /**\r\n * Obtiene toda la configuración del config server\r\n */\r\n getAll(): ConfigServerResponse | null {\r\n return this.configServerData ? { ...this.configServerData } : null;\r\n }\r\n\r\n /**\r\n * Verifica si la configuración ha sido cargada\r\n */\r\n isConfigLoaded(): boolean {\r\n return this.isLoaded;\r\n }\r\n\r\n /**\r\n * Obtiene la configuración final de la aplicación (con valores del config server aplicados)\r\n */\r\n getAppConfig(): AppConfiguration {\r\n return this.store.appConfig();\r\n }\r\n\r\n /**\r\n * Obtiene los datos raw del config server\r\n */\r\n getConfigServerData(): ConfigServerResponse | null {\r\n return this.configServerData;\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';\r\nimport { Observable, of } from 'rxjs';\r\nimport { catchError, map } from 'rxjs/operators';\r\nimport { AuthService } from './authentication.service';\r\nimport { ConfigService } from './config.service';\r\nimport { AuthorizationRequest, AuthorizationResponse, MenuHierarchyItem } from '../models/authorization.interface';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class AuthorizationService {\r\n\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly authService: AuthService,\r\n private readonly configService: ConfigService\r\n ) {}\r\n\r\n /**\r\n * Verifica si el usuario tiene permisos para acceder a un recurso específico\r\n */\r\n verifyPermission(resourcePath: string, operationName: string = 'VIEW'): Observable<boolean> {\r\n const groups = this.getUserGroups();\r\n const config = this.configService.getAppConfig();\r\n \r\n if (groups.length === 0) {\r\n return of(false);\r\n }\r\n\r\n const request: AuthorizationRequest = {\r\n groupIds: groups,\r\n componentId: config.configServer.frontend,\r\n resourcePath: resourcePath,\r\n operationName: operationName\r\n };\r\n\r\n return this.checkAuthorization(request);\r\n }\r\n\r\n /**\r\n * Realiza la llamada HTTP al servicio de autorización\r\n */\r\n private checkAuthorization(request: AuthorizationRequest): Observable<boolean> {\r\n let params = new HttpParams();\r\n \r\n const cleanGroups = request.groupIds.map(group => group.replace(/\\//g, ''));\r\n const groupIdsString = cleanGroups.join(',');\r\n \r\n params = params.set('groupIds', groupIdsString);\r\n params = params.set('componentId', request.componentId);\r\n params = params.set('resourcePath', request.resourcePath);\r\n params = params.set('operationName', request.operationName);\r\n\r\n let headers = new HttpHeaders();\r\n\r\n const url = `${this.configService.getAppConfig().authorization.baseUrl}${this.configService.getAppConfig().authorization.verifyEndpoint}`;\r\n\r\n return this.http.get<AuthorizationResponse>(url, { \r\n params,\r\n headers\r\n }).pipe(\r\n map(response => {\r\n return response.hasPermission;\r\n }),\r\n catchError(() => {\r\n return of(false);\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Obtiene los grupos del usuario desde el access token\r\n */\r\n private getUserGroups(): string[] {\r\n return this.authService.getUserGroups();\r\n }\r\n\r\n /** \r\n * Método público para obtener los grupos del usuario (útil para debugging)\r\n */\r\n public getUserGroupsDebug(): string[] {\r\n return this.authService.getUserGroups();\r\n }\r\n\r\n /**\r\n * Obtiene la jerarquía de menús basada en el componente y los grupos del usuario\r\n */\r\n getMenuHierarchy(): Observable<MenuHierarchyItem[]> {\r\n const groups = this.getUserGroups();\r\n const config = this.configService.getAppConfig();\r\n \r\n if (groups.length === 0) {\r\n return of([]);\r\n }\r\n\r\n const cleanGroups = groups.map(group => group.replace(/\\//g, ''));\r\n const groupIdsString = cleanGroups.join(',');\r\n\r\n let params = new HttpParams();\r\n params = params.set('componentId', config.configServer.frontend);\r\n params = params.set('groupIds', groupIdsString);\r\n\r\n let headers = new HttpHeaders();\r\n\r\n const url = `${config.authorization.baseUrl}${config.authorization.hierarchyEndpoint}`;\r\n\r\n return this.http.get<MenuHierarchyItem[]>(url, { \r\n params,\r\n headers\r\n }).pipe(\r\n catchError(error => {\r\n console.error('Error obteniendo jerarquía de menús:', error);\r\n return of([]);\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Obtiene elementos de menú de nivel raíz (level 1)\r\n */\r\n getRootMenuItems(menuHierarchy: MenuHierarchyItem[]): MenuHierarchyItem[] {\r\n return menuHierarchy.filter(item => item.level === 1);\r\n }\r\n\r\n /**\r\n * Obtiene elementos hijos de un elemento padre específico por path\r\n */\r\n getChildMenuItems(menuHierarchy: MenuHierarchyItem[], parentPath: string, level: number): MenuHierarchyItem[] {\r\n return menuHierarchy.filter(item => \r\n item.level === level && \r\n item.hasParent && \r\n item.path.startsWith(parentPath) &&\r\n item.path !== parentPath &&\r\n this.isDirectChild(item.path, parentPath, level)\r\n );\r\n }\r\n\r\n /**\r\n * Verifica si un elemento tiene hijos\r\n */\r\n hasChildren(menuHierarchy: MenuHierarchyItem[], item: MenuHierarchyItem): boolean {\r\n return this.getChildMenuItems(menuHierarchy, item.path, item.level + 1).length > 0;\r\n }\r\n\r\n /**\r\n * Verifica si un path es hijo directo de otro path\r\n */\r\n private isDirectChild(childPath: string, parentPath: string, expectedLevel: number): boolean {\r\n const relativePath = childPath.substring(parentPath.length);\r\n const slashCount = (relativePath.match(/\\//g) || []).length;\r\n return slashCount === 1;\r\n }\r\n\r\n /**\r\n * Verifica múltiples permisos a la vez\r\n */\r\n verifyMultiplePermissions(permissions: { resourcePath: string, operationName?: string }[]): Observable<{ [key: string]: boolean }> {\r\n const results: { [key: string]: boolean } = {};\r\n const observables = permissions.map(permission => \r\n this.verifyPermission(permission.resourcePath, permission.operationName).pipe(\r\n map(authorized => ({ \r\n key: `${permission.resourcePath}_${permission.operationName || 'VIEW'}`, \r\n authorized \r\n }))\r\n )\r\n );\r\n\r\n return new Observable(observer => {\r\n let completed = 0;\r\n observables.forEach(obs => {\r\n obs.subscribe(result => {\r\n results[result.key] = result.authorized;\r\n completed++;\r\n if (completed === observables.length) {\r\n observer.next(results);\r\n observer.complete();\r\n }\r\n });\r\n });\r\n });\r\n }\r\n}\r\n","import { inject } from '@angular/core';\r\nimport { CanActivateFn, Router } from '@angular/router';\r\nimport { AuthService } from '../services/authentication.service';\r\nimport { map, take } from 'rxjs/operators';\r\n\r\nexport const authGuard: CanActivateFn = (route, state) => {\r\n const authService = inject(AuthService);\r\n const router = inject(Router);\r\n\r\n const handleAuthenticated = (): boolean => {\r\n return true;\r\n };\r\n\r\n const handleUnauthenticated = (currentUrl: string): boolean => {\r\n if (currentUrl !== '/login' && !currentUrl.includes('/login')) {\r\n router.navigate(['/login'], { \r\n queryParams: { returnUrl: currentUrl } \r\n });\r\n }\r\n return false;\r\n }; \r\n\r\n return authService.isAuthenticated$.pipe(\r\n take(1),\r\n map(isAuthenticated => {\r\n return isAuthenticated \r\n ? handleAuthenticated() \r\n : handleUnauthenticated(state.url);\r\n })\r\n );\r\n};\r\n","import { Component, OnInit, OnDestroy, input, computed, inject } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { Subscription } from 'rxjs';\r\nimport { AuthService } from '../../services/authentication.service';\r\nimport { FrmkConfigStore } from '../../services/frmk-config-store.service';\r\nimport { LoginConfig, DEFAULT_LOGIN_CONFIG } from '../../models/login-config.interface';\r\nimport { VERSION } from '../../version';\r\n\r\n@Component({\r\n selector: 'lib-login',\r\n standalone: true,\r\n imports: [CommonModule],\r\n templateUrl: './login.component.html',\r\n styleUrls: ['./login.component.scss']\r\n})\r\nexport class LoginComponent implements OnInit, OnDestroy {\r\n /**\r\n * Configuration object to customize the login component appearance and behavior\r\n */\r\n readonly config = input<Partial<LoginConfig>>({});\r\n\r\n private readonly store = inject(FrmkConfigStore);\r\n\r\n isLoggingIn = false;\r\n statusMessage = '';\r\n private authSubscription?: Subscription;\r\n private isProcessingCallback = false;\r\n\r\n /** Configuración merged: defaults ← libraryConfig.loginConfig ← @Input config */\r\n readonly mergedConfig = computed<LoginConfig>(() => {\r\n const storeConfig = this.store.isConfigured()\r\n ? this.store.loginConfig()\r\n : DEFAULT_LOGIN_CONFIG;\r\n const inputCfg = this.config() ?? {};\r\n return {\r\n ...storeConfig,\r\n ...inputCfg,\r\n version: inputCfg.version || storeConfig.version || VERSION\r\n };\r\n });\r\n\r\n constructor(public authService: AuthService) {}\r\n\r\n ngOnInit() {\r\n // Check if processing OAuth callback\r\n // Also check for 'iss' and 'session_state' which indicate we came from OAuth even if 'code' was already processed\r\n const urlParams = new URLSearchParams(globalThis.location?.search || '');\r\n const hasCode = urlParams.has('code');\r\n const hasIss = urlParams.has('iss');\r\n const hasSessionState = urlParams.has('session_state');\r\n const hasFragment = (globalThis.location?.hash || '').includes('access_token') || \r\n (globalThis.location?.hash || '').includes('code');\r\n \r\n if (hasCode || hasFragment || hasIss || hasSessionState) {\r\n this.isProcessingCallback = true;\r\n this.statusMessage = 'Procesando autenticación...';\r\n }\r\n\r\n // Subscribe to authentication state changes\r\n this.authSubscription = this.authService.isAuthenticated$.subscribe(isAuthenticated => {\r\n if (isAuthenticated) {\r\n this.statusMessage = '¡Autenticación exitosa! Redirigiendo...';\r\n // Small delay to show success message, then redirect\r\n setTimeout(() => {\r\n this.navigateToRedirect();\r\n }, 500);\r\n }\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n if (this.authSubscription) {\r\n this.authSubscription.unsubscribe();\r\n }\r\n }\r\n\r\n /**\r\n * Get merged configuration value\r\n */\r\n getConfig<K extends keyof LoginConfig>(key: K): LoginConfig[K] {\r\n return this.mergedConfig()[key];\r\n }\r\n\r\n /**\r\n * Get custom CSS styles for theming\r\n */\r\n getCustomStyles(): { [key: string]: string } {\r\n const styles: { [key: string]: string } = {};\r\n const cfg = this.mergedConfig();\r\n \r\n if (cfg.primaryColor) {\r\n styles['--color-primary'] = cfg.primaryColor;\r\n }\r\n if (cfg.backgroundColor) {\r\n styles['--login-bg-color'] = cfg.backgroundColor;\r\n }\r\n if (cfg.textColor) {\r\n styles['--login-text-color'] = cfg.textColor;\r\n }\r\n \r\n return styles;\r\n }\r\n\r\n login(): void {\r\n this.isLoggingIn = true;\r\n this.statusMessage = 'Redirigiendo al proveedor de autenticación...';\r\n \r\n setTimeout(() => {\r\n this.authService.login();\r\n }, 500);\r\n }\r\n\r\n logout(): void {\r\n this.authService.logout();\r\n this.isLoggingIn = false;\r\n this.statusMessage = '';\r\n this.isProcessingCallback = false;\r\n }\r\n\r\n goToDashboard(): void {\r\n this.navigateToRedirect();\r\n }\r\n\r\n private navigateToRedirect(): void {\r\n const redirectUrl = this.mergedConfig().redirectUrl;\r\n if (typeof globalThis.location !== 'undefined') {\r\n const baseUrl = `${globalThis.location.protocol}//${globalThis.location.host}`;\r\n globalThis.location.href = `${baseUrl}${redirectUrl}`;\r\n }\r\n }\r\n}\r\n","<div class=\"login-page\" [ngStyle]=\"getCustomStyles()\">\r\n <div class=\"login-page__container\">\r\n <!-- Logo -->\r\n <div class=\"login-page__logo\">\r\n <img \r\n [src]=\"getConfig('logoUrl')\" \r\n [alt]=\"getConfig('logoAlt')\" \r\n class=\"login-page__logo-img\"\r\n [style.width]=\"getConfig('logoWidth')\"\r\n [style.height]=\"getConfig('logoHeight')\" />\r\n </div>\r\n\r\n <!-- Header -->\r\n <div class=\"login-page__header\">\r\n <h1>{{ getConfig('title') }}</h1>\r\n <p *ngIf=\"getConfig('subtitle')\" class=\"subtitle\">{{ getConfig('subtitle') }}</p>\r\n </div>\r\n \r\n <!-- Login Form -->\r\n <div *ngIf=\"(authService.isDoneLoading$ | async)\" class=\"login-page__form\">\r\n <div *ngIf=\"!(authService.isAuthenticated$ | async)\">\r\n <!-- Status Message -->\r\n <div *ngIf=\"statusMessage\" class=\"auth-alert auth-alert--info\">\r\n <div class=\"auth-alert__content\">\r\n <p>{{ statusMessage }}</p>\r\n </div>\r\n </div>\r\n\r\n <!-- Login Button -->\r\n <button \r\n class=\"btn btn--primary btn--lg\" \r\n (click)=\"login()\" \r\n [disabled]=\"isLoggingIn\"\r\n [class.loading]=\"isLoggingIn\">\r\n {{ isLoggingIn ? 'Redirigiendo...' : getConfig('loginButtonText') }}\r\n </button>\r\n\r\n <!-- Footer -->\r\n <div class=\"login-page__footer\" *ngIf=\"getConfig('showFooter')\">\r\n <p *ngIf=\"getConfig('footerText'); else defaultFooter\">\r\n {{ getConfig('footerText') }}\r\n </p>\r\n <ng-template #defaultFooter>\r\n <p>\r\n Acceso seguro para usuarios de \r\n <strong>{{ getConfig('institutionName') }}</strong>\r\n </p>\r\n </ng-template>\r\n </div>\r\n </div>\r\n \r\n <!-- Already Authenticated -->\r\n <div *ngIf=\"authService.isAuthenticated$ | async\" class=\"auth-alert auth-alert--success\">\r\n <div class=\"auth-alert__content\">\r\n <h4>¡Sesión activa!</h4>\r\n <p>Ya tienes una sesión iniciada en el sistema.</p>\r\n </div>\r\n \r\n <div class=\"login-page__actions\">\r\n <button class=\"btn btn--primary btn--lg\" (click)=\"goToDashboard()\">\r\n {{ getConfig('dashboardButtonText') }}\r\n </button>\r\n \r\n <button \r\n *ngIf=\"getConfig('showLogoutButton')\"\r\n class=\"btn btn--secondary btn--lg\" \r\n (click)=\"logout()\">\r\n {{ getConfig('logoutButtonText') }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- Loading State -->\r\n <div *ngIf=\"!(authService.isDoneLoading$ | async)\" class=\"auth-loading\">\r\n <div class=\"auth-loading__spinner\"></div>\r\n <p class=\"auth-loading__text\">Procesando autenticación...</p>\r\n </div>\r\n\r\n <!-- Version -->\r\n <div *ngIf=\"getConfig('showVersion')\" class=\"login-page__version\">\r\n <span>v{{ getConfig('version') }}</span>\r\n </div>\r\n </div>\r\n</div>\r\n","import { Component, OnInit, HostListener, input, computed, inject } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { RouterModule } from '@angular/router';\r\nimport { AuthService } from '../../services/authentication.service';\r\nimport { AuthorizationService } from '../../services/authorization.service';\r\nimport { FrmkConfigStore } from '../../services/frmk-config-store.service';\r\nimport { MenuHierarchyItem } from '../../models/authorization.interface';\r\nimport { DashboardConfig, DEFAULT_DASHBOARD_CONFIG } from '../../models/dashboard-config.interface';\r\nimport { VERSION } from '../../version';\r\n\r\n// Re-export for backwards compatibility\r\nexport { DashboardConfig } from '../../models/dashboard-config.interface';\r\n\r\n@Component({\r\n selector: 'lib-dashboard',\r\n standalone: true,\r\n imports: [CommonModule, RouterModule],\r\n templateUrl: './dashboard.component.html',\r\n styleUrls: ['./dashboard.component.scss']\r\n})\r\nexport class DashboardComponent implements OnInit {\r\n readonly config = input<Partial<DashboardConfig>>({});\r\n\r\n private readonly store = inject(FrmkConfigStore);\r\n\r\n userInfo: any = null;\r\n userRoles: string[] = [];\r\n menuHierarchy: MenuHierarchyItem[] = [];\r\n isMenuOpen = false;\r\n isLoadingMenu = false;\r\n openMenuItems: Set<string> = new Set();\r\n isUserPanelOpen = false;\r\n isMobileMenuOpen = false;\r\n\r\n /** Configuración merged: defaults ← libraryConfig.dashboardConfig ← @Input config */\r\n readonly mergedConfig = computed<DashboardConfig>(() => {\r\n const storeConfig = this.store.isConfigured()\r\n ? this.store.dashboardConfig()\r\n : DEFAULT_DASHBOARD_CONFIG;\r\n const inputCfg = this.config() ?? {};\r\n return {\r\n ...storeConfig,\r\n ...inputCfg,\r\n version: inputCfg.version || storeConfig.version || VERSION\r\n };\r\n });\r\n\r\n constructor(\r\n public authService: AuthService,\r\n private readonly authorizationService: AuthorizationService\r\n ) {}\r\n\r\n ngOnInit(): void {\r\n this.loadUserInfo();\r\n this.loadMenuHierarchy();\r\n }\r\n\r\n getConfig<K extends keyof DashboardConfig>(key: K): DashboardConfig[K] {\r\n return this.mergedConfig()[key];\r\n }\r\n\r\n get appVersion(): string {\r\n return this.mergedConfig().version;\r\n }\r\n\r\n private loadUserInfo(): void {\r\n this.userInfo = this.authService.identityClaims;\r\n this.userRoles = this.authService.getUserRoles();\r\n }\r\n\r\n private loadMenuHierarchy(): void {\r\n this.isLoadingMenu = true;\r\n this.authorizationService.getMenuHierarchy().subscribe({\r\n next: (menuItems) => {\r\n this.menuHierarchy = this.buildHierarchicalMenu(menuItems);\r\n this.isLoadingMenu = false;\r\n },\r\n error: (error) => {\r\n console.error('Error loading menu hierarchy:', error);\r\n this.menuHierarchy = [];\r\n this.isLoadingMenu = false;\r\n }\r\n });\r\n }\r\n\r\n private buildHierarchicalMenu(flatItems: MenuHierarchyItem[]): MenuHierarchyItem[] {\r\n const itemMap = new Map<string, MenuHierarchyItem>();\r\n \r\n flatItems.forEach(item => {\r\n itemMap.set(item.path, { ...item, children: [] });\r\n });\r\n\r\n const rootItems: MenuHierarchyItem[] = [];\r\n \r\n flatItems.forEach(item => {\r\n const currentItem = itemMap.get(item.path)!;\r\n \r\n if (item.level === 1) {\r\n rootItems.push(currentItem);\r\n } else {\r\n const parent = this.findParent(item, flatItems);\r\n if (parent) {\r\n const parentItem = itemMap.get(parent.path);\r\n if (parentItem?.children) {\r\n parentItem.children.push(currentItem);\r\n }\r\n }\r\n }\r\n });\r\n\r\n return rootItems;\r\n }\r\n\r\n private findParent(item: MenuHierarchyItem, allItems: MenuHierarchyItem[]): MenuHierarchyItem | null {\r\n for (const potentialParent of allItems) {\r\n if (potentialParent.level === item.level - 1 && \r\n item.path.startsWith(potentialParent.path) &&\r\n item.path !== potentialParent.path) {\r\n return potentialParent;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n toggleMenuItem(itemId: string, item: MenuHierarchyItem): void {\r\n const isCurrentlyOpen = this.openMenuItems.has(itemId);\r\n \r\n if (isCurrentlyOpen) {\r\n this.closeMenuAndChildren(itemId);\r\n } else {\r\n this.closeSiblingMenus(item);\r\n this.openMenuItems.add(itemId);\r\n }\r\n }\r\n\r\n private closeMenuAndChildren(itemId: string): void {\r\n this.openMenuItems.delete(itemId);\r\n const itemsToClose = Array.from(this.openMenuItems).filter(id => id.startsWith(itemId + '-'));\r\n itemsToClose.forEach(id => this.openMenuItems.delete(id));\r\n }\r\n\r\n private closeSiblingMenus(currentItem: MenuHierarchyItem): void {\r\n if (currentItem.level === 1) {\r\n const rootItems = this.getRootMenuItems();\r\n rootItems.forEach(rootItem => {\r\n if (rootItem.code !== currentItem.code) {\r\n this.closeMenuAndChildren(rootItem.code);\r\n }\r\n });\r\n } else {\r\n const allItems = this.flattenMenuItems(this.menuHierarchy);\r\n const parent = this.findParent(currentItem, allItems);\r\n if (parent?.children) {\r\n parent.children.forEach(sibling => {\r\n if (sibling.code !== currentItem.code) {\r\n this.closeMenuAndChildren(sibling.code);\r\n }\r\n });\r\n }\r\n }\r\n }\r\n\r\n private flattenMenuItems(items: MenuHierarchyItem[]): MenuHierarchyItem[] {\r\n const flattened: MenuHierarchyItem[] = [];\r\n \r\n const flatten = (itemList: MenuHierarchyItem[]) => {\r\n itemList.forEach(item => {\r\n flattened.push(item);\r\n if (item.children) {\r\n flatten(item.children);\r\n }\r\n });\r\n };\r\n \r\n flatten(items);\r\n return flattened;\r\n }\r\n\r\n onMenuItemClick(event: Event, item: MenuHierarchyItem): void {\r\n if (this.hasChildren(item)) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.toggleMenuItem(item.code, item);\r\n } else {\r\n // Close mobile menu when navigating to a page\r\n this.closeMobileMenu();\r\n }\r\n }\r\n\r\n @HostListener('document:click', ['$event'])\r\n onDocumentClick(event: Event): void {\r\n const target = event.target as HTMLElement;\r\n const navElement = target.closest('.dashboard-nav');\r\n const userPanel = target.closest('.user-profile');\r\n \r\n if (!navElement) {\r\n this.openMenuItems.clear();\r\n }\r\n \r\n if (!userPanel) {\r\n this.isUserPanelOpen = false;\r\n }\r\n }\r\n\r\n toggleUserPanel(event: Event): void {\r\n event.stopPropagation();\r\n this.isUserPanelOpen = !this.isUserPanelOpen;\r\n }\r\n\r\n getUsername(): string {\r\n if (!this.userInfo?.preferred_username) return 'usuario';\r\n const username = this.userInfo.preferred_username;\r\n const atIndex = username.indexOf('@');\r\n return atIndex > 0 ? username.substring(0, atIndex) : username;\r\n }\r\n\r\n getUserFullName(): string {\r\n return this.userInfo?.name || 'Usuario';\r\n }\r\n\r\n getDocument(): string {\r\n return this.userInfo?.dui || 'N/A';\r\n }\r\n\r\n getInstitution(): string {\r\n return this.userInfo?.direccion || 'N/A';\r\n }\r\n\r\n getDependency(): string {\r\n return this.userInfo?.dependencia || 'N/A';\r\n }\r\n\r\n getRole(): string {\r\n return this.userInfo?.cargo || 'N/A';\r\n }\r\n\r\n isMenuItemOpen(itemId: string): boolean {\r\n return this.openMenuItems.has(itemId);\r\n }\r\n\r\n hasChildren(item: MenuHierarchyItem): boolean {\r\n return !!(item.children && item.children.length > 0);\r\n }\r\n\r\n getRootMenuItems(): MenuHierarchyItem[] {\r\n return this.menuHierarchy.filter(item => item.level === 1);\r\n }\r\n\r\n /**\r\n * Obtiene el icono para un item del menú.\r\n * Si el item tiene un icono definido, lo usa; de lo contrario, usa un icono por defecto según el nivel.\r\n */\r\n getMenuIcon(item: MenuHierarchyItem): string {\r\n // Si tiene icono definido, usarlo\r\n if (item.icono && item.icono.trim() !== '') {\r\n return item.icono;\r\n }\r\n \r\n // Iconos por defecto según el nivel\r\n if (item.level === 1) {\r\n return 'folder';\r\n } else if (item.level === 2) {\r\n return 'article';\r\n } else {\r\n return 'radio_button_unchecked';\r\n }\r\n }\r\n\r\n logoutAndRedirect(): void {\r\n this.authService.logoutAndRedirect();\r\n }\r\n\r\n getUserInitials(): string {\r\n if (!this.userInfo) return 'U';\r\n \r\n const name = this.userInfo.name || this.userInfo.preferred_username || 'Usuario';\r\n const words = name.split(' ');\r\n \r\n if (words.length >= 2) {\r\n return (words[0][0] + words[1][0]).toUpperCase();\r\n } else {\r\n return name.substring(0, 2).toUpperCase();\r\n }\r\n }\r\n\r\n toggleMobileMenu(): void {\r\n this.isMobileMenuOpen = !this.isMobileMenuOpen;\r\n }\r\n\r\n closeMobileMenu(): void {\r\n this.isMobileMenuOpen = false;\r\n document.body.style.overflow = '';\r\n }\r\n}\r\n","<div class=\"dashboard\">\r\n <!-- Header -->\r\n <header class=\"dashboard-header\">\r\n <!-- Mobile Header Top -->\r\n <div class=\"header-mobile-top\">\r\n <div class=\"ministry-logo-mobile\">\r\n <img [src]=\"getConfig('logoUrl')\" [alt]=\"getConfig('logoAlt')\" />\r\n </div>\r\n <h1 class=\"mobile-title\">{{ getConfig('title') }}</h1>\r\n </div>\r\n\r\n <!-- Mobile Header Bottom -->\r\n <div class=\"header-mobile-bottom\">\r\n <button class=\"hamburger-btn\" \r\n (click)=\"toggleMobileMenu()\"\r\n [class.active]=\"isMobileMenuOpen\"\r\n aria-label=\"Toggle menu\">\r\n <span class=\"hamburger-line\"></span>\r\n <span class=\"hamburger-line\"></span>\r\n <span class=\"hamburger-line\"></span>\r\n </button>\r\n\r\n <div class=\"user-profile mobile-user\" *ngIf=\"userInfo\">\r\n <button class=\"user-info-trigger\" \r\n (click)=\"toggleUserPanel($event)\"\r\n [attr.aria-expanded]=\"isUserPanelOpen\"\r\n aria-label=\"Abrir menú de usuario\">\r\n <div class=\"user-avatar\">\r\n <span>{{ getUserInitials() }}</span>\r\n </div>\r\n <div class=\"user-details\">\r\n <span class=\"user-name\">{{ getUsername() }}</span>\r\n </div>\r\n <span class=\"material-symbols-outlined dropdown-icon\">\r\n {{ isUserPanelOpen ? 'expand_less' : 'expand_more' }}\r\n </span>\r\n </button>\r\n \r\n <!-- User Panel -->\r\n <ng-container *ngTemplateOutlet=\"userPanelTemplate\"></ng-container>\r\n </div>\r\n </div>\r\n\r\n <!-- Desktop Header -->\r\n <div class=\"header-desktop-layout\">\r\n <div class=\"header-left\">\r\n <div class=\"ministry-logo\">\r\n <div class=\"logo-icon\">\r\n <img [src]=\"getConfig('logoUrl')\" [alt]=\"getConfig('logoAlt')\" />\r\n </div>\r\n <div class=\"ministry-info\">\r\n <h1>{{ getConfig('title') }}</h1>\r\n <span class=\"subtitle\" *ngIf=\"getConfig('subtitle')\">{{ getConfig('subtitle') }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <div class=\"header-right\">\r\n <div class=\"user-profile desktop-user\" *ngIf=\"userInfo\">\r\n <button class=\"user-info-trigger\" \r\n (click)=\"toggleUserPanel($event)\"\r\n [attr.aria-expanded]=\"isUserPanelOpen\"\r\n aria-label=\"Abrir menú de usuario\">\r\n <div class=\"user-avatar\">\r\n <span>{{ getUserInitials() }}</span>\r\n </div>\r\n <div class=\"user-details\">\r\n <span class=\"user-name\">{{ getUsername() }}</span>\r\n </div>\r\n <span class=\"material-symbols-outlined dropdown-icon\">\r\n {{ isUserPanelOpen ? 'expand_less' : 'expand_more' }}\r\n </span>\r\n </button>\r\n \r\n <!-- User Panel -->\r\n <ng-container *ngTemplateOutlet=\"userPanelTemplate\"></ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </header>\r\n\r\n <!-- User Panel Template -->\r\n <ng-template #userPanelTemplate>\r\n <div class=\"user-panel\" *ngIf=\"isUserPanelOpen\">\r\n <div class=\"user-panel-header\">\r\n <span class=\"panel-title\">Perfil de Usuario</span>\r\n </div>\r\n <div class=\"user-panel-content\">\r\n <div class=\"user-info-item\">\r\n <span class=\"material-symbols-outlined info-icon\">person</span>\r\n <div class=\"info-content\">\r\n <span class=\"info-label\">Código de Usuario:</span>\r\n <span class=\"info-value\">{{ getUsername() }}</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"user-info-item\">\r\n <span class=\"material-symbols-outlined info-icon\">badge</span>\r\n <div class=\"info-content\">\r\n <span class=\"info-label\">Nombre de Usuario:</span>\r\n <span class=\"info-value\">{{ getUserFullName() }}</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"user-info-item\">\r\n <span class=\"material-symbols-outlined info-icon\">credit_card</span>\r\n <div class=\"info-content\">\r\n <span class=\"info-label\">Documento:</span>\r\n <span class=\"info-value\">{{ getDocument() }}</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"user-info-item mobile-hidden\">\r\n <span class=\"material-symbols-outlined info-icon\">business</span>\r\n <div class=\"info-content\">\r\n <span class=\"info-label\">Institución:</span>\r\n <span class=\"info-value\">{{ getInstitution() }}</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"user-info-item mobile-hidden\">\r\n <span class=\"material-symbols-outlined info-icon\">apartment</span>\r\n <div class=\"info-content\">\r\n <span class=\"info-label\">Dependencia:</span>\r\n <span class=\"info-value\">{{ getDependency() }}</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"user-info-item mobile-hidden\">\r\n <span class=\"material-symbols-outlined info-icon\">work</span>\r\n <div class=\"info-content\">\r\n <span class=\"info-label\">Rol:</span>\r\n <span class=\"info-value\">{{ getRole() }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"user-panel-footer\">\r\n <button class=\"logout-btn-panel\" (click)=\"logoutAndRedirect()\" title=\"Cerrar sesión\">\r\n <span class=\"material-symbols-outlined\">logout</span>\r\n <span class=\"logout-text\">CERRAR SESIÓN</span>\r\n </button>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Mobile Menu Overlay -->\r\n <div class=\"nav-overlay\" *ngIf=\"isMobileMenuOpen\" (click)=\"closeMobileMenu()\"></div>\r\n\r\n <!-- Navigation (Horizontal Desktop / Sidebar Mobile) -->\r\n <nav class=\"dashboard-nav\" [class.mobile-open]=\"isMobileMenuOpen\">\r\n <div class=\"nav-mobile-header\">\r\n <div class=\"nav-mobile-logo\">\r\n <img [src]=\"getConfig('logoUrl')\" [alt]=\"getConfig('logoAlt')\" />\r\n <span class=\"nav-mobile-title\">Menú</span>\r\n </div>\r\n <button class=\"nav-close-btn\" (click)=\"closeMobileMenu()\" aria-label=\"Cerrar menú\">\r\n <span class=\"material-symbols-outlined\">close</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"nav-container\">\r\n <!-- Static Menu Items -->\r\n <ng-container *ngIf=\"getConfig('showStaticMenu')\">\r\n <a routerLink=\".\" \r\n routerLinkActive=\"active\" \r\n [routerLinkActiveOptions]=\"{exact: true}\" \r\n class=\"nav-item\"\r\n (click)=\"closeMobileMenu()\">\r\n <span class=\"material-symbols-outlined nav-icon\">home</span>\r\n <span class=\"nav-text\">Inicio</span>\r\n </a>\r\n </ng-container>\r\n\r\n <!-- Separator -->\r\n <div class=\"nav-separator\" *ngIf=\"!isLoadingMenu && menuHierarchy.length > 0\"></div>\r\n \r\n <!-- Dynamic Menu -->\r\n <div class=\"dynamic-menu\" *ngIf=\"!isLoadingMenu && menuHierarchy.length > 0\">\r\n <ng-container *ngFor=\"let rootItem of getRootMenuItems()\">\r\n <div class=\"menu-item-container\" [class.has-children]=\"hasChildren(rootItem)\">\r\n <a \r\n [routerLink]=\"hasChildren(rootItem) ? null : rootItem.path\" \r\n routerLinkActive=\"active\" \r\n class=\"nav-item root-item\"\r\n [class.expandable]=\"hasChildren(rootItem)\"\r\n (click)=\"onMenuItemClick($event, rootItem)\">\r\n <span class=\"material-symbols-outlined nav-icon\">{{ getMenuIcon(rootItem) }}</span>\r\n <span class=\"nav-text\">{{ rootItem.name }}</span>\r\n <span class=\"material-symbols-outlined expand-icon\" *ngIf=\"hasChildren(rootItem)\">\r\n {{ isMenuItemOpen(rootItem.code) ? 'expand_more' : 'chevron_right' }}\r\n </span>\r\n </a>\r\n \r\n <!-- Submenu -->\r\n <div class=\"submenu\" *ngIf=\"hasChildren(rootItem) && isMenuItemOpen(rootItem.code)\">\r\n <ng-container *ngTemplateOutlet=\"menuTemplate; context: { items: rootItem.children, level: 2 }\"></ng-container>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n \r\n <!-- Loading Indicator -->\r\n <div class=\"menu-loading\" *ngIf=\"isLoadingMenu\">\r\n <span class=\"material-symbols-outlined nav-icon\">hourglass_empty</span>\r\n <span class=\"nav-text\">Cargando menú...</span>\r\n </div>\r\n </div>\r\n </nav>\r\n\r\n <!-- Recursive Menu Template -->\r\n <ng-template #menuTemplate let-items=\"items\" let-level=\"level\">\r\n <ng-container *ngFor=\"let item of items\">\r\n <div class=\"menu-item-container\" [class.has-children]=\"hasChildren(item)\" [attr.data-level]=\"level\">\r\n <a \r\n [routerLink]=\"hasChildren(item) ? null : item.path\" \r\n routerLinkActive=\"active\" \r\n class=\"nav-item submenu-item\"\r\n [class.expandable]=\"hasChildren(item)\"\r\n (click)=\"onMenuItemClick($event, item)\">\r\n <span class=\"material-symbols-outlined nav-icon\">{{ getMenuIcon(item) }}</span>\r\n <span class=\"nav-text\">{{ item.name }}</span>\r\n <span class=\"material-symbols-outlined expand-icon\" *ngIf=\"hasChildren(item)\">\r\n {{ isMenuItemOpen(item.code) ? 'expand_more' : 'chevron_right' }}\r\n </span>\r\n </a>\r\n\r\n <!-- Recursive Submenu (max 5 levels) -->\r\n <div class=\"submenu\" *ngIf=\"hasChildren(item) && isMenuItemOpen(item.code) && level < 5\">\r\n <ng-container *ngTemplateOutlet=\"menuTemplate; context: { items: item.children, level: level + 1 }\"></ng-container>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- Main Content -->\r\n <main class=\"dashboard-content\">\r\n <div class=\"content-wrapper\">\r\n <router-outlet></router-outlet>\r\n </div>\r\n </main>\r\n\r\n <!-- Footer -->\r\n <footer class=\"dashboard-footer\">\r\n <div class=\"footer-content\">\r\n <span class=\"footer-text\">\r\n {{ getConfig('footerText') }}\r\n <ng-container *ngIf=\"getConfig('showVersion')\">\r\n Versión {{ appVersion }}.\r\n </ng-container>\r\n Todos los derechos reservados.\r\n </span>\r\n </div>\r\n </footer>\r\n</div>\r\n","// ========================================\r\n// @dinafi/frmk - Public API\r\n// Angular Shared Library - Ministerio de Hacienda\r\n// ========================================\r\n\r\n// === VERSION ===\r\nexport { VERSION, VERSION_INFO } from './lib/version';\r\n\r\n// === MODELS / INTERFACES ===\r\nexport {\r\n // Login Configuration\r\n LoginConfig,\r\n DEFAULT_LOGIN_CONFIG,\r\n \r\n // Dashboard Configuration\r\n DashboardConfig,\r\n DEFAULT_DASHBOARD_CONFIG,\r\n \r\n // Application Configuration\r\n AppConfiguration,\r\n ConfigServerResponse,\r\n \r\n // Authorization\r\n AuthorizationRequest,\r\n AuthorizationResponse,\r\n MenuHierarchyItem,\r\n MenuHierarchyRequest,\r\n \r\n // Library Configuration\r\n FrmkLibraryConfig,\r\n DEFAULT_LIBRARY_CONFIG\r\n} from './lib/models';\r\n\r\n// === SERVICES ===\r\nexport {\r\n // Central Configuration Store (v2.0 — reemplaza funciones globales)\r\n FrmkConfigStore,\r\n \r\n // Authentication Service\r\n AuthService,\r\n \r\n // Authorization Service\r\n AuthorizationService,\r\n \r\n // Configuration Service\r\n ConfigService\r\n} from './lib/services';\r\n\r\n// === GUARDS ===\r\nexport { authGuard } from './lib/guards';\r\n\r\n// === COMPONENTS ===\r\nexport { \r\n LoginComponent \r\n} from './lib/components/login/login.component';\r\n\r\nexport { \r\n DashboardComponent\r\n} from './lib/components/dashboard/dashboard.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i2","i3.FrmkConfigStore","i1","i2.FrmkConfigStore","i2.AuthService","i3.ConfigService","i1.AuthService","i2.AuthorizationService"],"mappings":"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"}
1
+ {"version":3,"file":"shared-lib-angular.mjs","sources":["../../src/lib/version.ts","../../src/lib/models/login-config.interface.ts","../../src/lib/models/dashboard-config.interface.ts","../../src/lib/models/library-config.interface.ts","../../src/lib/services/frmk-config-store.service.ts","../../src/lib/services/token-storage.service.ts","../../src/lib/services/authentication.service.ts","../../src/lib/services/config.service.ts","../../src/lib/services/authorization.service.ts","../../src/lib/guards/authorization.guard.ts","../../src/lib/components/login/login.component.ts","../../src/lib/components/login/login.component.html","../../src/lib/components/dashboard/dashboard.component.ts","../../src/lib/components/dashboard/dashboard.component.html","../../src/public-api.ts","../../src/shared-lib-angular.ts"],"sourcesContent":["// ========================================\n// VERSION - Auto-generado por sync-version.js\n// ========================================\n// Ejecutar 'npm run sync-version' para actualizar manualmente\n// Se sincroniza automáticamente en prebuild\n\n/**\n * Versión actual de la librería @dinafi/frmk\n * Sincronizada con package.json\n */\nexport const VERSION = '2.0.3';\n\n/**\n * Información completa de la versión\n */\nexport const VERSION_INFO = {\n version: '2.0.3',\n name: 'shared-lib-angular',\n buildDate: '2026-02-05T21:05:38.248Z',\n angular: '^20.0.0'\n} as const;\n","/**\r\n * Interface for configuring the LoginComponent appearance and behavior\r\n */\r\nexport interface LoginConfig {\r\n // === IDENTITY ===\r\n /** URL of the logo image. Defaults to the Ministerio de Hacienda logo */\r\n logoUrl: string;\r\n /** Alt text for the logo image */\r\n logoAlt: string;\r\n /** Width of the logo (CSS value, e.g., '120px') */\r\n logoWidth: string;\r\n /** Height of the logo (CSS value, e.g., '120px') */\r\n logoHeight: string;\r\n\r\n // === TEXTS ===\r\n /** Main title displayed on the login page */\r\n title: string;\r\n /** Optional subtitle displayed below the title */\r\n subtitle?: string;\r\n /** Institution name displayed in the footer */\r\n institutionName: string;\r\n /** Text for the login button */\r\n loginButtonText: string;\r\n /** Text for the logout button */\r\n logoutButtonText: string;\r\n /** Text for the \"go to dashboard\" button when already authenticated */\r\n dashboardButtonText: string;\r\n\r\n // === VERSION ===\r\n /** Whether to show the version number */\r\n showVersion: boolean;\r\n /** Version string to display */\r\n version: string;\r\n\r\n // === COLORS (CSS custom properties override) ===\r\n /** Primary color (overrides --color-primary) */\r\n primaryColor?: string;\r\n /** Background color of the container */\r\n backgroundColor?: string;\r\n /** Text color */\r\n textColor?: string;\r\n\r\n // === BEHAVIOR ===\r\n /** URL to redirect after successful login */\r\n redirectUrl: string;\r\n /** Whether to show the logout button when authenticated */\r\n showLogoutButton: boolean;\r\n\r\n // === FOOTER ===\r\n /** Custom footer text */\r\n footerText?: string;\r\n /** Whether to show the footer */\r\n showFooter: boolean;\r\n}\r\n\r\n/**\r\n * Default configuration for the LoginComponent\r\n */\r\nexport const DEFAULT_LOGIN_CONFIG: LoginConfig = {\r\n logoUrl: 'assets/@dinafi/frmk/logo-mh.png',\r\n logoAlt: 'Logo',\r\n logoWidth: '120px',\r\n logoHeight: '120px',\r\n title: 'Sistema de Autenticación',\r\n institutionName: 'Ministerio de Hacienda de El Salvador',\r\n loginButtonText: 'Iniciar Sesión con OIDC',\r\n logoutButtonText: 'Cerrar Sesión',\r\n dashboardButtonText: 'Ir al Dashboard',\r\n showVersion: true,\r\n version: '1.0.0',\r\n redirectUrl: '/home',\r\n showLogoutButton: true,\r\n showFooter: true\r\n};\r\n","/**\r\n * Interface for configuring the DashboardComponent appearance and behavior\r\n */\r\nexport interface DashboardConfig {\r\n /** Application title displayed in the header */\r\n title: string;\r\n /** Optional subtitle */\r\n subtitle?: string;\r\n /** Logo URL */\r\n logoUrl: string;\r\n /** Logo alt text */\r\n logoAlt: string;\r\n /** Footer text */\r\n footerText: string;\r\n /** Whether to show the version in the footer */\r\n showVersion: boolean;\r\n /** Version string */\r\n version: string;\r\n /** Whether to show static menu items (Inicio, Página Ejemplo, Componentes UI) */\r\n showStaticMenu: boolean;\r\n}\r\n\r\n/**\r\n * Default configuration for the DashboardComponent\r\n */\r\nexport const DEFAULT_DASHBOARD_CONFIG: DashboardConfig = {\r\n title: 'Sistema',\r\n logoUrl: 'assets/@dinafi/frmk/logo-mh.png',\r\n logoAlt: 'Logo',\r\n footerText: 'Ministerio de Hacienda, El Salvador',\r\n showVersion: true,\r\n version: '1.0.0',\r\n showStaticMenu: true\r\n};\r\n","import { LoginConfig } from './login-config.interface';\r\nimport { DashboardConfig } from './dashboard-config.interface';\r\n\r\n/**\r\n * Configuración de la librería que debe ser proporcionada por la aplicación consumidora.\r\n * Estos valores son críticos y deben ser configurados al inicializar la librería\r\n * mediante `FrmkConfigStore.initialize()` en el APP_INITIALIZER.\r\n */\r\nexport interface FrmkLibraryConfig {\r\n /**\r\n * URL del servidor de configuración (Config Server)\r\n * Ejemplo: 'config-server.example.com' o 'localhost:8080'\r\n */\r\n configServerHost: string;\r\n\r\n /**\r\n * Identificador del frontend en el Config Server\r\n * Este valor identifica la aplicación para obtener su configuración específica\r\n * Ejemplo: 'mi-aplicacion-frontend'\r\n */\r\n frontendId: string;\r\n\r\n /**\r\n * Ruta del servicio de configuración (opcional)\r\n * Por defecto: '/api/v1/config/service'\r\n */\r\n configServicePath?: string;\r\n\r\n /**\r\n * Realm de autenticación (opcional)\r\n * Por defecto se obtiene del Config Server\r\n */\r\n realm?: string;\r\n\r\n /**\r\n * Si es ambiente de producción (opcional)\r\n * Por defecto: false\r\n */\r\n production?: boolean;\r\n\r\n /**\r\n * Si requiere HTTPS (opcional)\r\n * Por defecto: true\r\n */\r\n requireHttps?: boolean;\r\n\r\n /**\r\n * Mostrar información de debug (opcional)\r\n * Por defecto: false\r\n */\r\n showDebugInformation?: boolean;\r\n\r\n /**\r\n * Configuración del componente de Login (opcional)\r\n * Permite personalizar textos, logos y comportamiento del login\r\n */\r\n loginConfig?: Partial<LoginConfig>;\r\n\r\n /**\r\n * Configuración del componente Dashboard (opcional)\r\n * Permite personalizar el layout principal de la aplicación\r\n */\r\n dashboardConfig?: Partial<DashboardConfig>;\r\n}\r\n\r\n/**\r\n * Configuración por defecto de la librería\r\n */\r\nexport const DEFAULT_LIBRARY_CONFIG: Partial<FrmkLibraryConfig> = {\r\n configServicePath: '/api/v1/config/service',\r\n production: false,\r\n requireHttps: true,\r\n showDebugInformation: false\r\n};\r\n","import { Injectable, signal, computed } from '@angular/core';\r\nimport { AuthConfig } from 'angular-oauth2-oidc';\r\nimport { AppConfiguration, ConfigServerResponse } from '../models/app-config.interface';\r\nimport { FrmkLibraryConfig, DEFAULT_LIBRARY_CONFIG } from '../models/library-config.interface';\r\nimport { LoginConfig, DEFAULT_LOGIN_CONFIG } from '../models/login-config.interface';\r\nimport { DashboardConfig, DEFAULT_DASHBOARD_CONFIG } from '../models/dashboard-config.interface';\r\n\r\n/**\r\n * Store centralizado de configuración del framework.\r\n *\r\n * Reemplaza las variables globales mutables (`currentAppConfig`, `libraryConfig`)\r\n * con un servicio inyectable basado en signals de Angular.\r\n *\r\n * Ciclo de vida:\r\n * 1. `initialize(config)` — llamado en APP_INITIALIZER con FrmkLibraryConfig\r\n * 2. `applyServerConfig(data)` — llamado por ConfigService tras obtener datos del Config Server\r\n *\r\n * Todas las propiedades computadas lanzan error si se leen antes de `initialize()`.\r\n *\r\n * @example\r\n * // En APP_INITIALIZER:\r\n * const store = inject(FrmkConfigStore);\r\n * store.initialize(myLibraryConfig);\r\n * await configService.loadConfig(); // internamente llama store.applyServerConfig()\r\n * authService.initializeAuth(store.authConfig());\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class FrmkConfigStore {\r\n\r\n // ── Signals internos ──────────────────────────────────────────────\r\n\r\n private readonly _libraryConfig = signal<FrmkLibraryConfig | null>(null);\r\n private readonly _serverConfig = signal<ConfigServerResponse | null>(null);\r\n\r\n // ── Estado público (read-only) ────────────────────────────────────\r\n\r\n /** Indica si la librería ha sido inicializada con `initialize()`. */\r\n readonly isConfigured = computed(() => this._libraryConfig() !== null);\r\n\r\n /** Configuración de la librería (merged con defaults). Lanza si no inicializada. */\r\n readonly libraryConfig = computed(() => {\r\n const cfg = this._libraryConfig();\r\n if (!cfg) {\r\n throw new Error(\r\n '[FRMK] La librería no ha sido configurada. ' +\r\n 'Llame a FrmkConfigStore.initialize() en su APP_INITIALIZER.'\r\n );\r\n }\r\n return cfg;\r\n });\r\n\r\n /** Configuración del componente Login (defaults + libraryConfig.loginConfig). */\r\n readonly loginConfig = computed<LoginConfig>(() => {\r\n const lib = this.libraryConfig();\r\n return { ...DEFAULT_LOGIN_CONFIG, ...(lib.loginConfig || {}) };\r\n });\r\n\r\n /** Configuración del componente Dashboard (defaults + libraryConfig.dashboardConfig). */\r\n readonly dashboardConfig = computed<DashboardConfig>(() => {\r\n const lib = this.libraryConfig();\r\n return { ...DEFAULT_DASHBOARD_CONFIG, ...(lib.dashboardConfig || {}) };\r\n });\r\n\r\n /**\r\n * Configuración completa de la aplicación.\r\n * Si hay datos del Config Server se aplican; en caso contrario se usan solo los defaults + libraryConfig.\r\n */\r\n readonly appConfig = computed<AppConfiguration>(() => {\r\n const lib = this.libraryConfig(); // lanza si no inicializada\r\n let config = this.createDefaultAppConfig(lib);\r\n\r\n const serverData = this._serverConfig();\r\n if (serverData) {\r\n const mapped = this.mapConfigServerResponse(serverData, config);\r\n config = this.mergeConfigurations(config, mapped);\r\n }\r\n\r\n return this.buildDynamicUrls(config);\r\n });\r\n\r\n /** AuthConfig de angular-oauth2-oidc derivada de appConfig. */\r\n readonly authConfig = computed<AuthConfig>(() => {\r\n const app = this.appConfig();\r\n return {\r\n issuer: app.auth.issuer,\r\n loginUrl: app.auth.loginUrl,\r\n tokenEndpoint: app.auth.tokenEndpoint,\r\n userinfoEndpoint: app.auth.userinfoEndpoint,\r\n logoutUrl: app.auth.logoutUrl,\r\n redirectUri: app.auth.redirectUri,\r\n postLogoutRedirectUri: app.auth.postLogoutRedirectUri,\r\n clientId: app.auth.clientId,\r\n responseType: 'code',\r\n scope: app.auth.scope,\r\n disableAtHashCheck: true,\r\n requireHttps: app.environment.requireHttps,\r\n showDebugInformation: app.environment.showDebugInformation,\r\n strictDiscoveryDocumentValidation: false,\r\n skipIssuerCheck: true,\r\n requestAccessToken: true,\r\n customQueryParams: {},\r\n silentRefreshTimeout: 5000,\r\n timeoutFactor: 0.25,\r\n sessionChecksEnabled: false,\r\n clearHashAfterLogin: true,\r\n oidc: true,\r\n clockSkewInSec: 30,\r\n disableIdTokenTimer: true\r\n };\r\n });\r\n\r\n // ── Métodos públicos ──────────────────────────────────────────────\r\n\r\n /**\r\n * Inicializa la librería con la configuración proporcionada por la app consumidora.\r\n * Debe llamarse UNA vez dentro del APP_INITIALIZER, antes de cualquier otro uso.\r\n *\r\n * @param config Configuración de la librería (se fusiona con DEFAULT_LIBRARY_CONFIG)\r\n */\r\n initialize(config: FrmkLibraryConfig): void {\r\n this._libraryConfig.set({\r\n ...DEFAULT_LIBRARY_CONFIG,\r\n ...config\r\n } as FrmkLibraryConfig);\r\n\r\n // Resetear server config para que appConfig se recalcule con los nuevos defaults\r\n this._serverConfig.set(null);\r\n }\r\n\r\n /**\r\n * Aplica los datos devueltos por el Config Server.\r\n * Llamado por `ConfigService.loadConfig()` después de la petición HTTP.\r\n *\r\n * @param data Respuesta del Config Server (o undefined si falló la carga)\r\n */\r\n applyServerConfig(data?: ConfigServerResponse): void {\r\n this._serverConfig.set(data ?? null);\r\n }\r\n\r\n // ── Lógica privada (migrada de app.config.ts) ─────────────────────\r\n\r\n private createDefaultAppConfig(lib: FrmkLibraryConfig): AppConfiguration {\r\n return {\r\n hosts: {\r\n configServer: lib.configServerHost,\r\n authServer: '',\r\n keycloak: '',\r\n localApp: ''\r\n },\r\n paths: {\r\n configService: lib.configServicePath || '/api/v1/config/service',\r\n realm: lib.realm || 'realm-to-create'\r\n },\r\n configServer: {\r\n url: '',\r\n frontend: lib.frontendId\r\n },\r\n auth: {\r\n issuer: '',\r\n loginUrl: '',\r\n tokenEndpoint: '',\r\n userinfoEndpoint: '',\r\n logoutUrl: '',\r\n clientId: '',\r\n redirectUri: '',\r\n postLogoutRedirectUri: '',\r\n silentRefreshRedirectUri: '',\r\n scope: 'openid email profile'\r\n },\r\n authorization: {\r\n baseUrl: '',\r\n verifyEndpoint: '/api/v1/authz/verify-groups',\r\n hierarchyEndpoint: '/api/v1/authz/hierarchy-by-component-and-groups'\r\n },\r\n environment: {\r\n production: lib.production ?? false,\r\n requireHttps: lib.requireHttps ?? true,\r\n showDebugInformation: lib.showDebugInformation ?? false\r\n }\r\n };\r\n }\r\n\r\n private mapConfigServerResponse(\r\n data: ConfigServerResponse,\r\n defaultConfig: AppConfiguration\r\n ): Partial<AppConfiguration> {\r\n const mapped: Partial<AppConfiguration> = {};\r\n\r\n if (data['security.url.auth']) {\r\n mapped.hosts = {\r\n ...defaultConfig.hosts,\r\n ...(mapped.hosts || {}),\r\n authServer: data['security.url.auth']\r\n };\r\n }\r\n\r\n if (data['quarkus.oidc.client-id']) {\r\n mapped.auth = {\r\n ...defaultConfig.auth,\r\n ...(mapped.auth || {}),\r\n clientId: data['quarkus.oidc.client-id']\r\n };\r\n }\r\n\r\n if (data['security.realm']) {\r\n mapped.paths = {\r\n ...defaultConfig.paths,\r\n ...(mapped.paths || {}),\r\n realm: data['security.realm']\r\n };\r\n }\r\n\r\n if (data['security.url.authz']) {\r\n mapped.authorization = {\r\n ...defaultConfig.authorization,\r\n ...(mapped.authorization || {}),\r\n baseUrl: data['security.url.authz']\r\n };\r\n }\r\n\r\n if (data['security.scope']) {\r\n mapped.auth = {\r\n ...defaultConfig.auth,\r\n ...(mapped.auth || {}),\r\n scope: data['security.scope']\r\n };\r\n }\r\n\r\n if (data['security.url.keycloak']) {\r\n mapped.hosts = {\r\n ...defaultConfig.hosts,\r\n ...(mapped.hosts || {}),\r\n keycloak: data['security.url.keycloak']\r\n };\r\n }\r\n\r\n if (data['security.url.callback']) {\r\n mapped.hosts = {\r\n ...defaultConfig.hosts,\r\n ...(mapped.hosts || {}),\r\n localApp: data['security.url.callback']\r\n };\r\n }\r\n\r\n if (data['security.url.https'] !== undefined) {\r\n mapped.environment = {\r\n ...defaultConfig.environment,\r\n ...(mapped.environment || {}),\r\n requireHttps: data['security.url.https']\r\n };\r\n }\r\n\r\n return mapped;\r\n }\r\n\r\n private mergeConfigurations(\r\n base: AppConfiguration,\r\n override: Partial<AppConfiguration>\r\n ): AppConfiguration {\r\n const merged = { ...base };\r\n\r\n if (override.hosts) {\r\n merged.hosts = { ...merged.hosts, ...override.hosts };\r\n }\r\n if (override.paths) {\r\n merged.paths = { ...merged.paths, ...override.paths };\r\n }\r\n if (override.configServer) {\r\n merged.configServer = { ...merged.configServer, ...override.configServer };\r\n }\r\n if (override.auth) {\r\n merged.auth = { ...merged.auth, ...override.auth };\r\n }\r\n if (override.authorization) {\r\n merged.authorization = { ...merged.authorization, ...override.authorization };\r\n }\r\n if (override.environment) {\r\n merged.environment = { ...merged.environment, ...override.environment };\r\n }\r\n\r\n return merged;\r\n }\r\n\r\n private buildDynamicUrls(config: AppConfiguration): AppConfiguration {\r\n const c = { ...config };\r\n const proto = c.environment.requireHttps ? 'https' : 'http';\r\n\r\n // Config Server URL\r\n c.configServer = { ...c.configServer };\r\n c.configServer.url = `${proto}://${c.hosts.configServer}${c.paths.configService}`;\r\n\r\n // Auth URLs\r\n c.auth = { ...c.auth };\r\n c.auth.issuer = `${proto}://${c.hosts.keycloak}/realms/${c.paths.realm}`;\r\n c.auth.loginUrl = `${proto}://${c.hosts.keycloak}/realms/${c.paths.realm}/protocol/openid-connect/auth`;\r\n c.auth.tokenEndpoint = `${proto}://${c.hosts.authServer}/oidc/realm/${c.paths.realm}/protocol/openid-connect/token`;\r\n c.auth.userinfoEndpoint = `${proto}://${c.hosts.authServer}/oidc/realm/${c.paths.realm}/protocol/openid-connect/userinfo`;\r\n c.auth.logoutUrl = `${proto}://${c.hosts.authServer}/oidc/realm/${c.paths.realm}/protocol/openid-connect/logout`;\r\n\r\n // Redirect URLs (locales)\r\n const currentOrigin = globalThis.window?.location?.origin ?? c.hosts.localApp;\r\n c.auth.redirectUri = `${currentOrigin}/login`;\r\n c.auth.postLogoutRedirectUri = `${currentOrigin}/login`;\r\n\r\n // Authorization URL\r\n c.authorization = { ...c.authorization };\r\n c.authorization.baseUrl = `${proto}://${c.authorization.baseUrl}`;\r\n\r\n return c;\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\n\r\n/**\r\n * Keys de tokens OAuth/OIDC manejados por angular-oauth2-oidc y Keycloak.\r\n * Única fuente de verdad — elimina listas duplicadas e inconsistentes.\r\n */\r\nconst TOKEN_KEYS = [\r\n 'access_token',\r\n 'refresh_token',\r\n 'id_token',\r\n 'token_type',\r\n 'expires_at',\r\n 'nonce',\r\n 'PKCE_verifier',\r\n 'code_verifier',\r\n 'session_state',\r\n 'id_token_claims_obj',\r\n 'id_token_expires_at',\r\n 'id_token_stored_at',\r\n 'access_token_stored_at'\r\n] as const;\r\n\r\n/**\r\n * Keys de estado OAuth que deben preservarse durante un callback\r\n * (necesarias para validar code + state en el intercambio PKCE).\r\n */\r\nconst STATE_KEYS: ReadonlySet<string> = new Set([\r\n 'nonce',\r\n 'PKCE_verifier',\r\n 'code_verifier',\r\n 'session_state',\r\n 'state'\r\n]);\r\n\r\n/**\r\n * Servicio centralizado para gestión de tokens en localStorage / sessionStorage.\r\n *\r\n * - Elimina las 4+ listas de keys duplicadas e inconsistentes que existían en AuthService.\r\n * - Opera simétricamente sobre ambos storages.\r\n * - Soporta la key dinámica `refresh_token_{clientId}` que usa angular-oauth2-oidc.\r\n * - Expone métodos públicos para que la plantilla pueda leer tokens sin acceder a storage directamente.\r\n *\r\n * @example\r\n * // Desde la librería (AuthService):\r\n * this.tokenStorage.clearAll();\r\n *\r\n * // Desde la plantilla (skeleton):\r\n * const expired = this.tokenStorage.isTokenExpired();\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class TokenStorageService {\r\n\r\n // ── Limpieza ──────────────────────────────────────────────────────\r\n\r\n /**\r\n * Limpia TODOS los tokens y estado OAuth de ambos storages.\r\n * Incluye la key dinámica `refresh_token_{clientId}` si se proporciona.\r\n *\r\n * @param clientId — clientId de OAuth para limpiar `refresh_token_{clientId}` (opcional)\r\n */\r\n clearAll(clientId?: string): void {\r\n TOKEN_KEYS.forEach(key => {\r\n localStorage.removeItem(key);\r\n sessionStorage.removeItem(key);\r\n });\r\n\r\n // Key dinámica de angular-oauth2-oidc\r\n if (clientId) {\r\n localStorage.removeItem(`refresh_token_${clientId}`);\r\n sessionStorage.removeItem(`refresh_token_${clientId}`);\r\n }\r\n\r\n // También limpiar 'state' que no está en TOKEN_KEYS pero puede persistir\r\n localStorage.removeItem('state');\r\n sessionStorage.removeItem('state');\r\n }\r\n\r\n /**\r\n * Limpia tokens pero MANTIENE las keys de estado OAuth necesarias para\r\n * validar el callback (nonce, PKCE_verifier, code_verifier, session_state, state).\r\n *\r\n * Usar durante un callback OAuth antes de procesar el authorization code.\r\n */\r\n clearTokensKeepState(): void {\r\n TOKEN_KEYS.forEach(key => {\r\n if (!STATE_KEYS.has(key)) {\r\n localStorage.removeItem(key);\r\n sessionStorage.removeItem(key);\r\n }\r\n });\r\n\r\n console.log('[TokenStorageService] Cleared tokens, kept state/nonce/PKCE for callback validation');\r\n }\r\n\r\n // ── Lectura ───────────────────────────────────────────────────────\r\n\r\n /**\r\n * Lee un valor de localStorage o sessionStorage (en ese orden de prioridad).\r\n */\r\n getItem(key: string): string | null {\r\n return localStorage.getItem(key) ?? sessionStorage.getItem(key);\r\n }\r\n\r\n /**\r\n * Obtiene el refresh_token, incluyendo la variante dinámica `refresh_token_{clientId}`.\r\n *\r\n * @param clientId — clientId de OAuth (opcional)\r\n */\r\n getRefreshToken(clientId?: string): string | null {\r\n const token = this.getItem('refresh_token');\r\n if (token) return token;\r\n\r\n if (clientId) {\r\n return localStorage.getItem(`refresh_token_${clientId}`)\r\n ?? sessionStorage.getItem(`refresh_token_${clientId}`)\r\n ?? null;\r\n }\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * Obtiene el access_token de cualquier storage.\r\n */\r\n getAccessToken(): string | null {\r\n return this.getItem('access_token');\r\n }\r\n\r\n // ── Estado ────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Verifica si hay un token almacenado y está expirado.\r\n * Retorna `false` si no existe `expires_at` (no hay token, no está \"expirado\").\r\n */\r\n isTokenExpired(): boolean {\r\n const expiresAt = this.getItem('expires_at');\r\n if (!expiresAt) {\r\n return false;\r\n }\r\n return parseInt(expiresAt, 10) < Date.now();\r\n }\r\n\r\n // ── Utilidades ────────────────────────────────────────────────────\r\n\r\n /**\r\n * Elimina una key específica de ambos storages.\r\n */\r\n removeItem(key: string): void {\r\n localStorage.removeItem(key);\r\n sessionStorage.removeItem(key);\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { AuthConfig, OAuthService, OAuthEvent } from 'angular-oauth2-oidc';\r\nimport { BehaviorSubject } from 'rxjs';\r\nimport { FrmkConfigStore } from './frmk-config-store.service';\r\nimport { TokenStorageService } from './token-storage.service';\r\n\r\n@Injectable({ \r\n providedIn: 'root'\r\n})\r\nexport class AuthService {\r\n private readonly isAuthenticatedSubject$ = new BehaviorSubject<boolean>(false);\r\n public isAuthenticated$ = this.isAuthenticatedSubject$.asObservable();\r\n\r\n private readonly isDoneLoadingSubject$ = new BehaviorSubject<boolean>(false);\r\n public isDoneLoading$ = this.isDoneLoadingSubject$.asObservable();\r\n\r\n private isInitialLogin = true;\r\n\r\n constructor(\r\n private readonly oauthService: OAuthService,\r\n private readonly router: Router,\r\n private readonly store: FrmkConfigStore,\r\n private readonly tokenStorage: TokenStorageService\r\n ) {\r\n // IMPORTANTE: Limpiar tokens expirados ANTES de cualquier otra operación\r\n this.clearExpiredTokensOnStartup();\r\n \r\n this.oauthService.events \r\n .subscribe((event) => {\r\n if (event instanceof OAuthEvent) {\r\n if (event.type === 'token_received') {\r\n this.handleSuccessfulAuthentication();\r\n }\r\n if (event.type === 'logout') {\r\n this.handleLogout();\r\n }\r\n if (event.type === 'token_error') {\r\n this.isDoneLoadingSubject$.next(true);\r\n }\r\n if (event.type === 'silently_refreshed') {\r\n this.handleSilentRefresh();\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Limpia tokens expirados al iniciar la aplicación\r\n * Solo limpia si NO estamos en un callback OAuth\r\n */\r\n private clearExpiredTokensOnStartup(): void {\r\n const urlParams = new URLSearchParams(window.location.search);\r\n \r\n // Detectar TODOS los parámetros que indican un callback OAuth\r\n // Keycloak puede enviar: code, state, session_state, iss (RFC 9207)\r\n const isOAuthCallback = urlParams.has('code') || \r\n urlParams.has('iss') || \r\n urlParams.has('session_state') ||\r\n urlParams.has('state') ||\r\n window.location.hash.includes('access_token') ||\r\n window.location.hash.includes('code');\r\n \r\n if (isOAuthCallback) {\r\n console.log('[AuthService] OAuth callback detected, skipping token cleanup');\r\n return;\r\n }\r\n\r\n // Verificar si hay un token y si está expirado\r\n if (this.tokenStorage.isTokenExpired()) {\r\n console.log('[AuthService] Expired token detected, clearing storage');\r\n this.tokenStorage.clearAll();\r\n }\r\n }\r\n\r\n\r\n\r\n private handleSuccessfulAuthentication(): void {\r\n if (this.oauthService.hasValidAccessToken()) {\r\n this.isAuthenticatedSubject$.next(true);\r\n this.isDoneLoadingSubject$.next(true);\r\n \r\n // Limpiar parámetros OAuth de la URL para evitar problemas al refrescar\r\n this.cleanupOAuthParams();\r\n \r\n if (this.isInitialLogin) {\r\n this.isInitialLogin = false;\r\n }\r\n } else {\r\n this.isDoneLoadingSubject$.next(true);\r\n }\r\n }\r\n\r\n /**\r\n * Limpia los parámetros OAuth de la URL después del login exitoso\r\n * Esto evita problemas cuando el usuario refresca la página\r\n */\r\n private cleanupOAuthParams(): void {\r\n try {\r\n const url = new URL(window.location.href);\r\n const paramsToRemove = ['code', 'state', 'session_state', 'iss'];\r\n let hasOAuthParams = false;\r\n \r\n paramsToRemove.forEach(param => {\r\n if (url.searchParams.has(param)) {\r\n url.searchParams.delete(param);\r\n hasOAuthParams = true;\r\n }\r\n });\r\n \r\n if (hasOAuthParams) {\r\n // Reemplazar URL sin recargar la página\r\n window.history.replaceState({}, document.title, url.toString());\r\n console.log('[AuthService] OAuth params cleaned from URL');\r\n }\r\n } catch (error) {\r\n console.warn('[AuthService] Error cleaning OAuth params:', error);\r\n }\r\n }\r\n\r\n private handleSilentRefresh(): void {\r\n if (this.oauthService.hasValidAccessToken()) {\r\n this.isAuthenticatedSubject$.next(true);\r\n this.isDoneLoadingSubject$.next(true);\r\n }\r\n }\r\n\r\n private handleLogout(): void {\r\n this.isAuthenticatedSubject$.next(false);\r\n this.isDoneLoadingSubject$.next(true);\r\n }\r\n\r\n /**\r\n * Limpia todos los tokens del storage y resetea OAuthService\r\n */\r\n private clearTokenStorage(): void {\r\n this.oauthService.logOut(true); // true = no redirect, solo limpiar\r\n this.tokenStorage.clearAll();\r\n }\r\n\r\n /**\r\n * Verifica si el token actual está expirado\r\n */\r\n private isTokenExpired(): boolean {\r\n // Primero verificar vía OAuthService (tokens en memoria)\r\n const expiresAt = this.oauthService.getAccessTokenExpiration();\r\n if (expiresAt) {\r\n return expiresAt < Date.now();\r\n }\r\n // Fallback: verificar en storage\r\n return this.tokenStorage.isTokenExpired();\r\n }\r\n\r\n private async runInitialLoginSequence(): Promise<void> {\r\n try {\r\n const urlParams = new URLSearchParams(window.location.search);\r\n const hasCode = urlParams.has('code');\r\n const hasState = urlParams.has('state');\r\n const hasIss = urlParams.has('iss');\r\n const hasSessionState = urlParams.has('session_state');\r\n const hasFragment = window.location.hash.includes('access_token') || window.location.hash.includes('code');\r\n \r\n // Detectar si estamos en un callback OAuth (Keycloak envía code, state, session_state, iss)\r\n const isOAuthCallback = hasCode || hasFragment || (hasState && (hasIss || hasSessionState));\r\n\r\n // Si NO estamos en callback OAuth y hay tokens expirados, limpiar y terminar\r\n if (!isOAuthCallback && this.isTokenExpired()) {\r\n console.log('[AuthService] No OAuth callback detected and token expired, clearing storage');\r\n this.clearTokenStorage();\r\n this.isDoneLoadingSubject$.next(true);\r\n return;\r\n }\r\n\r\n // Si estamos en callback OAuth, SIEMPRE limpiar tokens anteriores para evitar conflictos\r\n // Esto es crítico: angular-oauth2-oidc valida tokens existentes antes de procesar el código nuevo\r\n if (isOAuthCallback) {\r\n console.log('[AuthService] OAuth callback detected, clearing old tokens before processing');\r\n // Limpiar solo tokens, NO el state/nonce que necesitamos para validar el callback\r\n this.tokenStorage.clearTokensKeepState();\r\n \r\n this.isInitialLogin = true;\r\n await this.oauthService.tryLoginCodeFlow();\r\n } \r\n\r\n const hasValidToken = this.oauthService.hasValidAccessToken();\r\n \r\n if (hasValidToken) {\r\n if (!hasCode && !hasFragment) {\r\n this.isInitialLogin = false;\r\n }\r\n this.handleSuccessfulAuthentication();\r\n } else {\r\n this.isDoneLoadingSubject$.next(true);\r\n }\r\n \r\n } catch (error: any) {\r\n console.error('[AuthService] Error during authentication initialization:', error);\r\n \r\n // Si el error es por token expirado, limpiar y permitir nuevo login\r\n if (error?.message?.includes('expired') || error?.reason?.includes('expired')) {\r\n this.clearTokenStorage();\r\n }\r\n \r\n this.isDoneLoadingSubject$.next(true);\r\n } \r\n }\r\n\r\n private setupManualConfiguration(): void {\r\n const authConfig = this.store.authConfig();\r\n this.oauthService.tokenEndpoint = authConfig.tokenEndpoint!;\r\n this.oauthService.userinfoEndpoint = authConfig.userinfoEndpoint!;\r\n this.oauthService.loginUrl = authConfig.loginUrl!;\r\n this.oauthService.logoutUrl = authConfig.logoutUrl!;\r\n this.oauthService.clientId = authConfig.clientId!;\r\n this.oauthService.redirectUri = authConfig.redirectUri!;\r\n this.oauthService.scope = authConfig.scope!;\r\n this.oauthService.responseType = authConfig.responseType!;\r\n }\r\n\r\n public initializeAuth(authConfig: AuthConfig): void {\r\n const urlParams = new URLSearchParams(window.location.search);\r\n const hasCode = urlParams.has('code');\r\n \r\n // Si es callback OAuth, resetear TODO el estado de OAuthService\r\n if (hasCode) {\r\n console.log('[AuthService] OAuth callback detected: resetting OAuthService state');\r\n \r\n // Limpiar storage EXCEPTO state/nonce/PKCE\r\n this.tokenStorage.clearTokensKeepState();\r\n \r\n // CRÍTICO: Resetear propiedades internas de OAuthService\r\n // para que no valide tokens viejos en memoria\r\n this.resetOAuthServiceInternalState();\r\n } else {\r\n // No es callback - verificar si hay tokens expirados\r\n if (this.tokenStorage.isTokenExpired()) {\r\n console.log('[AuthService] Clearing all expired tokens before configure');\r\n this.tokenStorage.clearAll();\r\n this.resetOAuthServiceInternalState();\r\n }\r\n }\r\n \r\n // Ahora es seguro configurar OAuthService\r\n this.oauthService.configure(authConfig);\r\n this.setupManualConfiguration();\r\n this.runInitialLoginSequence();\r\n }\r\n\r\n /**\r\n * Resetea las propiedades internas de OAuthService\r\n * Esto es necesario porque la librería guarda tokens en memoria\r\n * que no se limpian con localStorage/sessionStorage\r\n */\r\n private resetOAuthServiceInternalState(): void {\r\n try {\r\n const oauth = this.oauthService as any;\r\n oauth._accessToken = null;\r\n oauth._idToken = null;\r\n oauth._idTokenClaims = null;\r\n oauth.idTokenClaimsJson = null;\r\n oauth._refreshToken = null;\r\n console.log('[AuthService] OAuthService internal state reset');\r\n } catch (e) {\r\n console.warn('[AuthService] Could not reset internal state:', e);\r\n }\r\n }\r\n\r\n public getAuthConfig(): AuthConfig {\r\n return this.store.authConfig();\r\n }\r\n\r\n public login(targetUrl?: string): void {\r\n this.isInitialLogin = true;\r\n \r\n if (!this.oauthService.clientId) {\r\n return;\r\n }\r\n if (!this.oauthService.redirectUri) {\r\n return;\r\n }\r\n\r\n this.oauthService.initLoginFlow(targetUrl || undefined);\r\n }\r\n\r\n public async logout(): Promise<void> {\r\n try {\r\n await this.callKeycloakLogoutEndpoint().catch(err => {\r\n console.warn('Keycloak logout endpoint failed, but will continue with local cleanup:', err);\r\n });\r\n \r\n this.performLocalLogout();\r\n \r\n } catch (error) {\r\n console.error('Error during logout:', error);\r\n this.performLocalLogout();\r\n }\r\n }\r\n\r\n private async callKeycloakLogoutEndpoint(): Promise<void> {\r\n const authConfig = this.store.authConfig();\r\n const logoutUrl = authConfig.logoutUrl;\r\n \r\n let refreshToken: string | null = this.oauthService.getRefreshToken();\r\n \r\n if (!refreshToken) {\r\n refreshToken = this.tokenStorage.getRefreshToken(authConfig.clientId);\r\n }\r\n \r\n if (!logoutUrl) {\r\n console.warn('Logout URL not configured, skipping Keycloak logout');\r\n return;\r\n }\r\n\r\n if (!refreshToken) {\r\n console.warn('No refresh token found, logout endpoint may fail');\r\n }\r\n\r\n const body = new URLSearchParams();\r\n body.set('client_id', authConfig.clientId!);\r\n \r\n if (refreshToken) {\r\n body.set('refresh_token', refreshToken);\r\n }\r\n\r\n const headers: HeadersInit = {\r\n 'Content-Type': 'application/x-www-form-urlencoded'\r\n };\r\n\r\n try {\r\n const response = await fetch(logoutUrl, {\r\n method: 'POST',\r\n headers,\r\n body: body.toString()\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text();\r\n console.warn('Keycloak logout returned error, but local cleanup completed:', errorText);\r\n }\r\n } catch (error) {\r\n console.warn('Failed to call Keycloak logout endpoint:', error);\r\n }\r\n }\r\n\r\n private performLocalLogout(): void {\r\n const authConfig = this.store.authConfig();\r\n this.oauthService.logOut(true);\r\n this.tokenStorage.clearAll(authConfig.clientId);\r\n \r\n this.isAuthenticatedSubject$.next(false);\r\n this.isDoneLoadingSubject$.next(true);\r\n \r\n const currentUrl = this.router.url;\r\n if (currentUrl !== '/login' && !currentUrl.includes('/login')) {\r\n this.router.navigate(['/login']);\r\n }\r\n }\r\n\r\n public logoutAndRedirect(targetUrl: string = '/login'): void {\r\n this.logout();\r\n this.router.navigate([targetUrl]);\r\n }\r\n\r\n public hasValidToken(): boolean {\r\n return this.oauthService.hasValidAccessToken();\r\n }\r\n\r\n public get identityClaims(): any {\r\n return this.oauthService.getIdentityClaims();\r\n }\r\n\r\n public get accessToken(): string {\r\n return this.oauthService.getAccessToken();\r\n }\r\n\r\n public getUserRoles(): string[] {\r\n const claims = this.identityClaims;\r\n if (claims?.roles) {\r\n return Array.isArray(claims.roles) ? claims.roles : [claims.roles];\r\n }\r\n \r\n if (claims) {\r\n const roles: string[] = [];\r\n \r\n if (claims.realm_access?.roles) {\r\n roles.push(...claims.realm_access.roles);\r\n }\r\n \r\n const authConfig = this.store.authConfig();\r\n if (claims.resource_access?.[authConfig.clientId!]?.roles) {\r\n roles.push(...claims.resource_access[authConfig.clientId!].roles);\r\n }\r\n \r\n return roles;\r\n }\r\n return [];\r\n }\r\n\r\n public hasRole(role: string): boolean {\r\n return this.getUserRoles().includes(role);\r\n }\r\n\r\n public hasAnyRole(roles: string[]): boolean {\r\n const userRoles = this.getUserRoles();\r\n return roles.some(role => userRoles.includes(role));\r\n }\r\n\r\n public getUserGroups(): string[] {\r\n const claims = this.identityClaims;\r\n const groups: string[] = [];\r\n\r\n // First, try to get groups from identity claims (ID token)\r\n if (claims) {\r\n if (claims.groups) {\r\n if (Array.isArray(claims.groups)) {\r\n groups.push(...claims.groups);\r\n } else {\r\n groups.push(claims.groups);\r\n }\r\n }\r\n\r\n if (claims.accessTokenGroups) {\r\n if (Array.isArray(claims.accessTokenGroups)) {\r\n groups.push(...claims.accessTokenGroups);\r\n } else {\r\n groups.push(claims.accessTokenGroups);\r\n }\r\n }\r\n\r\n if (claims.realm_access?.groups) {\r\n groups.push(...claims.realm_access.groups);\r\n }\r\n }\r\n\r\n // If no groups found in ID token, try to decode access token\r\n if (groups.length === 0) {\r\n const accessToken = this.accessToken;\r\n if (accessToken) {\r\n try {\r\n const payload = this.decodeJwtPayload(accessToken);\r\n console.log('[AuthService] Access token payload:', payload);\r\n\r\n // Extract groups from access token\r\n if (payload.groups) {\r\n if (Array.isArray(payload.groups)) {\r\n groups.push(...payload.groups);\r\n } else {\r\n groups.push(payload.groups);\r\n }\r\n }\r\n\r\n // Also check realm_access.roles as groups (Keycloak pattern)\r\n if (payload.realm_access?.roles) {\r\n groups.push(...payload.realm_access.roles);\r\n }\r\n\r\n // Check resource_access for client-specific roles\r\n if (payload.resource_access) {\r\n Object.values(payload.resource_access).forEach((resource: any) => {\r\n if (resource.roles && Array.isArray(resource.roles)) {\r\n groups.push(...resource.roles);\r\n }\r\n });\r\n }\r\n } catch (error) {\r\n console.error('[AuthService] Error decoding access token:', error);\r\n }\r\n }\r\n }\r\n\r\n const uniqueGroups = [...new Set(groups)];\r\n console.log('[AuthService] getUserGroups result:', uniqueGroups);\r\n return uniqueGroups;\r\n }\r\n\r\n private decodeJwtPayload(token: string): any {\r\n try {\r\n const parts = token.split('.');\r\n if (parts.length !== 3) {\r\n throw new Error('Invalid JWT format');\r\n }\r\n const payload = parts[1];\r\n const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));\r\n return JSON.parse(decoded);\r\n } catch (error) {\r\n console.error('[AuthService] Failed to decode JWT:', error);\r\n return {};\r\n }\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { firstValueFrom } from 'rxjs';\r\nimport { AppConfiguration, ConfigServerResponse } from '../models/app-config.interface';\r\nimport { FrmkConfigStore } from './frmk-config-store.service';\r\n\r\n@Injectable({ \r\n providedIn: 'root' \r\n})\r\nexport class ConfigService {\r\n private configServerData: ConfigServerResponse | null = null;\r\n private isLoaded = false;\r\n\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly store: FrmkConfigStore\r\n ) {}\r\n\r\n /**\r\n * Carga la configuración desde el config-server\r\n */\r\n async loadConfig(): Promise<void> {\r\n try {\r\n const appConfig = this.store.appConfig();\r\n const url = `${appConfig.configServer.url}/${appConfig.configServer.frontend}`;\r\n \r\n this.configServerData = await firstValueFrom(\r\n this.http.get<ConfigServerResponse>(url)\r\n );\r\n \r\n // Aplicar datos del server al store — todos los computeds se recalculan automáticamente\r\n this.store.applyServerConfig(this.configServerData);\r\n \r\n this.isLoaded = true;\r\n } catch (error) {\r\n console.log(`Exception while loading config: ${error}`);\r\n this.store.applyServerConfig();\r\n this.isLoaded = true;\r\n }\r\n }\r\n\r\n /**\r\n * Obtiene un valor de configuración por clave del config server\r\n */\r\n get(key: string): string | boolean | undefined {\r\n return this.configServerData?.[key as keyof ConfigServerResponse];\r\n }\r\n\r\n /**\r\n * Obtiene toda la configuración del config server\r\n */\r\n getAll(): ConfigServerResponse | null {\r\n return this.configServerData ? { ...this.configServerData } : null;\r\n }\r\n\r\n /**\r\n * Verifica si la configuración ha sido cargada\r\n */\r\n isConfigLoaded(): boolean {\r\n return this.isLoaded;\r\n }\r\n\r\n /**\r\n * Obtiene la configuración final de la aplicación (con valores del config server aplicados)\r\n */\r\n getAppConfig(): AppConfiguration {\r\n return this.store.appConfig();\r\n }\r\n\r\n /**\r\n * Obtiene los datos raw del config server\r\n */\r\n getConfigServerData(): ConfigServerResponse | null {\r\n return this.configServerData;\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';\r\nimport { Observable, of } from 'rxjs';\r\nimport { catchError, map } from 'rxjs/operators';\r\nimport { AuthService } from './authentication.service';\r\nimport { ConfigService } from './config.service';\r\nimport { AuthorizationRequest, AuthorizationResponse, MenuHierarchyItem } from '../models/authorization.interface';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class AuthorizationService {\r\n\r\n constructor(\r\n private readonly http: HttpClient,\r\n private readonly authService: AuthService,\r\n private readonly configService: ConfigService\r\n ) {}\r\n\r\n /**\r\n * Verifica si el usuario tiene permisos para acceder a un recurso específico\r\n */\r\n verifyPermission(resourcePath: string, operationName: string = 'VIEW'): Observable<boolean> {\r\n const groups = this.getUserGroups();\r\n const config = this.configService.getAppConfig();\r\n \r\n if (groups.length === 0) {\r\n return of(false);\r\n }\r\n\r\n const request: AuthorizationRequest = {\r\n groupIds: groups,\r\n componentId: config.configServer.frontend,\r\n resourcePath: resourcePath,\r\n operationName: operationName\r\n };\r\n\r\n return this.checkAuthorization(request);\r\n }\r\n\r\n /**\r\n * Realiza la llamada HTTP al servicio de autorización\r\n */\r\n private checkAuthorization(request: AuthorizationRequest): Observable<boolean> {\r\n let params = new HttpParams();\r\n \r\n const cleanGroups = request.groupIds.map(group => group.replace(/\\//g, ''));\r\n const groupIdsString = cleanGroups.join(',');\r\n \r\n params = params.set('groupIds', groupIdsString);\r\n params = params.set('componentId', request.componentId);\r\n params = params.set('resourcePath', request.resourcePath);\r\n params = params.set('operationName', request.operationName);\r\n\r\n let headers = new HttpHeaders();\r\n\r\n const url = `${this.configService.getAppConfig().authorization.baseUrl}${this.configService.getAppConfig().authorization.verifyEndpoint}`;\r\n\r\n return this.http.get<AuthorizationResponse>(url, { \r\n params,\r\n headers\r\n }).pipe(\r\n map(response => {\r\n return response.hasPermission;\r\n }),\r\n catchError(() => {\r\n return of(false);\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Obtiene los grupos del usuario desde el access token\r\n */\r\n private getUserGroups(): string[] {\r\n return this.authService.getUserGroups();\r\n }\r\n\r\n /** \r\n * Método público para obtener los grupos del usuario (útil para debugging)\r\n */\r\n public getUserGroupsDebug(): string[] {\r\n return this.authService.getUserGroups();\r\n }\r\n\r\n /**\r\n * Obtiene la jerarquía de menús basada en el componente y los grupos del usuario\r\n */\r\n getMenuHierarchy(): Observable<MenuHierarchyItem[]> {\r\n const groups = this.getUserGroups();\r\n const config = this.configService.getAppConfig();\r\n \r\n if (groups.length === 0) {\r\n return of([]);\r\n }\r\n\r\n const cleanGroups = groups.map(group => group.replace(/\\//g, ''));\r\n const groupIdsString = cleanGroups.join(',');\r\n\r\n let params = new HttpParams();\r\n params = params.set('componentId', config.configServer.frontend);\r\n params = params.set('groupIds', groupIdsString);\r\n\r\n let headers = new HttpHeaders();\r\n\r\n const url = `${config.authorization.baseUrl}${config.authorization.hierarchyEndpoint}`;\r\n\r\n return this.http.get<MenuHierarchyItem[]>(url, { \r\n params,\r\n headers\r\n }).pipe(\r\n catchError(error => {\r\n console.error('Error obteniendo jerarquía de menús:', error);\r\n return of([]);\r\n })\r\n );\r\n }\r\n\r\n /**\r\n * Obtiene elementos de menú de nivel raíz (level 1)\r\n */\r\n getRootMenuItems(menuHierarchy: MenuHierarchyItem[]): MenuHierarchyItem[] {\r\n return menuHierarchy.filter(item => item.level === 1);\r\n }\r\n\r\n /**\r\n * Obtiene elementos hijos de un elemento padre específico por path\r\n */\r\n getChildMenuItems(menuHierarchy: MenuHierarchyItem[], parentPath: string, level: number): MenuHierarchyItem[] {\r\n return menuHierarchy.filter(item => \r\n item.level === level && \r\n item.hasParent && \r\n item.path.startsWith(parentPath) &&\r\n item.path !== parentPath &&\r\n this.isDirectChild(item.path, parentPath, level)\r\n );\r\n }\r\n\r\n /**\r\n * Verifica si un elemento tiene hijos\r\n */\r\n hasChildren(menuHierarchy: MenuHierarchyItem[], item: MenuHierarchyItem): boolean {\r\n return this.getChildMenuItems(menuHierarchy, item.path, item.level + 1).length > 0;\r\n }\r\n\r\n /**\r\n * Verifica si un path es hijo directo de otro path\r\n */\r\n private isDirectChild(childPath: string, parentPath: string, expectedLevel: number): boolean {\r\n const relativePath = childPath.substring(parentPath.length);\r\n const slashCount = (relativePath.match(/\\//g) || []).length;\r\n return slashCount === 1;\r\n }\r\n\r\n /**\r\n * Verifica múltiples permisos a la vez\r\n */\r\n verifyMultiplePermissions(permissions: { resourcePath: string, operationName?: string }[]): Observable<{ [key: string]: boolean }> {\r\n const results: { [key: string]: boolean } = {};\r\n const observables = permissions.map(permission => \r\n this.verifyPermission(permission.resourcePath, permission.operationName).pipe(\r\n map(authorized => ({ \r\n key: `${permission.resourcePath}_${permission.operationName || 'VIEW'}`, \r\n authorized \r\n }))\r\n )\r\n );\r\n\r\n return new Observable(observer => {\r\n let completed = 0;\r\n observables.forEach(obs => {\r\n obs.subscribe(result => {\r\n results[result.key] = result.authorized;\r\n completed++;\r\n if (completed === observables.length) {\r\n observer.next(results);\r\n observer.complete();\r\n }\r\n });\r\n });\r\n });\r\n }\r\n}\r\n","import { inject } from '@angular/core';\r\nimport { CanActivateFn, Router } from '@angular/router';\r\nimport { AuthService } from '../services/authentication.service';\r\nimport { map, take } from 'rxjs/operators';\r\n\r\nexport const authGuard: CanActivateFn = (route, state) => {\r\n const authService = inject(AuthService);\r\n const router = inject(Router);\r\n\r\n const handleAuthenticated = (): boolean => {\r\n return true;\r\n };\r\n\r\n const handleUnauthenticated = (currentUrl: string): boolean => {\r\n if (currentUrl !== '/login' && !currentUrl.includes('/login')) {\r\n router.navigate(['/login'], { \r\n queryParams: { returnUrl: currentUrl } \r\n });\r\n }\r\n return false;\r\n }; \r\n\r\n return authService.isAuthenticated$.pipe(\r\n take(1),\r\n map(isAuthenticated => {\r\n return isAuthenticated \r\n ? handleAuthenticated() \r\n : handleUnauthenticated(state.url);\r\n })\r\n );\r\n};\r\n","import { Component, OnInit, OnDestroy, input, computed, inject } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { Subscription } from 'rxjs';\r\nimport { AuthService } from '../../services/authentication.service';\r\nimport { FrmkConfigStore } from '../../services/frmk-config-store.service';\r\nimport { LoginConfig, DEFAULT_LOGIN_CONFIG } from '../../models/login-config.interface';\r\nimport { VERSION } from '../../version';\r\n\r\n@Component({\r\n selector: 'lib-login',\r\n standalone: true,\r\n imports: [CommonModule],\r\n templateUrl: './login.component.html',\r\n styleUrls: ['./login.component.scss']\r\n})\r\nexport class LoginComponent implements OnInit, OnDestroy {\r\n /**\r\n * Configuration object to customize the login component appearance and behavior\r\n */\r\n readonly config = input<Partial<LoginConfig>>({});\r\n\r\n private readonly store = inject(FrmkConfigStore);\r\n\r\n isLoggingIn = false;\r\n statusMessage = '';\r\n private authSubscription?: Subscription;\r\n private isProcessingCallback = false;\r\n\r\n /** Configuración merged: defaults ← libraryConfig.loginConfig ← @Input config */\r\n readonly mergedConfig = computed<LoginConfig>(() => {\r\n const storeConfig = this.store.isConfigured()\r\n ? this.store.loginConfig()\r\n : DEFAULT_LOGIN_CONFIG;\r\n const inputCfg = this.config() ?? {};\r\n return {\r\n ...storeConfig,\r\n ...inputCfg,\r\n version: inputCfg.version || storeConfig.version || VERSION\r\n };\r\n });\r\n\r\n constructor(public authService: AuthService) {}\r\n\r\n ngOnInit() {\r\n // Check if processing OAuth callback\r\n // Also check for 'iss' and 'session_state' which indicate we came from OAuth even if 'code' was already processed\r\n const urlParams = new URLSearchParams(globalThis.location?.search || '');\r\n const hasCode = urlParams.has('code');\r\n const hasIss = urlParams.has('iss');\r\n const hasSessionState = urlParams.has('session_state');\r\n const hasFragment = (globalThis.location?.hash || '').includes('access_token') || \r\n (globalThis.location?.hash || '').includes('code');\r\n \r\n if (hasCode || hasFragment || hasIss || hasSessionState) {\r\n this.isProcessingCallback = true;\r\n this.statusMessage = 'Procesando autenticación...';\r\n }\r\n\r\n // Subscribe to authentication state changes\r\n this.authSubscription = this.authService.isAuthenticated$.subscribe(isAuthenticated => {\r\n if (isAuthenticated) {\r\n this.statusMessage = '¡Autenticación exitosa! Redirigiendo...';\r\n // Small delay to show success message, then redirect\r\n setTimeout(() => {\r\n this.navigateToRedirect();\r\n }, 500);\r\n }\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n if (this.authSubscription) {\r\n this.authSubscription.unsubscribe();\r\n }\r\n }\r\n\r\n /**\r\n * Get merged configuration value\r\n */\r\n getConfig<K extends keyof LoginConfig>(key: K): LoginConfig[K] {\r\n return this.mergedConfig()[key];\r\n }\r\n\r\n /**\r\n * Get custom CSS styles for theming\r\n */\r\n getCustomStyles(): { [key: string]: string } {\r\n const styles: { [key: string]: string } = {};\r\n const cfg = this.mergedConfig();\r\n \r\n if (cfg.primaryColor) {\r\n styles['--color-primary'] = cfg.primaryColor;\r\n }\r\n if (cfg.backgroundColor) {\r\n styles['--login-bg-color'] = cfg.backgroundColor;\r\n }\r\n if (cfg.textColor) {\r\n styles['--login-text-color'] = cfg.textColor;\r\n }\r\n \r\n return styles;\r\n }\r\n\r\n login(): void {\r\n this.isLoggingIn = true;\r\n this.statusMessage = 'Redirigiendo al proveedor de autenticación...';\r\n \r\n setTimeout(() => {\r\n this.authService.login();\r\n }, 500);\r\n }\r\n\r\n logout(): void {\r\n this.authService.logout();\r\n this.isLoggingIn = false;\r\n this.statusMessage = '';\r\n this.isProcessingCallback = false;\r\n }\r\n\r\n goToDashboard(): void {\r\n this.navigateToRedirect();\r\n }\r\n\r\n private navigateToRedirect(): void {\r\n const redirectUrl = this.mergedConfig().redirectUrl;\r\n if (typeof globalThis.location !== 'undefined') {\r\n const baseUrl = `${globalThis.location.protocol}//${globalThis.location.host}`;\r\n globalThis.location.href = `${baseUrl}${redirectUrl}`;\r\n }\r\n }\r\n}\r\n","<div class=\"login-page\" [ngStyle]=\"getCustomStyles()\">\r\n <div class=\"login-page__container\">\r\n <!-- Logo -->\r\n <div class=\"login-page__logo\">\r\n <img \r\n [src]=\"getConfig('logoUrl')\" \r\n [alt]=\"getConfig('logoAlt')\" \r\n class=\"login-page__logo-img\"\r\n [style.width]=\"getConfig('logoWidth')\"\r\n [style.height]=\"getConfig('logoHeight')\" />\r\n </div>\r\n\r\n <!-- Header -->\r\n <div class=\"login-page__header\">\r\n <h1>{{ getConfig('title') }}</h1>\r\n <p *ngIf=\"getConfig('subtitle')\" class=\"subtitle\">{{ getConfig('subtitle') }}</p>\r\n </div>\r\n \r\n <!-- Login Form -->\r\n <div *ngIf=\"(authService.isDoneLoading$ | async)\" class=\"login-page__form\">\r\n <div *ngIf=\"!(authService.isAuthenticated$ | async)\">\r\n <!-- Status Message -->\r\n <div *ngIf=\"statusMessage\" class=\"auth-alert auth-alert--info\">\r\n <div class=\"auth-alert__content\">\r\n <p>{{ statusMessage }}</p>\r\n </div>\r\n </div>\r\n\r\n <!-- Login Button -->\r\n <button \r\n class=\"btn btn--primary btn--lg\" \r\n (click)=\"login()\" \r\n [disabled]=\"isLoggingIn\"\r\n [class.loading]=\"isLoggingIn\">\r\n {{ isLoggingIn ? 'Redirigiendo...' : getConfig('loginButtonText') }}\r\n </button>\r\n\r\n <!-- Footer -->\r\n <div class=\"login-page__footer\" *ngIf=\"getConfig('showFooter')\">\r\n <p *ngIf=\"getConfig('footerText'); else defaultFooter\">\r\n {{ getConfig('footerText') }}\r\n </p>\r\n <ng-template #defaultFooter>\r\n <p>\r\n Acceso seguro para usuarios de \r\n <strong>{{ getConfig('institutionName') }}</strong>\r\n </p>\r\n </ng-template>\r\n </div>\r\n </div>\r\n \r\n <!-- Already Authenticated -->\r\n <div *ngIf=\"authService.isAuthenticated$ | async\" class=\"auth-alert auth-alert--success\">\r\n <div class=\"auth-alert__content\">\r\n <h4>¡Sesión activa!</h4>\r\n <p>Ya tienes una sesión iniciada en el sistema.</p>\r\n </div>\r\n \r\n <div class=\"login-page__actions\">\r\n <button class=\"btn btn--primary btn--lg\" (click)=\"goToDashboard()\">\r\n {{ getConfig('dashboardButtonText') }}\r\n </button>\r\n \r\n <button \r\n *ngIf=\"getConfig('showLogoutButton')\"\r\n class=\"btn btn--secondary btn--lg\" \r\n (click)=\"logout()\">\r\n {{ getConfig('logoutButtonText') }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- Loading State -->\r\n <div *ngIf=\"!(authService.isDoneLoading$ | async)\" class=\"auth-loading\">\r\n <div class=\"auth-loading__spinner\"></div>\r\n <p class=\"auth-loading__text\">Procesando autenticación...</p>\r\n </div>\r\n\r\n <!-- Version -->\r\n <div *ngIf=\"getConfig('showVersion')\" class=\"login-page__version\">\r\n <span>v{{ getConfig('version') }}</span>\r\n </div>\r\n </div>\r\n</div>\r\n","import { Component, OnInit, HostListener, input, computed, inject } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { RouterModule } from '@angular/router';\r\nimport { AuthService } from '../../services/authentication.service';\r\nimport { AuthorizationService } from '../../services/authorization.service';\r\nimport { FrmkConfigStore } from '../../services/frmk-config-store.service';\r\nimport { MenuHierarchyItem } from '../../models/authorization.interface';\r\nimport { DashboardConfig, DEFAULT_DASHBOARD_CONFIG } from '../../models/dashboard-config.interface';\r\nimport { VERSION } from '../../version';\r\n\r\n// Re-export for backwards compatibility\r\nexport { DashboardConfig } from '../../models/dashboard-config.interface';\r\n\r\n@Component({\r\n selector: 'lib-dashboard',\r\n standalone: true,\r\n imports: [CommonModule, RouterModule],\r\n templateUrl: './dashboard.component.html',\r\n styleUrls: ['./dashboard.component.scss']\r\n})\r\nexport class DashboardComponent implements OnInit {\r\n readonly config = input<Partial<DashboardConfig>>({});\r\n\r\n private readonly store = inject(FrmkConfigStore);\r\n\r\n userInfo: any = null;\r\n userRoles: string[] = [];\r\n menuHierarchy: MenuHierarchyItem[] = [];\r\n isMenuOpen = false;\r\n isLoadingMenu = false;\r\n openMenuItems: Set<string> = new Set();\r\n isUserPanelOpen = false;\r\n isMobileMenuOpen = false;\r\n\r\n /** Configuración merged: defaults ← libraryConfig.dashboardConfig ← @Input config */\r\n readonly mergedConfig = computed<DashboardConfig>(() => {\r\n const storeConfig = this.store.isConfigured()\r\n ? this.store.dashboardConfig()\r\n : DEFAULT_DASHBOARD_CONFIG;\r\n const inputCfg = this.config() ?? {};\r\n return {\r\n ...storeConfig,\r\n ...inputCfg,\r\n version: inputCfg.version || storeConfig.version || VERSION\r\n };\r\n });\r\n\r\n constructor(\r\n public authService: AuthService,\r\n private readonly authorizationService: AuthorizationService\r\n ) {}\r\n\r\n ngOnInit(): void {\r\n this.loadUserInfo();\r\n this.loadMenuHierarchy();\r\n }\r\n\r\n getConfig<K extends keyof DashboardConfig>(key: K): DashboardConfig[K] {\r\n return this.mergedConfig()[key];\r\n }\r\n\r\n get appVersion(): string {\r\n return this.mergedConfig().version;\r\n }\r\n\r\n private loadUserInfo(): void {\r\n this.userInfo = this.authService.identityClaims;\r\n this.userRoles = this.authService.getUserRoles();\r\n }\r\n\r\n private loadMenuHierarchy(): void {\r\n this.isLoadingMenu = true;\r\n this.authorizationService.getMenuHierarchy().subscribe({\r\n next: (menuItems) => {\r\n this.menuHierarchy = this.buildHierarchicalMenu(menuItems);\r\n this.isLoadingMenu = false;\r\n },\r\n error: (error) => {\r\n console.error('Error loading menu hierarchy:', error);\r\n this.menuHierarchy = [];\r\n this.isLoadingMenu = false;\r\n }\r\n });\r\n }\r\n\r\n private buildHierarchicalMenu(flatItems: MenuHierarchyItem[]): MenuHierarchyItem[] {\r\n const itemMap = new Map<string, MenuHierarchyItem>();\r\n \r\n flatItems.forEach(item => {\r\n itemMap.set(item.path, { ...item, children: [] });\r\n });\r\n\r\n const rootItems: MenuHierarchyItem[] = [];\r\n \r\n flatItems.forEach(item => {\r\n const currentItem = itemMap.get(item.path)!;\r\n \r\n if (item.level === 1) {\r\n rootItems.push(currentItem);\r\n } else {\r\n const parent = this.findParent(item, flatItems);\r\n if (parent) {\r\n const parentItem = itemMap.get(parent.path);\r\n if (parentItem?.children) {\r\n parentItem.children.push(currentItem);\r\n }\r\n }\r\n }\r\n });\r\n\r\n return rootItems;\r\n }\r\n\r\n private findParent(item: MenuHierarchyItem, allItems: MenuHierarchyItem[]): MenuHierarchyItem | null {\r\n for (const potentialParent of allItems) {\r\n if (potentialParent.level === item.level - 1 && \r\n item.path.startsWith(potentialParent.path) &&\r\n item.path !== potentialParent.path) {\r\n return potentialParent;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n toggleMenuItem(itemId: string, item: MenuHierarchyItem): void {\r\n const isCurrentlyOpen = this.openMenuItems.has(itemId);\r\n \r\n if (isCurrentlyOpen) {\r\n this.closeMenuAndChildren(itemId);\r\n } else {\r\n this.closeSiblingMenus(item);\r\n this.openMenuItems.add(itemId);\r\n }\r\n }\r\n\r\n private closeMenuAndChildren(itemId: string): void {\r\n this.openMenuItems.delete(itemId);\r\n const itemsToClose = Array.from(this.openMenuItems).filter(id => id.startsWith(itemId + '-'));\r\n itemsToClose.forEach(id => this.openMenuItems.delete(id));\r\n }\r\n\r\n private closeSiblingMenus(currentItem: MenuHierarchyItem): void {\r\n if (currentItem.level === 1) {\r\n const rootItems = this.getRootMenuItems();\r\n rootItems.forEach(rootItem => {\r\n if (rootItem.code !== currentItem.code) {\r\n this.closeMenuAndChildren(rootItem.code);\r\n }\r\n });\r\n } else {\r\n const allItems = this.flattenMenuItems(this.menuHierarchy);\r\n const parent = this.findParent(currentItem, allItems);\r\n if (parent?.children) {\r\n parent.children.forEach(sibling => {\r\n if (sibling.code !== currentItem.code) {\r\n this.closeMenuAndChildren(sibling.code);\r\n }\r\n });\r\n }\r\n }\r\n }\r\n\r\n private flattenMenuItems(items: MenuHierarchyItem[]): MenuHierarchyItem[] {\r\n const flattened: MenuHierarchyItem[] = [];\r\n \r\n const flatten = (itemList: MenuHierarchyItem[]) => {\r\n itemList.forEach(item => {\r\n flattened.push(item);\r\n if (item.children) {\r\n flatten(item.children);\r\n }\r\n });\r\n };\r\n \r\n flatten(items);\r\n return flattened;\r\n }\r\n\r\n onMenuItemClick(event: Event, item: MenuHierarchyItem): void {\r\n if (this.hasChildren(item)) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.toggleMenuItem(item.code, item);\r\n } else {\r\n // Close mobile menu when navigating to a page\r\n this.closeMobileMenu();\r\n }\r\n }\r\n\r\n @HostListener('document:click', ['$event'])\r\n onDocumentClick(event: Event): void {\r\n const target = event.target as HTMLElement;\r\n const navElement = target.closest('.dashboard-nav');\r\n const userPanel = target.closest('.user-profile');\r\n \r\n if (!navElement) {\r\n this.openMenuItems.clear();\r\n }\r\n \r\n if (!userPanel) {\r\n this.isUserPanelOpen = false;\r\n }\r\n }\r\n\r\n toggleUserPanel(event: Event): void {\r\n event.stopPropagation();\r\n this.isUserPanelOpen = !this.isUserPanelOpen;\r\n }\r\n\r\n getUsername(): string {\r\n if (!this.userInfo?.preferred_username) return 'usuario';\r\n const username = this.userInfo.preferred_username;\r\n const atIndex = username.indexOf('@');\r\n return atIndex > 0 ? username.substring(0, atIndex) : username;\r\n }\r\n\r\n getUserFullName(): string {\r\n return this.userInfo?.name || 'Usuario';\r\n }\r\n\r\n getDocument(): string {\r\n return this.userInfo?.dui || 'N/A';\r\n }\r\n\r\n getInstitution(): string {\r\n return this.userInfo?.direccion || 'N/A';\r\n }\r\n\r\n getDependency(): string {\r\n return this.userInfo?.dependencia || 'N/A';\r\n }\r\n\r\n getRole(): string {\r\n return this.userInfo?.cargo || 'N/A';\r\n }\r\n\r\n isMenuItemOpen(itemId: string): boolean {\r\n return this.openMenuItems.has(itemId);\r\n }\r\n\r\n hasChildren(item: MenuHierarchyItem): boolean {\r\n return !!(item.children && item.children.length > 0);\r\n }\r\n\r\n getRootMenuItems(): MenuHierarchyItem[] {\r\n return this.menuHierarchy.filter(item => item.level === 1);\r\n }\r\n\r\n /**\r\n * Obtiene el icono para un item del menú.\r\n * Si el item tiene un icono definido, lo usa; de lo contrario, usa un icono por defecto según el nivel.\r\n */\r\n getMenuIcon(item: MenuHierarchyItem): string {\r\n // Si tiene icono definido, usarlo\r\n if (item.icono && item.icono.trim() !== '') {\r\n return item.icono;\r\n }\r\n \r\n // Iconos por defecto según el nivel\r\n if (item.level === 1) {\r\n return 'folder';\r\n } else if (item.level === 2) {\r\n return 'article';\r\n } else {\r\n return 'radio_button_unchecked';\r\n }\r\n }\r\n\r\n logoutAndRedirect(): void {\r\n this.authService.logoutAndRedirect();\r\n }\r\n\r\n getUserInitials(): string {\r\n if (!this.userInfo) return 'U';\r\n \r\n const name = this.userInfo.name || this.userInfo.preferred_username || 'Usuario';\r\n const words = name.split(' ');\r\n \r\n if (words.length >= 2) {\r\n return (words[0][0] + words[1][0]).toUpperCase();\r\n } else {\r\n return name.substring(0, 2).toUpperCase();\r\n }\r\n }\r\n\r\n toggleMobileMenu(): void {\r\n this.isMobileMenuOpen = !this.isMobileMenuOpen;\r\n }\r\n\r\n closeMobileMenu(): void {\r\n this.isMobileMenuOpen = false;\r\n document.body.style.overflow = '';\r\n }\r\n}\r\n","<div class=\"dashboard\">\r\n <!-- Header -->\r\n <header class=\"dashboard-header\">\r\n <!-- Mobile Header Top -->\r\n <div class=\"header-mobile-top\">\r\n <div class=\"ministry-logo-mobile\">\r\n <img [src]=\"getConfig('logoUrl')\" [alt]=\"getConfig('logoAlt')\" />\r\n </div>\r\n <h1 class=\"mobile-title\">{{ getConfig('title') }}</h1>\r\n </div>\r\n\r\n <!-- Mobile Header Bottom -->\r\n <div class=\"header-mobile-bottom\">\r\n <button class=\"hamburger-btn\" \r\n (click)=\"toggleMobileMenu()\"\r\n [class.active]=\"isMobileMenuOpen\"\r\n aria-label=\"Toggle menu\">\r\n <span class=\"hamburger-line\"></span>\r\n <span class=\"hamburger-line\"></span>\r\n <span class=\"hamburger-line\"></span>\r\n </button>\r\n\r\n <div class=\"user-profile mobile-user\" *ngIf=\"userInfo\">\r\n <button class=\"user-info-trigger\" \r\n (click)=\"toggleUserPanel($event)\"\r\n [attr.aria-expanded]=\"isUserPanelOpen\"\r\n aria-label=\"Abrir menú de usuario\">\r\n <div class=\"user-avatar\">\r\n <span>{{ getUserInitials() }}</span>\r\n </div>\r\n <div class=\"user-details\">\r\n <span class=\"user-name\">{{ getUsername() }}</span>\r\n </div>\r\n <span class=\"material-symbols-outlined dropdown-icon\">\r\n {{ isUserPanelOpen ? 'expand_less' : 'expand_more' }}\r\n </span>\r\n </button>\r\n \r\n <!-- User Panel -->\r\n <ng-container *ngTemplateOutlet=\"userPanelTemplate\"></ng-container>\r\n </div>\r\n </div>\r\n\r\n <!-- Desktop Header -->\r\n <div class=\"header-desktop-layout\">\r\n <div class=\"header-left\">\r\n <div class=\"ministry-logo\">\r\n <div class=\"logo-icon\">\r\n <img [src]=\"getConfig('logoUrl')\" [alt]=\"getConfig('logoAlt')\" />\r\n </div>\r\n <div class=\"ministry-info\">\r\n <h1>{{ getConfig('title') }}</h1>\r\n <span class=\"subtitle\" *ngIf=\"getConfig('subtitle')\">{{ getConfig('subtitle') }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <div class=\"header-right\">\r\n <div class=\"user-profile desktop-user\" *ngIf=\"userInfo\">\r\n <button class=\"user-info-trigger\" \r\n (click)=\"toggleUserPanel($event)\"\r\n [attr.aria-expanded]=\"isUserPanelOpen\"\r\n aria-label=\"Abrir menú de usuario\">\r\n <div class=\"user-avatar\">\r\n <span>{{ getUserInitials() }}</span>\r\n </div>\r\n <div class=\"user-details\">\r\n <span class=\"user-name\">{{ getUsername() }}</span>\r\n </div>\r\n <span class=\"material-symbols-outlined dropdown-icon\">\r\n {{ isUserPanelOpen ? 'expand_less' : 'expand_more' }}\r\n </span>\r\n </button>\r\n \r\n <!-- User Panel -->\r\n <ng-container *ngTemplateOutlet=\"userPanelTemplate\"></ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n </header>\r\n\r\n <!-- User Panel Template -->\r\n <ng-template #userPanelTemplate>\r\n <div class=\"user-panel\" *ngIf=\"isUserPanelOpen\">\r\n <div class=\"user-panel-header\">\r\n <span class=\"panel-title\">Perfil de Usuario</span>\r\n </div>\r\n <div class=\"user-panel-content\">\r\n <div class=\"user-info-item\">\r\n <span class=\"material-symbols-outlined info-icon\">person</span>\r\n <div class=\"info-content\">\r\n <span class=\"info-label\">Código de Usuario:</span>\r\n <span class=\"info-value\">{{ getUsername() }}</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"user-info-item\">\r\n <span class=\"material-symbols-outlined info-icon\">badge</span>\r\n <div class=\"info-content\">\r\n <span class=\"info-label\">Nombre de Usuario:</span>\r\n <span class=\"info-value\">{{ getUserFullName() }}</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"user-info-item\">\r\n <span class=\"material-symbols-outlined info-icon\">credit_card</span>\r\n <div class=\"info-content\">\r\n <span class=\"info-label\">Documento:</span>\r\n <span class=\"info-value\">{{ getDocument() }}</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"user-info-item mobile-hidden\">\r\n <span class=\"material-symbols-outlined info-icon\">business</span>\r\n <div class=\"info-content\">\r\n <span class=\"info-label\">Institución:</span>\r\n <span class=\"info-value\">{{ getInstitution() }}</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"user-info-item mobile-hidden\">\r\n <span class=\"material-symbols-outlined info-icon\">apartment</span>\r\n <div class=\"info-content\">\r\n <span class=\"info-label\">Dependencia:</span>\r\n <span class=\"info-value\">{{ getDependency() }}</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"user-info-item mobile-hidden\">\r\n <span class=\"material-symbols-outlined info-icon\">work</span>\r\n <div class=\"info-content\">\r\n <span class=\"info-label\">Rol:</span>\r\n <span class=\"info-value\">{{ getRole() }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"user-panel-footer\">\r\n <button class=\"logout-btn-panel\" (click)=\"logoutAndRedirect()\" title=\"Cerrar sesión\">\r\n <span class=\"material-symbols-outlined\">logout</span>\r\n <span class=\"logout-text\">CERRAR SESIÓN</span>\r\n </button>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <!-- Mobile Menu Overlay -->\r\n <div class=\"nav-overlay\" *ngIf=\"isMobileMenuOpen\" (click)=\"closeMobileMenu()\"></div>\r\n\r\n <!-- Navigation (Horizontal Desktop / Sidebar Mobile) -->\r\n <nav class=\"dashboard-nav\" [class.mobile-open]=\"isMobileMenuOpen\">\r\n <div class=\"nav-mobile-header\">\r\n <div class=\"nav-mobile-logo\">\r\n <img [src]=\"getConfig('logoUrl')\" [alt]=\"getConfig('logoAlt')\" />\r\n <span class=\"nav-mobile-title\">Menú</span>\r\n </div>\r\n <button class=\"nav-close-btn\" (click)=\"closeMobileMenu()\" aria-label=\"Cerrar menú\">\r\n <span class=\"material-symbols-outlined\">close</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"nav-container\">\r\n <!-- Static Menu Items -->\r\n <ng-container *ngIf=\"getConfig('showStaticMenu')\">\r\n <a routerLink=\".\" \r\n routerLinkActive=\"active\" \r\n [routerLinkActiveOptions]=\"{exact: true}\" \r\n class=\"nav-item\"\r\n (click)=\"closeMobileMenu()\">\r\n <span class=\"material-symbols-outlined nav-icon\">home</span>\r\n <span class=\"nav-text\">Inicio</span>\r\n </a>\r\n </ng-container>\r\n\r\n <!-- Separator -->\r\n <div class=\"nav-separator\" *ngIf=\"!isLoadingMenu && menuHierarchy.length > 0\"></div>\r\n \r\n <!-- Dynamic Menu -->\r\n <div class=\"dynamic-menu\" *ngIf=\"!isLoadingMenu && menuHierarchy.length > 0\">\r\n <ng-container *ngFor=\"let rootItem of getRootMenuItems()\">\r\n <div class=\"menu-item-container\" [class.has-children]=\"hasChildren(rootItem)\">\r\n <a \r\n [routerLink]=\"hasChildren(rootItem) ? null : rootItem.path\" \r\n routerLinkActive=\"active\" \r\n class=\"nav-item root-item\"\r\n [class.expandable]=\"hasChildren(rootItem)\"\r\n (click)=\"onMenuItemClick($event, rootItem)\">\r\n <span class=\"material-symbols-outlined nav-icon\">{{ getMenuIcon(rootItem) }}</span>\r\n <span class=\"nav-text\">{{ rootItem.name }}</span>\r\n <span class=\"material-symbols-outlined expand-icon\" *ngIf=\"hasChildren(rootItem)\">\r\n {{ isMenuItemOpen(rootItem.code) ? 'expand_more' : 'chevron_right' }}\r\n </span>\r\n </a>\r\n \r\n <!-- Submenu -->\r\n <div class=\"submenu\" *ngIf=\"hasChildren(rootItem) && isMenuItemOpen(rootItem.code)\">\r\n <ng-container *ngTemplateOutlet=\"menuTemplate; context: { items: rootItem.children, level: 2 }\"></ng-container>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n \r\n <!-- Loading Indicator -->\r\n <div class=\"menu-loading\" *ngIf=\"isLoadingMenu\">\r\n <span class=\"material-symbols-outlined nav-icon\">hourglass_empty</span>\r\n <span class=\"nav-text\">Cargando menú...</span>\r\n </div>\r\n </div>\r\n </nav>\r\n\r\n <!-- Recursive Menu Template -->\r\n <ng-template #menuTemplate let-items=\"items\" let-level=\"level\">\r\n <ng-container *ngFor=\"let item of items\">\r\n <div class=\"menu-item-container\" [class.has-children]=\"hasChildren(item)\" [attr.data-level]=\"level\">\r\n <a \r\n [routerLink]=\"hasChildren(item) ? null : item.path\" \r\n routerLinkActive=\"active\" \r\n class=\"nav-item submenu-item\"\r\n [class.expandable]=\"hasChildren(item)\"\r\n (click)=\"onMenuItemClick($event, item)\">\r\n <span class=\"material-symbols-outlined nav-icon\">{{ getMenuIcon(item) }}</span>\r\n <span class=\"nav-text\">{{ item.name }}</span>\r\n <span class=\"material-symbols-outlined expand-icon\" *ngIf=\"hasChildren(item)\">\r\n {{ isMenuItemOpen(item.code) ? 'expand_more' : 'chevron_right' }}\r\n </span>\r\n </a>\r\n\r\n <!-- Recursive Submenu (max 5 levels) -->\r\n <div class=\"submenu\" *ngIf=\"hasChildren(item) && isMenuItemOpen(item.code) && level < 5\">\r\n <ng-container *ngTemplateOutlet=\"menuTemplate; context: { items: item.children, level: level + 1 }\"></ng-container>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </ng-template>\r\n\r\n <!-- Main Content -->\r\n <main class=\"dashboard-content\">\r\n <div class=\"content-wrapper\">\r\n <router-outlet></router-outlet>\r\n </div>\r\n </main>\r\n\r\n <!-- Footer -->\r\n <footer class=\"dashboard-footer\">\r\n <div class=\"footer-content\">\r\n <span class=\"footer-text\">\r\n {{ getConfig('footerText') }}\r\n <ng-container *ngIf=\"getConfig('showVersion')\">\r\n Versión {{ appVersion }}.\r\n </ng-container>\r\n Todos los derechos reservados.\r\n </span>\r\n </div>\r\n </footer>\r\n</div>\r\n","// ========================================\r\n// @dinafi/frmk - Public API\r\n// Angular Shared Library - Ministerio de Hacienda\r\n// ========================================\r\n\r\n// === VERSION ===\r\nexport { VERSION, VERSION_INFO } from './lib/version';\r\n\r\n// === MODELS / INTERFACES ===\r\nexport {\r\n // Login Configuration\r\n LoginConfig,\r\n DEFAULT_LOGIN_CONFIG,\r\n \r\n // Dashboard Configuration\r\n DashboardConfig,\r\n DEFAULT_DASHBOARD_CONFIG,\r\n \r\n // Application Configuration\r\n AppConfiguration,\r\n ConfigServerResponse,\r\n \r\n // Authorization\r\n AuthorizationRequest,\r\n AuthorizationResponse,\r\n MenuHierarchyItem,\r\n MenuHierarchyRequest,\r\n \r\n // Library Configuration\r\n FrmkLibraryConfig,\r\n DEFAULT_LIBRARY_CONFIG\r\n} from './lib/models';\r\n\r\n// === SERVICES ===\r\nexport {\r\n // Central Configuration Store (v2.0 — reemplaza funciones globales)\r\n FrmkConfigStore,\r\n \r\n // Token Storage Service (v2.0.3 — centraliza localStorage/sessionStorage)\r\n TokenStorageService,\r\n \r\n // Authentication Service\r\n AuthService,\r\n \r\n // Authorization Service\r\n AuthorizationService,\r\n \r\n // Configuration Service\r\n ConfigService\r\n} from './lib/services';\r\n\r\n// === GUARDS ===\r\nexport { authGuard } from './lib/guards';\r\n\r\n// === COMPONENTS ===\r\nexport { \r\n LoginComponent \r\n} from './lib/components/login/login.component';\r\n\r\nexport { \r\n DashboardComponent\r\n} from './lib/components/dashboard/dashboard.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i2","i3.FrmkConfigStore","i4.TokenStorageService","i1","i2.FrmkConfigStore","i2.AuthService","i3.ConfigService","i1.AuthService","i2.AuthorizationService"],"mappings":"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"}
package/index.d.ts CHANGED
@@ -10,14 +10,14 @@ import { HttpClient } from '@angular/common/http';
10
10
  * Versión actual de la librería @dinafi/frmk
11
11
  * Sincronizada con package.json
12
12
  */
13
- declare const VERSION = "2.0.2";
13
+ declare const VERSION = "2.0.3";
14
14
  /**
15
15
  * Información completa de la versión
16
16
  */
17
17
  declare const VERSION_INFO: {
18
- readonly version: "2.0.2";
18
+ readonly version: "2.0.3";
19
19
  readonly name: "shared-lib-angular";
20
- readonly buildDate: "2026-02-05T20:47:48.315Z";
20
+ readonly buildDate: "2026-02-05T21:05:38.248Z";
21
21
  readonly angular: "^20.0.0";
22
22
  };
23
23
 
@@ -312,30 +312,79 @@ declare class FrmkConfigStore {
312
312
  static ɵprov: i0.ɵɵInjectableDeclaration<FrmkConfigStore>;
313
313
  }
314
314
 
315
+ /**
316
+ * Servicio centralizado para gestión de tokens en localStorage / sessionStorage.
317
+ *
318
+ * - Elimina las 4+ listas de keys duplicadas e inconsistentes que existían en AuthService.
319
+ * - Opera simétricamente sobre ambos storages.
320
+ * - Soporta la key dinámica `refresh_token_{clientId}` que usa angular-oauth2-oidc.
321
+ * - Expone métodos públicos para que la plantilla pueda leer tokens sin acceder a storage directamente.
322
+ *
323
+ * @example
324
+ * // Desde la librería (AuthService):
325
+ * this.tokenStorage.clearAll();
326
+ *
327
+ * // Desde la plantilla (skeleton):
328
+ * const expired = this.tokenStorage.isTokenExpired();
329
+ */
330
+ declare class TokenStorageService {
331
+ /**
332
+ * Limpia TODOS los tokens y estado OAuth de ambos storages.
333
+ * Incluye la key dinámica `refresh_token_{clientId}` si se proporciona.
334
+ *
335
+ * @param clientId — clientId de OAuth para limpiar `refresh_token_{clientId}` (opcional)
336
+ */
337
+ clearAll(clientId?: string): void;
338
+ /**
339
+ * Limpia tokens pero MANTIENE las keys de estado OAuth necesarias para
340
+ * validar el callback (nonce, PKCE_verifier, code_verifier, session_state, state).
341
+ *
342
+ * Usar durante un callback OAuth antes de procesar el authorization code.
343
+ */
344
+ clearTokensKeepState(): void;
345
+ /**
346
+ * Lee un valor de localStorage o sessionStorage (en ese orden de prioridad).
347
+ */
348
+ getItem(key: string): string | null;
349
+ /**
350
+ * Obtiene el refresh_token, incluyendo la variante dinámica `refresh_token_{clientId}`.
351
+ *
352
+ * @param clientId — clientId de OAuth (opcional)
353
+ */
354
+ getRefreshToken(clientId?: string): string | null;
355
+ /**
356
+ * Obtiene el access_token de cualquier storage.
357
+ */
358
+ getAccessToken(): string | null;
359
+ /**
360
+ * Verifica si hay un token almacenado y está expirado.
361
+ * Retorna `false` si no existe `expires_at` (no hay token, no está "expirado").
362
+ */
363
+ isTokenExpired(): boolean;
364
+ /**
365
+ * Elimina una key específica de ambos storages.
366
+ */
367
+ removeItem(key: string): void;
368
+ static ɵfac: i0.ɵɵFactoryDeclaration<TokenStorageService, never>;
369
+ static ɵprov: i0.ɵɵInjectableDeclaration<TokenStorageService>;
370
+ }
371
+
315
372
  declare class AuthService {
316
373
  private readonly oauthService;
317
374
  private readonly router;
318
375
  private readonly store;
376
+ private readonly tokenStorage;
319
377
  private readonly isAuthenticatedSubject$;
320
378
  isAuthenticated$: rxjs.Observable<boolean>;
321
379
  private readonly isDoneLoadingSubject$;
322
380
  isDoneLoading$: rxjs.Observable<boolean>;
323
381
  private isInitialLogin;
324
- constructor(oauthService: OAuthService, router: Router, store: FrmkConfigStore);
382
+ constructor(oauthService: OAuthService, router: Router, store: FrmkConfigStore, tokenStorage: TokenStorageService);
325
383
  /**
326
384
  * Limpia tokens expirados al iniciar la aplicación
327
385
  * Solo limpia si NO estamos en un callback OAuth
328
386
  */
329
387
  private clearExpiredTokensOnStartup;
330
- /**
331
- * Limpia todos los tokens del storage
332
- */
333
- private clearAllTokens;
334
- /**
335
- * Limpia tokens antiguos pero MANTIENE state, nonce y PKCE_verifier
336
- * que son necesarios para validar el callback OAuth
337
- */
338
- private clearOldTokensKeepState;
339
388
  private handleSuccessfulAuthentication;
340
389
  /**
341
390
  * Limpia los parámetros OAuth de la URL después del login exitoso
@@ -345,7 +394,7 @@ declare class AuthService {
345
394
  private handleSilentRefresh;
346
395
  private handleLogout;
347
396
  /**
348
- * Limpia todos los tokens del storage
397
+ * Limpia todos los tokens del storage y resetea OAuthService
349
398
  */
350
399
  private clearTokenStorage;
351
400
  /**
@@ -555,5 +604,5 @@ declare class DashboardComponent implements OnInit {
555
604
  static ɵcmp: i0.ɵɵComponentDeclaration<DashboardComponent, "lib-dashboard", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
556
605
  }
557
606
 
558
- export { AuthService, AuthorizationService, ConfigService, DEFAULT_DASHBOARD_CONFIG, DEFAULT_LIBRARY_CONFIG, DEFAULT_LOGIN_CONFIG, DashboardComponent, FrmkConfigStore, LoginComponent, VERSION, VERSION_INFO, authGuard };
607
+ export { AuthService, AuthorizationService, ConfigService, DEFAULT_DASHBOARD_CONFIG, DEFAULT_LIBRARY_CONFIG, DEFAULT_LOGIN_CONFIG, DashboardComponent, FrmkConfigStore, LoginComponent, TokenStorageService, VERSION, VERSION_INFO, authGuard };
559
608
  export type { AppConfiguration, AuthorizationRequest, AuthorizationResponse, ConfigServerResponse, DashboardConfig, FrmkLibraryConfig, LoginConfig, MenuHierarchyItem, MenuHierarchyRequest };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shared-lib-angular",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "Angular Librería Framework para autenticación, autorización y componentes de UI",
5
5
  "keywords": [
6
6
  "angular",