valtech-components 4.0.177 → 4.0.178
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/components/molecules/update-banner/update-banner.component.mjs +18 -6
- package/esm2022/lib/components/organisms/html-viewer-modal/html-viewer-modal.component.mjs +3 -3
- package/esm2022/lib/services/auth/auth.service.mjs +28 -4
- package/esm2022/lib/services/auth/oauth.service.mjs +16 -140
- package/esm2022/lib/version.mjs +2 -2
- package/fesm2022/valtech-components.mjs +62 -150
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/atoms/rights-footer/rights-footer.component.d.ts +2 -2
- package/lib/components/molecules/cta-card/cta-card.component.d.ts +1 -1
- package/lib/components/molecules/metric-card/metric-card.component.d.ts +1 -1
- package/lib/components/molecules/update-banner/update-banner.component.d.ts +7 -0
- package/lib/components/organisms/account-view/account-view.component.d.ts +1 -1
- package/lib/components/organisms/article/article.component.d.ts +5 -5
- package/lib/components/organisms/auth-cta/auth-cta.component.d.ts +1 -1
- package/lib/components/organisms/landing-steps/landing-steps.component.d.ts +1 -1
- package/lib/components/organisms/organization-view/organization-view.component.d.ts +1 -1
- package/lib/services/auth/auth.service.d.ts +1 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/lib/services/firebase/firebase-messaging-sw.js +0 -145
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, InjectionToken, makeEnvironmentProviders, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, TemplateRef, ViewContainerRef, input, Directive, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, HostBinding, HostListener, SecurityContext, NgZone, ViewChild, ElementRef, ChangeDetectorRef, output, ContentChild, model, ViewEncapsulation, untracked, viewChild, Injector, isSignal } from '@angular/core';
|
|
3
|
-
import { BehaviorSubject, throwError, Subject, map, distinctUntilChanged, filter as filter$1, take as take$1, firstValueFrom, of, from, EMPTY, Observable, interval, debounceTime, switchMap as switchMap$1, catchError as catchError$1, takeUntil, isObservable, forkJoin, race, timer, shareReplay } from 'rxjs';
|
|
4
|
-
import { catchError, switchMap, finalize, filter, take, timeout, map as map$1, tap, distinctUntilChanged as distinctUntilChanged$1, retry, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs/operators';
|
|
3
|
+
import { BehaviorSubject, throwError, Subject, map, distinctUntilChanged, filter as filter$1, take as take$1, firstValueFrom, of, from, EMPTY, Observable, interval, debounceTime, switchMap as switchMap$1, catchError as catchError$1, takeUntil, isObservable, forkJoin, race, timer, shareReplay as shareReplay$1 } from 'rxjs';
|
|
4
|
+
import { catchError, switchMap, finalize, filter, take, timeout, map as map$1, tap, shareReplay, distinctUntilChanged as distinctUntilChanged$1, retry, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs/operators';
|
|
5
5
|
import * as i1$3 from '@angular/common/http';
|
|
6
6
|
import { provideHttpClient, withInterceptors, HttpClient, HttpErrorResponse } from '@angular/common/http';
|
|
7
7
|
import * as i1$1 from '@angular/fire/firestore';
|
|
@@ -56,7 +56,7 @@ import { BrowserMultiFormatReader } from '@zxing/browser';
|
|
|
56
56
|
* Current version of valtech-components.
|
|
57
57
|
* This is automatically updated during the publish process.
|
|
58
58
|
*/
|
|
59
|
-
const VERSION = '4.0.
|
|
59
|
+
const VERSION = '4.0.178';
|
|
60
60
|
|
|
61
61
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
62
62
|
let isRefreshing = false;
|
|
@@ -6587,145 +6587,21 @@ class OAuthService {
|
|
|
6587
6587
|
this.clearLocalStorageFallback();
|
|
6588
6588
|
const nonce = this.generateNonce();
|
|
6589
6589
|
this.expectedNonce = nonce;
|
|
6590
|
-
// popup
|
|
6591
|
-
//
|
|
6592
|
-
|
|
6590
|
+
// Flujo REDIRECT (sin popup). El popup quedaba COLGADO bajo COOP: Google
|
|
6591
|
+
// setea Cross-Origin-Opener-Policy → window.opener queda severado (el
|
|
6592
|
+
// postMessage del popup no llega), BroadcastChannel/localStorage no siempre
|
|
6593
|
+
// entregan, y popup.closed queda bloqueado ("COOP policy would block the
|
|
6594
|
+
// window.closed call") → ni siquiera dispara el cancel: la ventana principal
|
|
6595
|
+
// espera para siempre sin redirigir. Navegamos la VENTANA COMPLETA al /start;
|
|
6596
|
+
// al volver, OAuthCallbackComponent corre como ventana principal (redirect_uri
|
|
6597
|
+
// SIN popup=true) y completa la sesión vía completeInMainWindow → navega al
|
|
6598
|
+
// home. Sin popup = sin COOP = sin cuelgue. (El link-flow sigue por popup.)
|
|
6599
|
+
const redirectUri = `${window.location.origin}/auth/oauth/callback`;
|
|
6593
6600
|
const startUrl = `${this.config?.apiUrl}/v2/auth/oauth/${provider}/start?redirect_uri=${encodeURIComponent(redirectUri)}&client_nonce=${encodeURIComponent(nonce)}`;
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
const top = window.screenY + (window.outerHeight - height) / 2;
|
|
6599
|
-
const features = `width=${width},height=${height},left=${left},top=${top},popup=yes`;
|
|
6600
|
-
this.popup = window.open(startUrl, 'oauth', features);
|
|
6601
|
-
if (!this.popup) {
|
|
6602
|
-
observer.error({
|
|
6603
|
-
code: 'POPUP_BLOCKED',
|
|
6604
|
-
message: 'El navegador bloqueó la ventana emergente. Por favor, permite popups para este sitio.',
|
|
6605
|
-
});
|
|
6606
|
-
return () => { };
|
|
6607
|
-
}
|
|
6608
|
-
// Escuchar mensajes del popup
|
|
6609
|
-
this.messageHandler = (event) => {
|
|
6610
|
-
// Validar origen
|
|
6611
|
-
if (event.origin !== window.location.origin) {
|
|
6612
|
-
return;
|
|
6613
|
-
}
|
|
6614
|
-
// Validar tipo de mensaje
|
|
6615
|
-
const data = event.data;
|
|
6616
|
-
if (data?.type !== 'oauth-callback') {
|
|
6617
|
-
return;
|
|
6618
|
-
}
|
|
6619
|
-
// Verificar el nonce del flujo (M-07): si no coincide, no es nuestro
|
|
6620
|
-
// callback → ignorar (no consumir el observable).
|
|
6621
|
-
if (!this.isNonceValid(data)) {
|
|
6622
|
-
return;
|
|
6623
|
-
}
|
|
6624
|
-
// Limpiar
|
|
6625
|
-
this.cleanup();
|
|
6626
|
-
// Emitir resultado dentro de NgZone para trigger change detection
|
|
6627
|
-
this.ngZone.run(() => {
|
|
6628
|
-
if (data.error) {
|
|
6629
|
-
observer.error(data.error);
|
|
6630
|
-
}
|
|
6631
|
-
else if (data.tokens) {
|
|
6632
|
-
observer.next(data.tokens);
|
|
6633
|
-
observer.complete();
|
|
6634
|
-
}
|
|
6635
|
-
else {
|
|
6636
|
-
observer.error({
|
|
6637
|
-
code: 'INVALID_RESPONSE',
|
|
6638
|
-
message: 'Respuesta inválida del servidor de autenticación',
|
|
6639
|
-
});
|
|
6640
|
-
}
|
|
6641
|
-
});
|
|
6642
|
-
};
|
|
6643
|
-
window.addEventListener('message', this.messageHandler);
|
|
6644
|
-
// BroadcastChannel: canal adicional immune a COOP (funciona entre misma
|
|
6645
|
-
// origin sin importar el browsing context group). Es el canal más fiable
|
|
6646
|
-
// cuando COOP sever el link opener→popup al pasar por Google/MS.
|
|
6647
|
-
try {
|
|
6648
|
-
this.broadcastChannel = new BroadcastChannel('valtech-oauth-callback');
|
|
6649
|
-
this.broadcastChannel.onmessage = (event) => {
|
|
6650
|
-
const data = event.data;
|
|
6651
|
-
if (data?.type !== 'oauth-callback')
|
|
6652
|
-
return;
|
|
6653
|
-
if (!this.isNonceValid(data))
|
|
6654
|
-
return;
|
|
6655
|
-
this.clearLocalStorageFallback();
|
|
6656
|
-
this.cleanup();
|
|
6657
|
-
this.ngZone.run(() => {
|
|
6658
|
-
if (data.error) {
|
|
6659
|
-
observer.error(data.error);
|
|
6660
|
-
}
|
|
6661
|
-
else if (data.tokens) {
|
|
6662
|
-
observer.next(data.tokens);
|
|
6663
|
-
observer.complete();
|
|
6664
|
-
}
|
|
6665
|
-
else {
|
|
6666
|
-
observer.error({
|
|
6667
|
-
code: 'INVALID_RESPONSE',
|
|
6668
|
-
message: 'Respuesta inválida del servidor de autenticación',
|
|
6669
|
-
});
|
|
6670
|
-
}
|
|
6671
|
-
});
|
|
6672
|
-
};
|
|
6673
|
-
}
|
|
6674
|
-
catch {
|
|
6675
|
-
// BroadcastChannel no disponible (contextos muy restringidos) — ignorar
|
|
6676
|
-
}
|
|
6677
|
-
// Polling de localStorage (COOP workaround - no podemos detectar popup.closed)
|
|
6678
|
-
// También verifica si el popup se cerró manualmente
|
|
6679
|
-
this.checkClosedInterval = setInterval(() => {
|
|
6680
|
-
// Primero verificar localStorage (funciona aunque COOP bloquee todo)
|
|
6681
|
-
const storedData = this.checkLocalStorageFallback();
|
|
6682
|
-
if (storedData) {
|
|
6683
|
-
this.cleanup();
|
|
6684
|
-
this.ngZone.run(() => {
|
|
6685
|
-
if (storedData.error) {
|
|
6686
|
-
observer.error(storedData.error);
|
|
6687
|
-
}
|
|
6688
|
-
else if (storedData.tokens) {
|
|
6689
|
-
// Gate de diagnóstico: la metadata de tokens (keys, presencia y
|
|
6690
|
-
// longitud del firebaseToken) no debe filtrarse a la consola en
|
|
6691
|
-
// producción (L4 del audit). Solo en dev.
|
|
6692
|
-
if (isDevMode()) {
|
|
6693
|
-
console.log('[OAuthService] Retrieved tokens from localStorage fallback', {
|
|
6694
|
-
keys: Object.keys(storedData.tokens),
|
|
6695
|
-
hasFirebaseToken: !!storedData.tokens.firebaseToken,
|
|
6696
|
-
firebaseTokenLength: storedData.tokens.firebaseToken?.length ?? 0,
|
|
6697
|
-
});
|
|
6698
|
-
}
|
|
6699
|
-
observer.next(storedData.tokens);
|
|
6700
|
-
observer.complete();
|
|
6701
|
-
}
|
|
6702
|
-
else {
|
|
6703
|
-
observer.error({
|
|
6704
|
-
code: 'INVALID_RESPONSE',
|
|
6705
|
-
message: 'Respuesta inválida del servidor de autenticación',
|
|
6706
|
-
});
|
|
6707
|
-
}
|
|
6708
|
-
});
|
|
6709
|
-
return;
|
|
6710
|
-
}
|
|
6711
|
-
// Intentar verificar si popup se cerró (puede fallar por COOP)
|
|
6712
|
-
try {
|
|
6713
|
-
if (this.popup?.closed) {
|
|
6714
|
-
this.cleanup();
|
|
6715
|
-
this.ngZone.run(() => {
|
|
6716
|
-
observer.error({
|
|
6717
|
-
code: 'POPUP_CLOSED',
|
|
6718
|
-
message: 'Se cerró la ventana de autenticación',
|
|
6719
|
-
});
|
|
6720
|
-
});
|
|
6721
|
-
}
|
|
6722
|
-
}
|
|
6723
|
-
catch {
|
|
6724
|
-
// COOP bloquea acceso a popup.closed - ignorar y seguir con polling
|
|
6725
|
-
}
|
|
6726
|
-
}, 300);
|
|
6727
|
-
// Cleanup cuando el observable se destruye
|
|
6728
|
-
return () => this.cleanup();
|
|
6601
|
+
window.location.assign(startUrl);
|
|
6602
|
+
// La página se descarga acá; el observable no emite (la finalización ocurre
|
|
6603
|
+
// en el callback, ya como ventana principal). Sin listeners ni polling.
|
|
6604
|
+
return () => { };
|
|
6729
6605
|
});
|
|
6730
6606
|
}
|
|
6731
6607
|
/**
|
|
@@ -8352,6 +8228,13 @@ class AuthService {
|
|
|
8352
8228
|
this.refreshTimerId = null;
|
|
8353
8229
|
this.syncSubscription = null;
|
|
8354
8230
|
this.firestoreRBACUnsubscribe = null;
|
|
8231
|
+
// Single-flight refresh: un solo POST /refresh en vuelo a la vez. Todos los
|
|
8232
|
+
// callers (bootstrap, reestablecer Firebase, interceptor 401, timer proactivo)
|
|
8233
|
+
// comparten el MISMO observable. Sin esto, refreshes concurrentes chocan contra
|
|
8234
|
+
// la rotación de refresh token del backend: el primero rota el token y el
|
|
8235
|
+
// segundo llega con el token ya invalidado → 401 → logout espurio (el usuario
|
|
8236
|
+
// cae a la landing al actualizar). Ver project_pwa-login-freeze.
|
|
8237
|
+
this.inFlightRefresh$ = null;
|
|
8355
8238
|
// =============================================
|
|
8356
8239
|
// ESTADO PÚBLICO (Signals readonly)
|
|
8357
8240
|
// =============================================
|
|
@@ -8762,13 +8645,20 @@ class AuthService {
|
|
|
8762
8645
|
* que el cliente debe guardar para el próximo refresh.
|
|
8763
8646
|
*/
|
|
8764
8647
|
refreshAccessToken() {
|
|
8648
|
+
// Single-flight: si ya hay un /refresh en vuelo, devolvemos el MISMO
|
|
8649
|
+
// observable (multicast vía shareReplay). Evita la carrera contra la rotación
|
|
8650
|
+
// de refresh token del backend, que producía 401 espurios → logout al
|
|
8651
|
+
// actualizar. Ver inFlightRefresh$ y project_pwa-login-freeze.
|
|
8652
|
+
if (this.inFlightRefresh$) {
|
|
8653
|
+
return this.inFlightRefresh$;
|
|
8654
|
+
}
|
|
8765
8655
|
// H-05 same-site-aware: en same-site (prod) el refresh va SOLO por la cookie
|
|
8766
8656
|
// HttpOnly (body vacío), no se persiste en localStorage → un XSS no lo roba.
|
|
8767
8657
|
// En cross-site (dev) la cookie de terceros se bloquea (Safari ITP / Chrome
|
|
8768
8658
|
// 3rd-party phase-out) → se manda en el body + se persiste (fallback).
|
|
8769
8659
|
// withCredentials adjunta la cookie cuando el browser la permite.
|
|
8770
8660
|
const body = this.storageService.cookieOnly ? {} : { refreshToken: this.state().refreshToken };
|
|
8771
|
-
|
|
8661
|
+
this.inFlightRefresh$ = this.http
|
|
8772
8662
|
.post(`${this.baseUrl}/refresh`, body, { withCredentials: true })
|
|
8773
8663
|
.pipe(
|
|
8774
8664
|
// Nunca dejar el refresh colgado: si la red/Lambda no responde a tiempo,
|
|
@@ -8798,7 +8688,17 @@ class AuthService {
|
|
|
8798
8688
|
// initialize() only clears state (no redirect). Auto-navigating to
|
|
8799
8689
|
// /login from this method redirects even users on public routes.
|
|
8800
8690
|
return throwError(() => error);
|
|
8801
|
-
})
|
|
8691
|
+
}),
|
|
8692
|
+
// Liberar el slot al terminar (éxito, error o timeout) para que el
|
|
8693
|
+
// próximo refresh real arranque uno nuevo.
|
|
8694
|
+
finalize(() => {
|
|
8695
|
+
this.inFlightRefresh$ = null;
|
|
8696
|
+
}),
|
|
8697
|
+
// Multicast: los side-effects del tap corren UNA vez y todos los callers
|
|
8698
|
+
// concurrentes reciben la misma respuesta/error. refCount:false → que un
|
|
8699
|
+
// caller se desuscribe temprano NO cancela la rotación de token en vuelo.
|
|
8700
|
+
shareReplay({ bufferSize: 1, refCount: false }));
|
|
8701
|
+
return this.inFlightRefresh$;
|
|
8802
8702
|
}
|
|
8803
8703
|
/**
|
|
8804
8704
|
* Maneja autenticación exitosa desde fuentes externas (OAuth, etc).
|
|
@@ -28351,6 +28251,13 @@ class UpdateBannerComponent {
|
|
|
28351
28251
|
dismissAction: this.tr('dismissAction'),
|
|
28352
28252
|
};
|
|
28353
28253
|
});
|
|
28254
|
+
/**
|
|
28255
|
+
* Feedback visual mientras se aplica el update. El botón pasa a estado
|
|
28256
|
+
* WORKING (spinner) y se bloquean nuevos taps. `applyUpdate()` siempre
|
|
28257
|
+
* recarga la página al terminar (try/finally), así que NO reseteamos este
|
|
28258
|
+
* flag: queda en true hasta que el reload reemplaza la app.
|
|
28259
|
+
*/
|
|
28260
|
+
this.applying = signal(false);
|
|
28354
28261
|
if (!this.i18n.hasNamespace(UPDATE_BANNER_I18N_NAMESPACE)) {
|
|
28355
28262
|
this.i18n.registerContent(UPDATE_BANNER_I18N_NAMESPACE, {
|
|
28356
28263
|
es: UPDATE_BANNER_DEFAULT_CONTENT.es,
|
|
@@ -28360,6 +28267,11 @@ class UpdateBannerComponent {
|
|
|
28360
28267
|
}
|
|
28361
28268
|
/** Aplica la actualización (activa el SW si existe + recarga). */
|
|
28362
28269
|
onUpdate() {
|
|
28270
|
+
// Anti multi-tap: el botón WORKING no queda `disabled` a nivel DOM, así que
|
|
28271
|
+
// sin este guard un usuario impaciente dispararía applyUpdate() N veces.
|
|
28272
|
+
if (this.applying())
|
|
28273
|
+
return;
|
|
28274
|
+
this.applying.set(true);
|
|
28363
28275
|
void this.version.applyUpdate();
|
|
28364
28276
|
}
|
|
28365
28277
|
/** Descarta el banner opcional. No-op en modo obligatorio. */
|
|
@@ -28429,7 +28341,7 @@ class UpdateBannerComponent {
|
|
|
28429
28341
|
color: 'primary',
|
|
28430
28342
|
fill: 'solid',
|
|
28431
28343
|
size: 'small',
|
|
28432
|
-
state: 'ENABLED',
|
|
28344
|
+
state: applying() ? 'WORKING' : 'ENABLED',
|
|
28433
28345
|
type: 'button',
|
|
28434
28346
|
}"
|
|
28435
28347
|
(onClick)="onUpdate()"
|
|
@@ -28441,7 +28353,7 @@ class UpdateBannerComponent {
|
|
|
28441
28353
|
color: 'dark',
|
|
28442
28354
|
fill: 'clear',
|
|
28443
28355
|
size: 'small',
|
|
28444
|
-
state: 'ENABLED',
|
|
28356
|
+
state: applying() ? 'DISABLED' : 'ENABLED',
|
|
28445
28357
|
type: 'button',
|
|
28446
28358
|
}"
|
|
28447
28359
|
(onClick)="onDismiss()"
|
|
@@ -28504,7 +28416,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
28504
28416
|
color: 'primary',
|
|
28505
28417
|
fill: 'solid',
|
|
28506
28418
|
size: 'small',
|
|
28507
|
-
state: 'ENABLED',
|
|
28419
|
+
state: applying() ? 'WORKING' : 'ENABLED',
|
|
28508
28420
|
type: 'button',
|
|
28509
28421
|
}"
|
|
28510
28422
|
(onClick)="onUpdate()"
|
|
@@ -28516,7 +28428,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
28516
28428
|
color: 'dark',
|
|
28517
28429
|
fill: 'clear',
|
|
28518
28430
|
size: 'small',
|
|
28519
|
-
state: 'ENABLED',
|
|
28431
|
+
state: applying() ? 'DISABLED' : 'ENABLED',
|
|
28520
28432
|
type: 'button',
|
|
28521
28433
|
}"
|
|
28522
28434
|
(onClick)="onDismiss()"
|
|
@@ -35347,7 +35259,7 @@ class HtmlViewerModalComponent {
|
|
|
35347
35259
|
<ion-content>
|
|
35348
35260
|
<iframe [srcdoc]="safeHtml" style="width: 100%; height: 100%; border: none;" title="Visor de documento"></iframe>
|
|
35349
35261
|
</ion-content>
|
|
35350
|
-
`, isInline: true, styles: [":host{display:flex;flex-direction:column}ion-content{--padding-bottom:
|
|
35262
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column}ion-content{--padding-top: 12px;--padding-bottom: 12px;--padding-start: 12px;--padding-end: 12px;--background: var(--ion-color-light, #f4f5f8)}iframe{display:block;border-radius:8px;background:#fff}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
|
|
35351
35263
|
}
|
|
35352
35264
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HtmlViewerModalComponent, decorators: [{
|
|
35353
35265
|
type: Component,
|
|
@@ -35370,7 +35282,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
35370
35282
|
<ion-content>
|
|
35371
35283
|
<iframe [srcdoc]="safeHtml" style="width: 100%; height: 100%; border: none;" title="Visor de documento"></iframe>
|
|
35372
35284
|
</ion-content>
|
|
35373
|
-
`, styles: [":host{display:flex;flex-direction:column}ion-content{--padding-bottom:
|
|
35285
|
+
`, styles: [":host{display:flex;flex-direction:column}ion-content{--padding-top: 12px;--padding-bottom: 12px;--padding-start: 12px;--padding-end: 12px;--background: var(--ion-color-light, #f4f5f8)}iframe{display:block;border-radius:8px;background:#fff}\n"] }]
|
|
35374
35286
|
}], propDecorators: { html: [{
|
|
35375
35287
|
type: Input
|
|
35376
35288
|
}], title: [{
|
|
@@ -61903,7 +61815,7 @@ class LegalContentService {
|
|
|
61903
61815
|
const stream = fallback && fallback !== locale
|
|
61904
61816
|
? primary.pipe(catchError$1(() => this.loadOne(slug, fallback, options.basePath)))
|
|
61905
61817
|
: primary;
|
|
61906
|
-
const shared = stream.pipe(shareReplay({ bufferSize: 1, refCount: false }));
|
|
61818
|
+
const shared = stream.pipe(shareReplay$1({ bufferSize: 1, refCount: false }));
|
|
61907
61819
|
this.cache.set(key, shared);
|
|
61908
61820
|
return shared;
|
|
61909
61821
|
}
|