valtech-components 2.0.826 → 2.0.828

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.
@@ -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.826';
56
+ const VERSION = '2.0.828';
57
57
 
58
58
  /**
59
59
  * Servicio para gestionar presets de componentes.
@@ -21509,6 +21509,7 @@ class FirebaseService {
21509
21509
  // true al haber User, false en signout. Permite que los gates
21510
21510
  // re-evalúen tras un logout/login dentro de la misma sesión de página.
21511
21511
  this._firebaseAuthReady.set(!!user);
21512
+ console.log(`[FBAuth] authState emit user=${user?.uid ?? 'null'} firebaseAuthReady=${!!user}`);
21512
21513
  this.sessionState.next({
21513
21514
  user: user ? this.mapUser(user) : null,
21514
21515
  isAuthenticated: !!user,
@@ -21518,6 +21519,7 @@ class FirebaseService {
21518
21519
  },
21519
21520
  error: error => {
21520
21521
  this._firebaseAuthReady.set(false);
21522
+ console.error(`[FBAuth] authState ERROR: ${error instanceof Error ? error.message : String(error)}`);
21521
21523
  this.sessionState.next({
21522
21524
  user: null,
21523
21525
  isAuthenticated: false,
@@ -21536,9 +21538,14 @@ class FirebaseService {
21536
21538
  */
21537
21539
  whenFirebaseAuthReady() {
21538
21540
  if (this._firebaseAuthReady()) {
21541
+ console.log('[FBAuth] whenFirebaseAuthReady resolved immediately (already ready)');
21539
21542
  return Promise.resolve(true);
21540
21543
  }
21541
- return firstValueFrom(this.firebaseAuthReady$);
21544
+ console.log('[FBAuth] whenFirebaseAuthReady waiting for Firebase Auth session...');
21545
+ return firstValueFrom(this.firebaseAuthReady$).then(v => {
21546
+ console.log('[FBAuth] whenFirebaseAuthReady resolved after wait');
21547
+ return v;
21548
+ });
21542
21549
  }
21543
21550
  // ===========================================================================
21544
21551
  // AUTENTICACIÓN
@@ -21558,6 +21565,7 @@ class FirebaseService {
21558
21565
  * ```
21559
21566
  */
21560
21567
  async signInWithCustomToken(token) {
21568
+ console.log(`[FBAuth] signInWithCustomToken called tokenLen=${token?.length ?? 0}`);
21561
21569
  try {
21562
21570
  const credential = await signInWithCustomToken(this.auth, token);
21563
21571
  // Forzar refresh del token para asegurar que los claims estén actualizados
@@ -21565,10 +21573,12 @@ class FirebaseService {
21565
21573
  if (credential.user) {
21566
21574
  await credential.user.getIdToken(true);
21567
21575
  }
21576
+ console.log(`[FBAuth] signInWithCustomToken OK uid=${credential.user?.uid ?? 'null'}`);
21568
21577
  return credential;
21569
21578
  }
21570
21579
  catch (error) {
21571
21580
  const message = this.getErrorMessage(error);
21581
+ console.error(`[FBAuth] signInWithCustomToken FAILED: ${message}`);
21572
21582
  throw new Error(message);
21573
21583
  }
21574
21584
  }
@@ -23766,8 +23776,11 @@ class NotificationsService {
23766
23776
  return this.collectionReady$.asObservable();
23767
23777
  }
23768
23778
  return this.collectionReady$.pipe(switchMap(collection => {
23769
- if (!collection)
23779
+ if (!collection) {
23780
+ console.log('[Notifs] collectionWhenAuthReady$ — collection is null (not initialized)');
23770
23781
  return of(null);
23782
+ }
23783
+ console.log('[Notifs] collectionWhenAuthReady$ — collection ready, awaiting Firebase Auth');
23771
23784
  return from(fb.whenFirebaseAuthReady()).pipe(map$1(() => collection));
23772
23785
  }));
23773
23786
  }
@@ -23810,6 +23823,7 @@ class NotificationsService {
23810
23823
  * un userId diferente al del usuario autenticado.
23811
23824
  */
23812
23825
  initialize(userId) {
23826
+ console.log(`[Notifs] initialize uid=${userId}`);
23813
23827
  if (!this.collectionFactory) {
23814
23828
  console.warn('[Notifications] FirestoreCollectionFactory not available. Ensure provideValtechFirebase() is configured.');
23815
23829
  return;
@@ -23853,8 +23867,11 @@ class NotificationsService {
23853
23867
  */
23854
23868
  getAll(limit = DEFAULT_LIMIT) {
23855
23869
  return this.collectionWhenAuthReady$().pipe(switchMap(collection => {
23856
- if (!collection)
23870
+ if (!collection) {
23871
+ console.warn('[Notifs] getAll — collection null → returning EMPTY (no emission)');
23857
23872
  return EMPTY;
23873
+ }
23874
+ console.log('[Notifs] getAll — attaching Firestore watchAll listener');
23858
23875
  return collection.watchAll({
23859
23876
  orderBy: [{ field: 'createdAt', direction: 'desc' }],
23860
23877
  limit,
@@ -24609,6 +24626,14 @@ class AuthService {
24609
24626
  }
24610
24627
  // 3. Iniciar timer de refresco proactivo
24611
24628
  this.startRefreshTimer();
24629
+ // 4. Re-establecer la sesión de Firebase en bootstrap.
24630
+ // El access token sigue válido, así que NO pasamos por la rama de
24631
+ // refresh — pero la persistencia IndexedDB propia de Firebase Auth no
24632
+ // sobrevive el contenedor de storage de una PWA standalone en iOS.
24633
+ // Sin esto, `firebaseAuthReady` se queda en `false` para siempre y
24634
+ // cualquier listener Firestore (ej. el inbox de notificaciones) cuelga.
24635
+ // Fire-and-forget: NO debe demorar el resolve de initialize().
24636
+ void this.ensureFirebaseSessionOnBootstrap();
24612
24637
  }
24613
24638
  else if (storedState.refreshToken) {
24614
24639
  // 4. Token expirado pero hay refresh token - intentar refrescar
@@ -25355,6 +25380,8 @@ class AuthService {
25355
25380
  // FIREBASE INTEGRATION
25356
25381
  // =============================================
25357
25382
  async signInWithFirebase(firebaseToken) {
25383
+ console.log(`[FBAuth] auth flow → signInWithFirebase attempt tokenLen=${firebaseToken?.length ?? 0} ` +
25384
+ `firebaseServicePresent=${!!this.firebaseService}`);
25358
25385
  try {
25359
25386
  if (this.firebaseService) {
25360
25387
  await this.firebaseService.signInWithCustomToken(firebaseToken);
@@ -25383,6 +25410,43 @@ class AuthService {
25383
25410
  console.warn('[ValtechAuth] Firebase signout failed:', error);
25384
25411
  }
25385
25412
  }
25413
+ /**
25414
+ * Re-establece la sesión de Firebase Auth en el bootstrap de la app cuando
25415
+ * el access token de la app sigue válido (la rama de initialize() que NO
25416
+ * pasa por refresh).
25417
+ *
25418
+ * Firebase Auth mantiene su PROPIA sesión con persistencia IndexedDB
25419
+ * independiente del storage de tokens de la app. En un navegador normal esa
25420
+ * persistencia se auto-restaura sola; en una PWA standalone en iOS el
25421
+ * contenedor de storage no sobrevive, y `firebaseAuthReady` se queda en
25422
+ * `false` indefinidamente → los listeners Firestore cuelgan (~40s timeout).
25423
+ *
25424
+ * Estrategia: dar una ventana corta a la auto-restauración de Firebase y, si
25425
+ * no ocurre, forzar un `refreshAccessToken()` — que ya hace `signInWithFirebase`
25426
+ * con el `firebaseToken` que devuelve `/refresh`.
25427
+ *
25428
+ * Fire-and-forget: se invoca con `void` para no demorar `initialize()`.
25429
+ */
25430
+ async ensureFirebaseSessionOnBootstrap() {
25431
+ if (!this.config.enableFirebaseIntegration || !this.firebaseService)
25432
+ return;
25433
+ // Dar a la persistencia IndexedDB propia de Firebase Auth una oportunidad
25434
+ // de auto-restaurarse (navegador normal). En una PWA standalone de iOS
25435
+ // normalmente NO lo hará.
25436
+ await new Promise(r => setTimeout(r, 2500));
25437
+ if (this.firebaseService.firebaseAuthReady()) {
25438
+ console.log('[FBAuth] bootstrap — Firebase session restored on its own');
25439
+ return;
25440
+ }
25441
+ console.log('[FBAuth] bootstrap — session valid but Firebase NOT ready → refreshing to re-establish');
25442
+ try {
25443
+ // refreshAccessToken() ya llama signInWithFirebase() en éxito.
25444
+ await firstValueFrom(this.refreshAccessToken());
25445
+ }
25446
+ catch (e) {
25447
+ console.warn('[FBAuth] bootstrap — refresh to re-establish Firebase failed:', e);
25448
+ }
25449
+ }
25386
25450
  // =============================================
25387
25451
  // DEVICE REGISTRATION (Push Notifications)
25388
25452
  // =============================================
@@ -38521,8 +38585,18 @@ function createRefreshableStream(factory, options) {
38521
38585
  // sesión NUNCA se establece (token inválido, signInWithFirebase falló), el
38522
38586
  // gate igual se libera tras `authGateTimeoutMs` y la factory procede: si no
38523
38587
  // hay permiso terminará en estado `error`, jamás en skeleton infinito.
38588
+ // Tag los dos inputs del `race` para distinguir en logs cuál ganó: la sesión
38589
+ // de Firebase Auth (`auth-ready`) o el timeout de seguridad (`timeout`).
38524
38590
  const authGate$ = firebase
38525
- ? race(firebase.firebaseAuthReady$, timer(authGateTimeoutMs)).pipe(take(1))
38591
+ ? race(firebase.firebaseAuthReady$.pipe(map$1(() => 'auth-ready')), timer(authGateTimeoutMs).pipe(map$1(() => 'timeout'))).pipe(take(1), tap(winner => {
38592
+ if (winner === 'timeout') {
38593
+ console.warn(`[RefreshStream] auth gate resolved by TIMEOUT after ${authGateTimeoutMs}ms ` +
38594
+ '(Firebase Auth session never confirmed)');
38595
+ }
38596
+ else {
38597
+ console.log('[RefreshStream] auth gate resolved by firebaseAuthReady$ (session ready)');
38598
+ }
38599
+ }))
38526
38600
  : of(true);
38527
38601
  const data = toSignal(toObservable(_reload, { injector }).pipe(tap(() => {
38528
38602
  _loading.set(true);
@@ -38534,6 +38608,7 @@ function createRefreshableStream(factory, options) {
38534
38608
  switchMap(() => authGate$.pipe(switchMap(() => factory().pipe(tap(() => {
38535
38609
  _loading.set(false);
38536
38610
  _error.set(false);
38611
+ console.log('[RefreshStream] factory emitted first value — loading=false');
38537
38612
  }),
38538
38613
  // Backoff corto exponencial acotado — solo red de seguridad para
38539
38614
  // reconexiones transitorias, NO para cubrir cold start.
@@ -38546,9 +38621,10 @@ function createRefreshableStream(factory, options) {
38546
38621
  // silencio), `timeout` dispara un error → `catchError` → estado
38547
38622
  // `error`. Nunca skeleton perpetuo. Va DESPUÉS de `retry` para
38548
38623
  // que cuente el tiempo total, no por intento.
38549
- timeout({ first: firstEmitTimeoutMs }), catchError(() => {
38624
+ timeout({ first: firstEmitTimeoutMs }), catchError(err => {
38550
38625
  _loading.set(false);
38551
38626
  _error.set(true);
38627
+ console.error(`[RefreshStream] factory failed/timed out → error state: ${err instanceof Error ? err.message : String(err)}`);
38552
38628
  return of(fallback);
38553
38629
  })))))), { initialValue: null, injector });
38554
38630
  return {