valtech-components 2.0.804 → 2.0.806
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.
- package/esm2022/lib/services/firebase/firebase.service.mjs +62 -12
- package/esm2022/lib/services/firebase/notifications.service.mjs +36 -4
- package/esm2022/lib/services/refreshable-stream/index.mjs +8 -0
- package/esm2022/lib/services/refreshable-stream/refreshable-stream.mjs +105 -0
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +5 -1
- package/fesm2022/valtech-components.mjs +203 -16
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/services/firebase/firebase.service.d.ts +52 -0
- package/lib/services/firebase/notifications.service.d.ts +17 -0
- package/lib/services/refreshable-stream/index.d.ts +7 -0
- package/lib/services/refreshable-stream/refreshable-stream.d.ts +106 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/public-api.d.ts +1 -0
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firebase Service
|
|
3
|
+
*
|
|
4
|
+
* Servicio principal para la autenticación con Firebase usando Custom Tokens.
|
|
5
|
+
* Permite que usuarios autenticados con tu backend (Cognito, etc.) accedan
|
|
6
|
+
* a servicios de Firebase (Firestore, Storage, FCM) de manera segura.
|
|
7
|
+
*/
|
|
8
|
+
import { Signal } from '@angular/core';
|
|
1
9
|
import { Auth, UserCredential } from '@angular/fire/auth';
|
|
2
10
|
import { Observable } from 'rxjs';
|
|
3
11
|
import { FirebaseUser, MembershipInfo, OrganizationInfo, SessionState, ValtechFirebaseConfig } from './types';
|
|
@@ -46,7 +54,51 @@ export declare class FirebaseService {
|
|
|
46
54
|
readonly user$: Observable<FirebaseUser | null>;
|
|
47
55
|
/** Indica si el usuario está autenticado en Firebase */
|
|
48
56
|
readonly isAuthenticated$: Observable<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Signal interna que respalda `firebaseAuthReady`.
|
|
59
|
+
* `true` cuando hay un `firebase.User` activo y por tanto las reglas de
|
|
60
|
+
* Firestore evaluarán `request.auth != null` correctamente.
|
|
61
|
+
*/
|
|
62
|
+
private readonly _firebaseAuthReady;
|
|
63
|
+
/**
|
|
64
|
+
* Indica si la sesión de **Firebase Auth** está establecida y lista para
|
|
65
|
+
* leer Firestore.
|
|
66
|
+
*
|
|
67
|
+
* IMPORTANTE: esto es distinto del JWT del backend. La sesión de Firebase
|
|
68
|
+
* Auth es una sesión separada que se establece vía `signInWithCustomToken`
|
|
69
|
+
* (ver `AuthService.signInWithFirebase`). En cold start de PWA, el JWT del
|
|
70
|
+
* backend puede estar listo varios cientos de ms antes de que Firebase Auth
|
|
71
|
+
* confirme su `User` — adjuntar un listener de Firestore en esa ventana
|
|
72
|
+
* produce `permission-denied`.
|
|
73
|
+
*
|
|
74
|
+
* Usar este signal (o `whenFirebaseAuthReady()`) como gate antes de
|
|
75
|
+
* suscribirse a cualquier query/listener de Firestore.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* if (this.firebase.firebaseAuthReady()) {
|
|
80
|
+
* // seguro leer Firestore
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
readonly firebaseAuthReady: Signal<boolean>;
|
|
85
|
+
/**
|
|
86
|
+
* Emite `true` una sola vez en cuanto la sesión de Firebase Auth está lista,
|
|
87
|
+
* y completa. Si ya está lista, emite inmediatamente.
|
|
88
|
+
*
|
|
89
|
+
* Pensado como gate compartido para abrir streams Firestore — espera la
|
|
90
|
+
* ventana de hidratación de Firebase Auth sin necesidad de retries.
|
|
91
|
+
*/
|
|
92
|
+
readonly firebaseAuthReady$: Observable<boolean>;
|
|
49
93
|
constructor(auth: Auth, config: ValtechFirebaseConfig);
|
|
94
|
+
/**
|
|
95
|
+
* Resuelve en cuanto la sesión de Firebase Auth está lista para leer
|
|
96
|
+
* Firestore. Si ya está lista, resuelve inmediatamente.
|
|
97
|
+
*
|
|
98
|
+
* Útil para gatear la primera suscripción a un listener de Firestore y así
|
|
99
|
+
* cerrar la ventana de `permission-denied` en cold start.
|
|
100
|
+
*/
|
|
101
|
+
whenFirebaseAuthReady(): Promise<boolean>;
|
|
50
102
|
/**
|
|
51
103
|
* Autentica al usuario con un Custom Token generado por el backend.
|
|
52
104
|
*
|
|
@@ -64,7 +64,16 @@ export declare class NotificationsService {
|
|
|
64
64
|
private currentUserId;
|
|
65
65
|
private collectionReady$;
|
|
66
66
|
private authService;
|
|
67
|
+
private firebaseService;
|
|
67
68
|
constructor(injector: Injector, collectionFactory: FirestoreCollectionFactory);
|
|
69
|
+
/**
|
|
70
|
+
* Gate de Firebase Auth: emite la colección lista SOLO cuando la sesión de
|
|
71
|
+
* Firebase Auth está confirmada. Sin FirebaseService disponible, no gatea
|
|
72
|
+
* (degrada al comportamiento previo). Espera a que `firebaseAuthReady$`
|
|
73
|
+
* emita antes de propagar la colección — así el listener Firestore nunca se
|
|
74
|
+
* adjunta antes de que `request.auth` esté disponible.
|
|
75
|
+
*/
|
|
76
|
+
private collectionWhenAuthReady$;
|
|
68
77
|
/**
|
|
69
78
|
* Configura auto-inicialización observando el estado de AuthService.
|
|
70
79
|
* Se ejecuta en el contexto del injector para poder usar effect().
|
|
@@ -90,6 +99,11 @@ export declare class NotificationsService {
|
|
|
90
99
|
* Obtiene notificaciones ordenadas por fecha descendente (real-time).
|
|
91
100
|
* Se actualiza automáticamente cuando cambian los datos.
|
|
92
101
|
*
|
|
102
|
+
* El listener Firestore NO se adjunta hasta que la sesión de Firebase Auth
|
|
103
|
+
* esté confirmada (`FirebaseService.firebaseAuthReady`). Esto cierra la
|
|
104
|
+
* ventana de `permission-denied` en cold start de PWA, donde el JWT del
|
|
105
|
+
* backend puede estar listo antes que la sesión de Firebase Auth.
|
|
106
|
+
*
|
|
93
107
|
* @param limit - Máximo de notificaciones a cargar (default: 50)
|
|
94
108
|
*/
|
|
95
109
|
getAll(limit?: number): Observable<NotificationDocument[]>;
|
|
@@ -109,6 +123,9 @@ export declare class NotificationsService {
|
|
|
109
123
|
/**
|
|
110
124
|
* Cuenta notificaciones no leídas usando server-side aggregation query.
|
|
111
125
|
* No descarga documentos — eficiente para badges en UI.
|
|
126
|
+
*
|
|
127
|
+
* Gateado por `firebaseAuthReady` — la aggregation query no se ejecuta hasta
|
|
128
|
+
* que la sesión de Firebase Auth esté lista.
|
|
112
129
|
*/
|
|
113
130
|
getUnreadCount(): Observable<number>;
|
|
114
131
|
/**
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Refreshable Stream
|
|
3
|
+
*
|
|
4
|
+
* Helper `createRefreshableStream` para vistas con datos Firestore.
|
|
5
|
+
* Soporta modo one-shot y real-time, con gate de `firebaseAuthReady`.
|
|
6
|
+
*/
|
|
7
|
+
export { createRefreshableStream, type RefreshableStream, type RefreshableStreamOptions, } from './refreshable-stream';
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Refreshable Stream
|
|
3
|
+
*
|
|
4
|
+
* Helper estándar para vistas que consumen datos de Firestore. Soporta DOS
|
|
5
|
+
* modos — el caller decide cuál vía la `factory`:
|
|
6
|
+
*
|
|
7
|
+
* - **one-shot** (recomendado por defecto): `() => from(svc.getAllOnce())`.
|
|
8
|
+
* Carga una vez y completa. Más barato — sin listener vivo.
|
|
9
|
+
* - **real-time**: `() => svc.getAll()`. Listener Firestore que auto-actualiza.
|
|
10
|
+
* Solo donde importa (inbox de notificaciones, badges).
|
|
11
|
+
*
|
|
12
|
+
* En ambos modos la primera suscripción se gatea por `firebaseAuthReady`
|
|
13
|
+
* (sesión de Firebase Auth lista) — así el listener/lectura nunca se adjunta
|
|
14
|
+
* antes de que `request.auth` esté disponible en las reglas de Firestore, lo
|
|
15
|
+
* que cierra la ventana de `permission-denied` en cold start de PWA.
|
|
16
|
+
*
|
|
17
|
+
* El `retry` con backoff corto es solo red de seguridad para reconexiones
|
|
18
|
+
* transitorias (no para cubrir cold start — eso lo cubre el gate de auth).
|
|
19
|
+
*/
|
|
20
|
+
import { Injector, Signal } from '@angular/core';
|
|
21
|
+
import { Observable } from 'rxjs';
|
|
22
|
+
/** Opciones de configuración para `createRefreshableStream`. */
|
|
23
|
+
export interface RefreshableStreamOptions<T> {
|
|
24
|
+
/**
|
|
25
|
+
* Valor emitido cuando la factory falla tras agotar los reintentos.
|
|
26
|
+
* Default: `null`.
|
|
27
|
+
*/
|
|
28
|
+
fallback?: T;
|
|
29
|
+
/**
|
|
30
|
+
* Número máximo de reintentos ante un error de la factory.
|
|
31
|
+
* Backoff corto — NO cubre cold start (eso lo hace el gate de auth), solo
|
|
32
|
+
* reconexiones transitorias. Default: 4.
|
|
33
|
+
*/
|
|
34
|
+
retryCount?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Delay base del backoff (ms). El delay efectivo crece exponencialmente
|
|
37
|
+
* acotado: 500ms → 1s → 2s ... Default: 500.
|
|
38
|
+
*/
|
|
39
|
+
retryBaseDelayMs?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Si `false`, NO espera a `firebaseAuthReady` antes de la primera
|
|
42
|
+
* suscripción. Útil para streams que no leen Firestore. Default: `true`.
|
|
43
|
+
*/
|
|
44
|
+
gateOnFirebaseAuth?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Timeout (ms) del gate de Firebase Auth. Si la sesión de Firebase Auth no
|
|
47
|
+
* se establece en este tiempo, el stream procede igual (la factory correrá
|
|
48
|
+
* y, si no hay permiso, terminará en estado `error` — NUNCA en skeleton
|
|
49
|
+
* infinito). Muy por encima de cualquier handshake real. Default: 20000.
|
|
50
|
+
*/
|
|
51
|
+
authGateTimeoutMs?: number;
|
|
52
|
+
/**
|
|
53
|
+
* Injector explícito. Solo necesario si `createRefreshableStream` se llama
|
|
54
|
+
* fuera de un injection context (raro). Por defecto usa `inject(Injector)`.
|
|
55
|
+
*/
|
|
56
|
+
injector?: Injector;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resultado de `createRefreshableStream`.
|
|
60
|
+
*/
|
|
61
|
+
export interface RefreshableStream<T> {
|
|
62
|
+
/** Datos actuales. `null` mientras la primera emisión no ha llegado. */
|
|
63
|
+
readonly data: Signal<T | null>;
|
|
64
|
+
/** `true` mientras se espera la primera emisión de la suscripción actual. */
|
|
65
|
+
readonly loading: Signal<boolean>;
|
|
66
|
+
/** `true` si la factory falló tras agotar los reintentos. */
|
|
67
|
+
readonly error: Signal<boolean>;
|
|
68
|
+
/**
|
|
69
|
+
* Re-suscribe la factory desde cero (nuevo listener / nueva lectura).
|
|
70
|
+
* Es lo que registra el `PageRefreshService` como handler de pull-to-refresh,
|
|
71
|
+
* y también el "reconectar manual" si un listener murió.
|
|
72
|
+
*/
|
|
73
|
+
reload: () => void;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Crea un stream refrescable a partir de una factory de Observable.
|
|
77
|
+
*
|
|
78
|
+
* DEBE llamarse en un injection context (field initializer o constructor) —
|
|
79
|
+
* usa `toSignal`/`toObservable`/`inject` internamente.
|
|
80
|
+
*
|
|
81
|
+
* @param factory - Función que produce el Observable a consumir. El caller
|
|
82
|
+
* decide el modo: `() => from(svc.getAllOnce())` (one-shot) o
|
|
83
|
+
* `() => svc.getAll()` (real-time).
|
|
84
|
+
* @param options - Configuración opcional (fallback, retry, gate).
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* // one-shot (recomendado por defecto)
|
|
89
|
+
* private readonly stream = createRefreshableStream(
|
|
90
|
+
* () => from(this.svc.getAllOnce()),
|
|
91
|
+
* );
|
|
92
|
+
*
|
|
93
|
+
* // real-time (inbox)
|
|
94
|
+
* private readonly stream = createRefreshableStream(
|
|
95
|
+
* () => this.notifs.getAll(50),
|
|
96
|
+
* );
|
|
97
|
+
*
|
|
98
|
+
* readonly items = this.stream.data;
|
|
99
|
+
* readonly loading = this.stream.loading;
|
|
100
|
+
*
|
|
101
|
+
* ionViewWillEnter() {
|
|
102
|
+
* this.pageRefresh.register(() => this.stream.reload());
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export declare function createRefreshableStream<T>(factory: () => Observable<T>, options?: RefreshableStreamOptions<T>): RefreshableStream<T>;
|
package/lib/version.d.ts
CHANGED
package/package.json
CHANGED
package/public-api.d.ts
CHANGED
|
@@ -263,6 +263,7 @@ export * from './lib/services/auth';
|
|
|
263
263
|
export * from './lib/services/i18n';
|
|
264
264
|
export * from './lib/services/preferences';
|
|
265
265
|
export * from './lib/services/page-refresh/page-refresh.service';
|
|
266
|
+
export * from './lib/services/refreshable-stream';
|
|
266
267
|
export * from './lib/services/app-config';
|
|
267
268
|
export * from './lib/services/presets';
|
|
268
269
|
export * from './lib/services/skeleton';
|