valtech-components 2.0.864 → 2.0.866

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.
@@ -2,5 +2,5 @@
2
2
  * Current version of valtech-components.
3
3
  * This is automatically updated during the publish process.
4
4
  */
5
- export const VERSION = '2.0.864';
6
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvdmVyc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDdXJyZW50IHZlcnNpb24gb2YgdmFsdGVjaC1jb21wb25lbnRzLlxuICogVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHVwZGF0ZWQgZHVyaW5nIHRoZSBwdWJsaXNoIHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gJzIuMC44NjQnO1xuIl19
5
+ export const VERSION = '2.0.866';
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvdmVyc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDdXJyZW50IHZlcnNpb24gb2YgdmFsdGVjaC1jb21wb25lbnRzLlxuICogVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHVwZGF0ZWQgZHVyaW5nIHRoZSBwdWJsaXNoIHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gJzIuMC44NjYnO1xuIl19
@@ -1,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, Injectable, makeEnvironmentProviders, APP_INITIALIZER, inject, EventEmitter, Component, Input, Output, input, computed, ChangeDetectionStrategy, HostBinding, HostListener, Pipe, effect, ViewChild, ChangeDetectorRef, ContentChild, PLATFORM_ID, Inject, ErrorHandler, DestroyRef, InjectionToken, runInInjectionContext, Optional, output, Injector, TemplateRef, ViewContainerRef, isSignal, Directive, ElementRef, ViewEncapsulation } from '@angular/core';
2
+ import { signal, Injectable, makeEnvironmentProviders, APP_INITIALIZER, inject, EventEmitter, Component, Input, Output, input, computed, ChangeDetectionStrategy, HostBinding, PLATFORM_ID, Inject, HostListener, Pipe, effect, ViewChild, ChangeDetectorRef, ContentChild, ErrorHandler, DestroyRef, InjectionToken, runInInjectionContext, Optional, output, Injector, TemplateRef, ViewContainerRef, isSignal, Directive, ElementRef, ViewEncapsulation } from '@angular/core';
3
3
  import * as i2$1 from '@ionic/angular/standalone';
4
4
  import { IonAvatar, IonCard, IonIcon, IonButton, IonSpinner, IonText, IonModal, IonHeader, IonToolbar, IonContent, IonButtons, IonTitle, IonProgressBar, IonSkeletonText, IonFab, IonFabButton, IonFabList, IonLabel, IonCardContent, IonCardHeader, IonCardTitle, IonCardSubtitle, IonCheckbox, IonTextarea, IonDatetime, IonDatetimeButton, IonInput, IonSelect, IonSelectOption, IonPopover, IonList, IonItem, IonRadioGroup, IonRadio, IonRange, IonSearchbar, IonSegment, IonSegmentButton, IonToggle, IonAccordion, IonAccordionGroup, IonTabBar, IonTabButton, IonBadge, IonBreadcrumb, IonBreadcrumbs, IonChip, IonNote, ToastController as ToastController$1, IonCol, IonRow, IonRefresher, IonRefresherContent, IonRippleEffect, AlertController, IonMenuButton, IonFooter, IonListHeader, IonInfiniteScroll, IonInfiniteScrollContent, IonGrid, MenuController, IonMenu, IonMenuToggle, IonSplitPane } from '@ionic/angular/standalone';
5
5
  import * as i1 from '@angular/common';
6
- import { CommonModule, NgStyle, NgFor, isPlatformBrowser, DOCUMENT, NgClass } from '@angular/common';
6
+ import { CommonModule, NgStyle, isPlatformBrowser, NgFor, DOCUMENT, NgClass } from '@angular/common';
7
7
  import { addIcons } from 'ionicons';
8
8
  import { addOutline, addCircleOutline, alertOutline, alertCircleOutline, arrowBackOutline, arrowForwardOutline, arrowDownOutline, settings, settingsOutline, checkmarkCircleOutline, ellipsisHorizontalOutline, notifications, notificationsOutline, openOutline, closeOutline, chatbubblesOutline, shareOutline, heart, heartOutline, home, homeOutline, eyeOffOutline, eyeOutline, scanOutline, chevronDownOutline, chevronForwardOutline, checkmarkOutline, clipboardOutline, copyOutline, filterOutline, locationOutline, calendarOutline, businessOutline, logoTwitter, logoInstagram, logoLinkedin, logoYoutube, logoTiktok, logoFacebook, logoGoogle, createOutline, trashOutline, playOutline, peopleOutline, phonePortraitOutline, refreshOutline, documentTextOutline, lockClosedOutline, informationCircleOutline, logoNpm, removeOutline, optionsOutline, personOutline, shieldCheckmarkOutline, keyOutline, desktopOutline, logOutOutline, cloudDownloadOutline, warningOutline, add, close, share, create, trash, star, camera, mic, send, downloadOutline, chevronDown, language, globeOutline, checkmark, list, grid, apps, menu, search, person, helpCircle, informationCircle, documentText, mail, calendar, folder, chevronForward, ellipsisHorizontal, chevronBack, playBack, playForward, ellipse, starOutline, starHalf, heartHalf, checkmarkCircle, timeOutline, flag, trendingUp, trendingDown, remove, analytics, people, cash, cart, eye, chatbubbleOutline, thumbsUpOutline, thumbsUp, happyOutline, happy, sadOutline, sad, chevronUp, pin, pencil, callOutline, logoWhatsapp, paperPlaneOutline, mailOutline, chevronDownCircleOutline, closeCircle, alertCircle, logoApple, logoMicrosoft, linkOutline, unlinkOutline, cloudOfflineOutline, documentOutline, attachOutline, cameraOutline, closeCircleOutline, imageOutline, chevronBackOutline, sendOutline, chatbubbleEllipsesOutline, swapVerticalOutline, chevronUpOutline, searchOutline, cartOutline, chatbubble, compass, compassOutline, gridOutline, listOutline, folderOutline, documents, documentsOutline, statsChart, statsChartOutline, menuOutline } from 'ionicons/icons';
9
9
  import * as i1$1 from '@angular/router';
@@ -53,7 +53,7 @@ import 'prismjs/components/prism-json';
53
53
  * Current version of valtech-components.
54
54
  * This is automatically updated during the publish process.
55
55
  */
56
- const VERSION = '2.0.864';
56
+ const VERSION = '2.0.866';
57
57
 
58
58
  /**
59
59
  * Servicio para gestionar presets de componentes.
@@ -800,7 +800,7 @@ function getTimeOfDayKey(date = new Date()) {
800
800
  * this.i18n.setLanguage('en');
801
801
  */
802
802
  class I18nService {
803
- constructor() {
803
+ constructor(platformId) {
804
804
  // Estado interno con Signals
805
805
  this._lang = signal(DEFAULT_I18N_CONFIG.defaultLanguage);
806
806
  this._content = signal({});
@@ -811,6 +811,7 @@ class I18nService {
811
811
  // Computed para verificaciones rápidas
812
812
  this.isSpanish = computed(() => this._lang() === 'es');
813
813
  this.isEnglish = computed(() => this._lang() === 'en');
814
+ this.isBrowser = isPlatformBrowser(platformId);
814
815
  this.loadStoredLanguage();
815
816
  }
816
817
  /**
@@ -892,12 +893,14 @@ class I18nService {
892
893
  if (lang === this._lang()) {
893
894
  return;
894
895
  }
895
- // Persistir en localStorage
896
- localStorage.setItem(LANG_STORAGE_KEY$1, lang);
896
+ // Persistir en localStorage (browser-only)
897
+ if (this.isBrowser) {
898
+ localStorage.setItem(LANG_STORAGE_KEY$1, lang);
899
+ }
897
900
  // Actualizar signal
898
901
  this._lang.set(lang);
899
902
  // Fallback: recargar si se solicita
900
- if (forceReload) {
903
+ if (forceReload && this.isBrowser) {
901
904
  window.location.reload();
902
905
  }
903
906
  }
@@ -952,6 +955,11 @@ class I18nService {
952
955
  * Carga idioma guardado en localStorage o detecta del navegador
953
956
  */
954
957
  loadStoredLanguage() {
958
+ // SSR: sin localStorage/navigator. Mantenemos el default; el browser
959
+ // hydratará el lang real cuando el cliente arranque.
960
+ if (!this.isBrowser) {
961
+ return;
962
+ }
955
963
  const stored = localStorage.getItem(LANG_STORAGE_KEY$1);
956
964
  if (stored && this.isValidLanguage(stored)) {
957
965
  this._lang.set(stored);
@@ -982,13 +990,16 @@ class I18nService {
982
990
  return result.replace(regex, value);
983
991
  }, text);
984
992
  }
985
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: I18nService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
993
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: I18nService, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
986
994
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: I18nService, providedIn: 'root' }); }
987
995
  }
988
996
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: I18nService, decorators: [{
989
997
  type: Injectable,
990
998
  args: [{ providedIn: 'root' }]
991
- }], ctorParameters: () => [] });
999
+ }], ctorParameters: () => [{ type: Object, decorators: [{
1000
+ type: Inject,
1001
+ args: [PLATFORM_ID]
1002
+ }] }] });
992
1003
 
993
1004
  /**
994
1005
  * Configuracion por defecto para header tipo 'home'
@@ -4735,7 +4746,8 @@ function provideValtechI18n(config = {}) {
4735
4746
  return makeEnvironmentProviders([
4736
4747
  {
4737
4748
  provide: APP_INITIALIZER,
4738
- useFactory: (i18n) => {
4749
+ useFactory: (i18n, platformId) => {
4750
+ const isBrowser = isPlatformBrowser(platformId);
4739
4751
  return () => {
4740
4752
  // Configurar idiomas soportados
4741
4753
  i18n.setI18nLanguages(mergedConfig.supportedLanguages);
@@ -4758,6 +4770,11 @@ function provideValtechI18n(config = {}) {
4758
4770
  // Sin detección de navegador: forzar idioma por defecto
4759
4771
  i18n.setLanguage(mergedConfig.defaultLanguage);
4760
4772
  }
4773
+ else if (!isBrowser) {
4774
+ // SSR: sin localStorage/navigator → forzar default. El cliente
4775
+ // re-evaluará en hydrate vía I18nService.loadStoredLanguage().
4776
+ i18n.setLanguage(mergedConfig.defaultLanguage);
4777
+ }
4761
4778
  else {
4762
4779
  // Con detección: re-evaluar ahora que supportedLanguages está configurado
4763
4780
  const stored = localStorage.getItem('app_lang');
@@ -4773,7 +4790,7 @@ function provideValtechI18n(config = {}) {
4773
4790
  }
4774
4791
  };
4775
4792
  },
4776
- deps: [I18nService],
4793
+ deps: [I18nService, PLATFORM_ID],
4777
4794
  multi: true,
4778
4795
  },
4779
4796
  ]);
@@ -8376,36 +8393,46 @@ const THEME = 'THEME';
8376
8393
  /**
8377
8394
  * Utility service for interacting with browser localStorage in a type-safe way.
8378
8395
  * Provides static methods for setting, getting, removing, and clearing items.
8396
+ *
8397
+ * SSR-safe: en Node (prerender) `localStorage` no existe — los métodos son no-ops
8398
+ * en server. `get` retorna `null` casteado a `T`, igual que cuando la key no
8399
+ * existe en browser.
8379
8400
  */
8380
8401
  class LocalStorageService {
8402
+ static get available() {
8403
+ return typeof localStorage !== 'undefined';
8404
+ }
8381
8405
  /**
8382
8406
  * Stores a value in localStorage under the given reference key.
8383
- * @param reference The key to store the value under
8384
- * @param value The value to store
8385
8407
  */
8386
8408
  static set(reference, value) {
8409
+ if (!this.available)
8410
+ return;
8387
8411
  localStorage.setItem(reference, JSON.stringify(value));
8388
8412
  }
8389
8413
  /**
8390
8414
  * Retrieves a value from localStorage by key.
8391
- * @param reference The key to retrieve
8392
- * @returns The parsed value
8393
8415
  */
8394
8416
  static get(reference) {
8417
+ if (!this.available)
8418
+ return null;
8395
8419
  const value = localStorage.getItem(reference);
8396
8420
  return JSON.parse(value);
8397
8421
  }
8398
8422
  /**
8399
8423
  * Removes an item from localStorage by key.
8400
- * @param reference The key to remove
8401
8424
  */
8402
8425
  static remove(reference) {
8426
+ if (!this.available)
8427
+ return;
8403
8428
  localStorage.removeItem(reference);
8404
8429
  }
8405
8430
  /**
8406
8431
  * Clears all items from localStorage.
8407
8432
  */
8408
8433
  static clear() {
8434
+ if (!this.available)
8435
+ return;
8409
8436
  localStorage.clear();
8410
8437
  }
8411
8438
  }
@@ -8422,7 +8449,7 @@ var ThemeOption;
8422
8449
  ThemeOption["AUTO"] = "auto";
8423
8450
  })(ThemeOption || (ThemeOption = {}));
8424
8451
  class ThemeService {
8425
- constructor() {
8452
+ constructor(platformId) {
8426
8453
  /**
8427
8454
  * Indicates if the light theme is active.
8428
8455
  */
@@ -8451,17 +8478,20 @@ class ThemeService {
8451
8478
  * The default theme option.
8452
8479
  */
8453
8480
  this.default = ThemeOption.AUTO;
8454
- const current = LocalStorageService.get(THEME);
8455
- console.log('💡 ThemeConfig current::: ', current);
8481
+ this.isBrowser = isPlatformBrowser(platformId);
8482
+ const current = this.isBrowser ? LocalStorageService.get(THEME) : null;
8456
8483
  this.theme = new BehaviorSubject(current || this.default);
8457
8484
  this.currentOption = this.Theme;
8458
- console.log('💡 ThemeConfig this.currentOption::: ', this.currentOption);
8485
+ // SSR: sin window/document. Estado queda en defaults; el hydrate posterior
8486
+ // en browser corre toggleUserPreference y cablea el media query.
8487
+ if (!this.isBrowser) {
8488
+ return;
8489
+ }
8459
8490
  this.toggleUserPreference(this.currentOption);
8460
8491
  const prefersDarkQuery = window.matchMedia('(prefers-color-scheme: dark)');
8461
8492
  this.prefersDark = prefersDarkQuery.matches;
8462
8493
  this.handleAutoConfiguration();
8463
8494
  prefersDarkQuery.addEventListener('change', mediaQuery => {
8464
- console.log('💡 ThemeConfig addEventListener change::: ', mediaQuery);
8465
8495
  this.prefersDark = mediaQuery.matches;
8466
8496
  this.handleAutoConfiguration();
8467
8497
  });
@@ -8501,7 +8531,9 @@ class ThemeService {
8501
8531
  */
8502
8532
  set Theme(theme) {
8503
8533
  this.theme.next(theme);
8504
- LocalStorageService.set(THEME, theme);
8534
+ if (this.isBrowser) {
8535
+ LocalStorageService.set(THEME, theme);
8536
+ }
8505
8537
  }
8506
8538
  /**
8507
8539
  * Toggles a theme class on the document body.
@@ -8515,7 +8547,9 @@ class ThemeService {
8515
8547
  * es lo que las apps en Ionic 8 necesitan para que el palette aplique.
8516
8548
  */
8517
8549
  toggleTheme(name, shouldAdd) {
8518
- console.log('toggleTheme::: ', name, shouldAdd);
8550
+ if (!this.isBrowser) {
8551
+ return;
8552
+ }
8519
8553
  document.body.classList.toggle(name, shouldAdd);
8520
8554
  if (name === 'dark') {
8521
8555
  document.documentElement.classList.toggle('ion-palette-dark', shouldAdd);
@@ -8548,7 +8582,7 @@ class ThemeService {
8548
8582
  break;
8549
8583
  }
8550
8584
  }
8551
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
8585
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
8552
8586
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, providedIn: 'root' }); }
8553
8587
  }
8554
8588
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, decorators: [{
@@ -8556,7 +8590,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
8556
8590
  args: [{
8557
8591
  providedIn: 'root',
8558
8592
  }]
8559
- }], ctorParameters: () => [] });
8593
+ }], ctorParameters: () => [{ type: Object, decorators: [{
8594
+ type: Inject,
8595
+ args: [PLATFORM_ID]
8596
+ }] }] });
8560
8597
 
8561
8598
  /**
8562
8599
  * val-title-block
@@ -9497,7 +9534,9 @@ class PinInputComponent {
9497
9534
  ngAfterViewInit() {
9498
9535
  const initial = this.props?.control?.value;
9499
9536
  if (initial && this.pinCode) {
9500
- this.pinCode.setValue(initial);
9537
+ // ng-otp-input crea sus inputs internos de forma asíncrona —
9538
+ // setValue sincrónico aquí llega antes de que estén listos.
9539
+ setTimeout(() => this.pinCode?.setValue(initial), 0);
9501
9540
  }
9502
9541
  }
9503
9542
  reset() {
@@ -17982,10 +18021,13 @@ class AnalyticsService {
17982
18021
  * @param pageTitle - Título de la página (opcional)
17983
18022
  */
17984
18023
  logPageView(pagePath, pageTitle) {
18024
+ // SSR: document/window no existen como globals — optional chaining no protege
18025
+ // contra ReferenceError. Cortocircuito explícito por platform.
18026
+ const isBrowser = isPlatformBrowser(this.platformId);
17985
18027
  this.logEvent('page_view', {
17986
18028
  page_path: pagePath,
17987
- page_title: pageTitle ?? document?.title,
17988
- page_location: window?.location?.href,
18029
+ page_title: pageTitle ?? (isBrowser ? document.title : undefined),
18030
+ page_location: isBrowser ? window.location.href : undefined,
17989
18031
  });
17990
18032
  }
17991
18033
  /**
@@ -18729,6 +18771,10 @@ const VALTECH_FIREBASE_CONFIG = new InjectionToken('ValtechFirebaseConfig');
18729
18771
  * ```
18730
18772
  */
18731
18773
  function provideValtechFirebase(config) {
18774
+ // SSR-safe: durante el prerender / Node, no existe window. getAnalytics(),
18775
+ // enableIndexedDbPersistence() y FCM tocan APIs del browser que no existen
18776
+ // en el server → cortocircuito de los providers/efectos browser-only acá.
18777
+ const isBrowser = typeof window !== 'undefined';
18732
18778
  // Construir array de providers base
18733
18779
  const providers = [
18734
18780
  // Guardar configuración para uso en servicios
@@ -18742,8 +18788,9 @@ function provideValtechFirebase(config) {
18742
18788
  if (config.emulator?.firestore) {
18743
18789
  connectFirestoreEmulator(firestore, config.emulator.firestore.host, config.emulator.firestore.port);
18744
18790
  }
18745
- // Habilitar persistencia offline si está configurada
18746
- if (config.persistence) {
18791
+ // Habilitar persistencia offline si está configurada (browser-only:
18792
+ // enableIndexedDbPersistence requiere IndexedDB, no existe en Node).
18793
+ if (config.persistence && isBrowser) {
18747
18794
  enableIndexedDbPersistence(firestore).catch((err) => {
18748
18795
  if (err.code === 'failed-precondition') {
18749
18796
  console.warn('[ValtechFirebase] Persistencia no disponible: múltiples pestañas abiertas');
@@ -18774,18 +18821,18 @@ function provideValtechFirebase(config) {
18774
18821
  return storage;
18775
18822
  }),
18776
18823
  ];
18777
- // Messaging (FCM) - solo si está explícitamente habilitado
18778
- // Requiere Service Worker configurado, puede congelar la app si no está disponible
18779
- if (config.enableMessaging) {
18824
+ // Messaging (FCM) - solo si está explícitamente habilitado y estamos en browser.
18825
+ // Requiere Service Worker + Notifications API skip total en SSR/Node.
18826
+ if (config.enableMessaging && isBrowser) {
18780
18827
  // Pre-registrar SW custom antes de que Firebase lo intente
18781
- if (typeof navigator !== 'undefined' && 'serviceWorker' in navigator) {
18828
+ if ('serviceWorker' in navigator) {
18782
18829
  navigator.serviceWorker.register('/firebase-messaging-sw.js').catch(console.error);
18783
18830
  }
18784
18831
  providers.push(provideMessaging(() => getMessaging()));
18785
18832
  }
18786
- // Analytics (GA4) - solo si está explícitamente habilitado
18787
- // Requiere measurementId en firebase config
18788
- if (config.enableAnalytics && config.firebase.measurementId) {
18833
+ // Analytics (GA4) - solo si está explícitamente habilitado y estamos en browser.
18834
+ // getAnalytics() / ScreenTrackingService tocan window/document → skip en SSR.
18835
+ if (config.enableAnalytics && config.firebase.measurementId && isBrowser) {
18789
18836
  providers.push(provideAnalytics(() => getAnalytics()));
18790
18837
  // Router tracker para page views automáticos (por defecto habilitado)
18791
18838
  if (config.analyticsConfig?.enablePageViewTracking !== false) {
@@ -21624,8 +21671,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21624
21671
  * Servicio para persistencia de estado de autenticación en localStorage.
21625
21672
  */
21626
21673
  class AuthStorageService {
21627
- constructor(config) {
21674
+ constructor(config, platformId) {
21628
21675
  this.config = config;
21676
+ this.isBrowser = isPlatformBrowser(platformId);
21629
21677
  const prefix = this.config.storagePrefix || 'valtech_auth_';
21630
21678
  this.keys = {
21631
21679
  ACCESS_TOKEN: `${prefix}access_token`,
@@ -21640,6 +21688,8 @@ class AuthStorageService {
21640
21688
  * Guarda el estado completo de autenticación.
21641
21689
  */
21642
21690
  saveState(state) {
21691
+ if (!this.isBrowser)
21692
+ return;
21643
21693
  try {
21644
21694
  localStorage.setItem(this.keys.ACCESS_TOKEN, state.accessToken);
21645
21695
  localStorage.setItem(this.keys.REFRESH_TOKEN, state.refreshToken);
@@ -21658,6 +21708,8 @@ class AuthStorageService {
21658
21708
  * Carga el estado de autenticación desde storage.
21659
21709
  */
21660
21710
  loadState() {
21711
+ if (!this.isBrowser)
21712
+ return {};
21661
21713
  try {
21662
21714
  const accessToken = localStorage.getItem(this.keys.ACCESS_TOKEN);
21663
21715
  const refreshToken = localStorage.getItem(this.keys.REFRESH_TOKEN);
@@ -21683,6 +21735,8 @@ class AuthStorageService {
21683
21735
  * Guarda solo el access token.
21684
21736
  */
21685
21737
  saveAccessToken(token, expiresAt) {
21738
+ if (!this.isBrowser)
21739
+ return;
21686
21740
  try {
21687
21741
  localStorage.setItem(this.keys.ACCESS_TOKEN, token);
21688
21742
  if (expiresAt) {
@@ -21697,6 +21751,8 @@ class AuthStorageService {
21697
21751
  * Guarda el refresh token (token rotation).
21698
21752
  */
21699
21753
  saveRefreshToken(token) {
21754
+ if (!this.isBrowser)
21755
+ return;
21700
21756
  try {
21701
21757
  localStorage.setItem(this.keys.REFRESH_TOKEN, token);
21702
21758
  }
@@ -21708,6 +21764,8 @@ class AuthStorageService {
21708
21764
  * Guarda los permisos actualizados.
21709
21765
  */
21710
21766
  savePermissions(response) {
21767
+ if (!this.isBrowser)
21768
+ return;
21711
21769
  try {
21712
21770
  localStorage.setItem(this.keys.ROLES, JSON.stringify(response.roles));
21713
21771
  localStorage.setItem(this.keys.PERMISSIONS, JSON.stringify(response.permissions));
@@ -21721,6 +21779,9 @@ class AuthStorageService {
21721
21779
  * Carga los permisos desde storage.
21722
21780
  */
21723
21781
  loadPermissions() {
21782
+ if (!this.isBrowser) {
21783
+ return { roles: [], permissions: [], isSuperAdmin: false };
21784
+ }
21724
21785
  try {
21725
21786
  const rolesJson = localStorage.getItem(this.keys.ROLES);
21726
21787
  const permissionsJson = localStorage.getItem(this.keys.PERMISSIONS);
@@ -21739,12 +21800,16 @@ class AuthStorageService {
21739
21800
  * Obtiene el refresh token.
21740
21801
  */
21741
21802
  getRefreshToken() {
21803
+ if (!this.isBrowser)
21804
+ return null;
21742
21805
  return localStorage.getItem(this.keys.REFRESH_TOKEN);
21743
21806
  }
21744
21807
  /**
21745
21808
  * Limpia todo el estado de autenticación.
21746
21809
  */
21747
21810
  clear() {
21811
+ if (!this.isBrowser)
21812
+ return;
21748
21813
  try {
21749
21814
  Object.values(this.keys).forEach((key) => localStorage.removeItem(key));
21750
21815
  }
@@ -21756,9 +21821,11 @@ class AuthStorageService {
21756
21821
  * Verifica si hay estado guardado.
21757
21822
  */
21758
21823
  hasStoredState() {
21824
+ if (!this.isBrowser)
21825
+ return false;
21759
21826
  return !!localStorage.getItem(this.keys.ACCESS_TOKEN);
21760
21827
  }
21761
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthStorageService, deps: [{ token: VALTECH_AUTH_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
21828
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthStorageService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
21762
21829
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthStorageService, providedIn: 'root' }); }
21763
21830
  }
21764
21831
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthStorageService, decorators: [{
@@ -21767,6 +21834,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21767
21834
  }], ctorParameters: () => [{ type: undefined, decorators: [{
21768
21835
  type: Inject,
21769
21836
  args: [VALTECH_AUTH_CONFIG]
21837
+ }] }, { type: Object, decorators: [{
21838
+ type: Inject,
21839
+ args: [PLATFORM_ID]
21770
21840
  }] }] });
21771
21841
 
21772
21842
  /**
@@ -21774,21 +21844,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21774
21844
  * Usa BroadcastChannel API con fallback a storage events.
21775
21845
  */
21776
21846
  class AuthSyncService {
21777
- constructor(config) {
21847
+ constructor(config, platformId) {
21778
21848
  this.config = config;
21779
21849
  this.channel = null;
21780
21850
  this.eventSubject = new Subject();
21781
21851
  this.storageListener = null;
21782
21852
  /** Observable de eventos de sincronización */
21783
21853
  this.onEvent$ = this.eventSubject.asObservable();
21854
+ this.isBrowser = isPlatformBrowser(platformId);
21784
21855
  const prefix = this.config.storagePrefix || 'valtech_auth_';
21785
21856
  this.channelName = `${prefix}sync_channel`;
21786
21857
  }
21787
21858
  /**
21788
21859
  * Inicia la sincronización entre pestañas.
21860
+ * SSR-noop — sync de pestañas solo aplica en browser.
21789
21861
  */
21790
21862
  start() {
21791
- if (!this.config.enableTabSync) {
21863
+ if (!this.config.enableTabSync || !this.isBrowser) {
21792
21864
  return;
21793
21865
  }
21794
21866
  // Intentar usar BroadcastChannel API (mejor rendimiento)
@@ -21808,7 +21880,7 @@ class AuthSyncService {
21808
21880
  this.channel.close();
21809
21881
  this.channel = null;
21810
21882
  }
21811
- if (this.storageListener) {
21883
+ if (this.storageListener && this.isBrowser) {
21812
21884
  window.removeEventListener('storage', this.storageListener);
21813
21885
  this.storageListener = null;
21814
21886
  }
@@ -21817,7 +21889,7 @@ class AuthSyncService {
21817
21889
  * Envía un evento a otras pestañas.
21818
21890
  */
21819
21891
  broadcast(event) {
21820
- if (!this.config.enableTabSync) {
21892
+ if (!this.config.enableTabSync || !this.isBrowser) {
21821
21893
  return;
21822
21894
  }
21823
21895
  const fullEvent = {
@@ -21903,7 +21975,7 @@ class AuthSyncService {
21903
21975
  }
21904
21976
  this.eventSubject.next(event);
21905
21977
  }
21906
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthSyncService, deps: [{ token: VALTECH_AUTH_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
21978
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthSyncService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
21907
21979
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthSyncService, providedIn: 'root' }); }
21908
21980
  }
21909
21981
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AuthSyncService, decorators: [{
@@ -21912,6 +21984,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
21912
21984
  }], ctorParameters: () => [{ type: undefined, decorators: [{
21913
21985
  type: Inject,
21914
21986
  args: [VALTECH_AUTH_CONFIG]
21987
+ }] }, { type: Object, decorators: [{
21988
+ type: Inject,
21989
+ args: [PLATFORM_ID]
21915
21990
  }] }] });
21916
21991
 
21917
21992
  /**
@@ -40459,7 +40534,8 @@ const DEFAULT_LANG = 'es';
40459
40534
  * this.locale.setLang('en');
40460
40535
  */
40461
40536
  class LocaleService {
40462
- constructor() {
40537
+ constructor(platformId) {
40538
+ this.isBrowser = isPlatformBrowser(platformId);
40463
40539
  this.lang = this.getStoredLang();
40464
40540
  }
40465
40541
  /**
@@ -40469,7 +40545,7 @@ class LocaleService {
40469
40545
  * @param lang Nuevo idioma ('es' o 'en')
40470
40546
  */
40471
40547
  setLang(lang) {
40472
- if (lang === this.lang) {
40548
+ if (lang === this.lang || !this.isBrowser) {
40473
40549
  return;
40474
40550
  }
40475
40551
  localStorage.setItem(LANG_STORAGE_KEY, lang);
@@ -40478,8 +40554,12 @@ class LocaleService {
40478
40554
  /**
40479
40555
  * Obtiene el idioma almacenado en localStorage.
40480
40556
  * Si no existe o no es válido, retorna el idioma por defecto.
40557
+ * En SSR (sin localStorage) retorna el default.
40481
40558
  */
40482
40559
  getStoredLang() {
40560
+ if (!this.isBrowser) {
40561
+ return DEFAULT_LANG;
40562
+ }
40483
40563
  const stored = localStorage.getItem(LANG_STORAGE_KEY);
40484
40564
  if (stored === 'es' || stored === 'en') {
40485
40565
  return stored;
@@ -40498,13 +40578,16 @@ class LocaleService {
40498
40578
  get isEnglish() {
40499
40579
  return this.lang === 'en';
40500
40580
  }
40501
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LocaleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
40581
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LocaleService, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
40502
40582
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LocaleService, providedIn: 'root' }); }
40503
40583
  }
40504
40584
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LocaleService, decorators: [{
40505
40585
  type: Injectable,
40506
40586
  args: [{ providedIn: 'root' }]
40507
- }], ctorParameters: () => [] });
40587
+ }], ctorParameters: () => [{ type: Object, decorators: [{
40588
+ type: Inject,
40589
+ args: [PLATFORM_ID]
40590
+ }] }] });
40508
40591
 
40509
40592
  // Types for valtech-components services
40510
40593
  // ValtechConfig and LangProvider have been removed in v3.0.0