valtech-components 4.0.171 → 4.0.173
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/organisms/html-viewer-modal/html-viewer-modal.component.mjs +8 -22
- package/esm2022/lib/services/auth/auth.service.mjs +28 -4
- package/esm2022/lib/version.mjs +2 -2
- package/fesm2022/valtech-components.mjs +36 -26
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/organisms/html-viewer-modal/html-viewer-modal.component.d.ts +5 -5
- package/lib/services/auth/auth.service.d.ts +1 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
package/esm2022/lib/version.mjs
CHANGED
|
@@ -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 = '4.0.
|
|
6
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
5
|
+
export const VERSION = '4.0.173';
|
|
6
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvdmVyc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDdXJyZW50IHZlcnNpb24gb2YgdmFsdGVjaC1jb21wb25lbnRzLlxuICogVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHVwZGF0ZWQgZHVyaW5nIHRoZSBwdWJsaXNoIHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gJzQuMC4xNzMnO1xuIl19
|
|
@@ -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.173';
|
|
60
60
|
|
|
61
61
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
62
62
|
let isRefreshing = false;
|
|
@@ -8349,6 +8349,13 @@ class AuthService {
|
|
|
8349
8349
|
this.refreshTimerId = null;
|
|
8350
8350
|
this.syncSubscription = null;
|
|
8351
8351
|
this.firestoreRBACUnsubscribe = null;
|
|
8352
|
+
// Single-flight refresh: un solo POST /refresh en vuelo a la vez. Todos los
|
|
8353
|
+
// callers (bootstrap, reestablecer Firebase, interceptor 401, timer proactivo)
|
|
8354
|
+
// comparten el MISMO observable. Sin esto, refreshes concurrentes chocan contra
|
|
8355
|
+
// la rotación de refresh token del backend: el primero rota el token y el
|
|
8356
|
+
// segundo llega con el token ya invalidado → 401 → logout espurio (el usuario
|
|
8357
|
+
// cae a la landing al actualizar). Ver project_pwa-login-freeze.
|
|
8358
|
+
this.inFlightRefresh$ = null;
|
|
8352
8359
|
// =============================================
|
|
8353
8360
|
// ESTADO PÚBLICO (Signals readonly)
|
|
8354
8361
|
// =============================================
|
|
@@ -8759,13 +8766,20 @@ class AuthService {
|
|
|
8759
8766
|
* que el cliente debe guardar para el próximo refresh.
|
|
8760
8767
|
*/
|
|
8761
8768
|
refreshAccessToken() {
|
|
8769
|
+
// Single-flight: si ya hay un /refresh en vuelo, devolvemos el MISMO
|
|
8770
|
+
// observable (multicast vía shareReplay). Evita la carrera contra la rotación
|
|
8771
|
+
// de refresh token del backend, que producía 401 espurios → logout al
|
|
8772
|
+
// actualizar. Ver inFlightRefresh$ y project_pwa-login-freeze.
|
|
8773
|
+
if (this.inFlightRefresh$) {
|
|
8774
|
+
return this.inFlightRefresh$;
|
|
8775
|
+
}
|
|
8762
8776
|
// H-05 same-site-aware: en same-site (prod) el refresh va SOLO por la cookie
|
|
8763
8777
|
// HttpOnly (body vacío), no se persiste en localStorage → un XSS no lo roba.
|
|
8764
8778
|
// En cross-site (dev) la cookie de terceros se bloquea (Safari ITP / Chrome
|
|
8765
8779
|
// 3rd-party phase-out) → se manda en el body + se persiste (fallback).
|
|
8766
8780
|
// withCredentials adjunta la cookie cuando el browser la permite.
|
|
8767
8781
|
const body = this.storageService.cookieOnly ? {} : { refreshToken: this.state().refreshToken };
|
|
8768
|
-
|
|
8782
|
+
this.inFlightRefresh$ = this.http
|
|
8769
8783
|
.post(`${this.baseUrl}/refresh`, body, { withCredentials: true })
|
|
8770
8784
|
.pipe(
|
|
8771
8785
|
// Nunca dejar el refresh colgado: si la red/Lambda no responde a tiempo,
|
|
@@ -8795,7 +8809,17 @@ class AuthService {
|
|
|
8795
8809
|
// initialize() only clears state (no redirect). Auto-navigating to
|
|
8796
8810
|
// /login from this method redirects even users on public routes.
|
|
8797
8811
|
return throwError(() => error);
|
|
8798
|
-
})
|
|
8812
|
+
}),
|
|
8813
|
+
// Liberar el slot al terminar (éxito, error o timeout) para que el
|
|
8814
|
+
// próximo refresh real arranque uno nuevo.
|
|
8815
|
+
finalize(() => {
|
|
8816
|
+
this.inFlightRefresh$ = null;
|
|
8817
|
+
}),
|
|
8818
|
+
// Multicast: los side-effects del tap corren UNA vez y todos los callers
|
|
8819
|
+
// concurrentes reciben la misma respuesta/error. refCount:false → que un
|
|
8820
|
+
// caller se desuscribe temprano NO cancela la rotación de token en vuelo.
|
|
8821
|
+
shareReplay({ bufferSize: 1, refCount: false }));
|
|
8822
|
+
return this.inFlightRefresh$;
|
|
8799
8823
|
}
|
|
8800
8824
|
/**
|
|
8801
8825
|
* Maneja autenticación exitosa desde fuentes externas (OAuth, etc).
|
|
@@ -35288,20 +35312,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
35288
35312
|
type: Output
|
|
35289
35313
|
}] } });
|
|
35290
35314
|
|
|
35291
|
-
addIcons({ printOutline
|
|
35315
|
+
addIcons({ printOutline });
|
|
35292
35316
|
/**
|
|
35293
35317
|
* `val-html-viewer-modal` — Modal para visualizar y descargar/imprimir HTML.
|
|
35294
35318
|
* Se abre como sheet a pantalla completa en móviles.
|
|
35295
35319
|
*
|
|
35296
35320
|
* Renderiza HTML embebido en un iframe (los estilos deben estar inline o
|
|
35297
|
-
* embebidos en el HTML).
|
|
35298
|
-
*
|
|
35321
|
+
* embebidos en el HTML). Botón Imprimir (print via iframe) + Cerrar. El diálogo
|
|
35322
|
+
* de impresión del SO ya ofrece "Guardar como PDF" y compartir nativo, así que
|
|
35323
|
+
* NO exponemos un "descargar HTML" (un .html suelto no le sirve al usuario).
|
|
35299
35324
|
*
|
|
35300
|
-
* Uso: ModalService.
|
|
35325
|
+
* Uso: ModalService.open({ component: HtmlViewerModalComponent, componentProps: { html: "...", title: "..." }, size: "full" })
|
|
35301
35326
|
*
|
|
35302
35327
|
* Props:
|
|
35303
35328
|
* - html: string — HTML completo con estilos embebidos (requerido)
|
|
35304
|
-
* - title: string —
|
|
35329
|
+
* - title: string — Título del documento (default: "documento")
|
|
35305
35330
|
*
|
|
35306
35331
|
* El componente recibe `_modalRef` inyectado por ModalService para cerrar.
|
|
35307
35332
|
*/
|
|
@@ -35323,15 +35348,6 @@ class HtmlViewerModalComponent {
|
|
|
35323
35348
|
iframe.contentWindow.print();
|
|
35324
35349
|
}
|
|
35325
35350
|
}
|
|
35326
|
-
downloadContent() {
|
|
35327
|
-
const blob = new Blob([this.html], { type: 'text/html;charset=utf-8' });
|
|
35328
|
-
const url = window.URL.createObjectURL(blob);
|
|
35329
|
-
const link = document.createElement('a');
|
|
35330
|
-
link.href = url;
|
|
35331
|
-
link.download = `${this.title}-${new Date().getTime()}.html`;
|
|
35332
|
-
link.click();
|
|
35333
|
-
window.URL.revokeObjectURL(url);
|
|
35334
|
-
}
|
|
35335
35351
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HtmlViewerModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
35336
35352
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: HtmlViewerModalComponent, isStandalone: true, selector: "val-html-viewer-modal", inputs: { html: "html", title: "title" }, ngImport: i0, template: `
|
|
35337
35353
|
<ion-header>
|
|
@@ -35345,9 +35361,6 @@ class HtmlViewerModalComponent {
|
|
|
35345
35361
|
<ion-button fill="clear" color="primary" (click)="printContent()" title="Imprimir">
|
|
35346
35362
|
<ion-icon name="print-outline" slot="icon-only" />
|
|
35347
35363
|
</ion-button>
|
|
35348
|
-
<ion-button fill="clear" color="primary" (click)="downloadContent()" title="Descargar">
|
|
35349
|
-
<ion-icon name="download-outline" slot="icon-only" />
|
|
35350
|
-
</ion-button>
|
|
35351
35364
|
</ion-buttons>
|
|
35352
35365
|
</ion-toolbar>
|
|
35353
35366
|
</ion-header>
|
|
@@ -35371,9 +35384,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
35371
35384
|
<ion-button fill="clear" color="primary" (click)="printContent()" title="Imprimir">
|
|
35372
35385
|
<ion-icon name="print-outline" slot="icon-only" />
|
|
35373
35386
|
</ion-button>
|
|
35374
|
-
<ion-button fill="clear" color="primary" (click)="downloadContent()" title="Descargar">
|
|
35375
|
-
<ion-icon name="download-outline" slot="icon-only" />
|
|
35376
|
-
</ion-button>
|
|
35377
35387
|
</ion-buttons>
|
|
35378
35388
|
</ion-toolbar>
|
|
35379
35389
|
</ion-header>
|
|
@@ -61922,7 +61932,7 @@ class LegalContentService {
|
|
|
61922
61932
|
const stream = fallback && fallback !== locale
|
|
61923
61933
|
? primary.pipe(catchError$1(() => this.loadOne(slug, fallback, options.basePath)))
|
|
61924
61934
|
: primary;
|
|
61925
|
-
const shared = stream.pipe(shareReplay({ bufferSize: 1, refCount: false }));
|
|
61935
|
+
const shared = stream.pipe(shareReplay$1({ bufferSize: 1, refCount: false }));
|
|
61926
61936
|
this.cache.set(key, shared);
|
|
61927
61937
|
return shared;
|
|
61928
61938
|
}
|