valtech-components 4.0.990 → 4.0.992

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.
Files changed (24) hide show
  1. package/esm2022/lib/components/organisms/survey-builder/survey-builder.component.mjs +12 -4
  2. package/esm2022/lib/components/organisms/survey-builder/types.mjs +1 -1
  3. package/esm2022/lib/services/errors/error-logging.interceptor.mjs +30 -5
  4. package/esm2022/lib/services/i18n/i18n.service.mjs +17 -4
  5. package/esm2022/lib/version.mjs +2 -2
  6. package/fesm2022/valtech-components.mjs +57 -11
  7. package/fesm2022/valtech-components.mjs.map +1 -1
  8. package/lib/components/atoms/rights-footer/rights-footer.component.d.ts +2 -2
  9. package/lib/components/molecules/cta-card/cta-card.component.d.ts +1 -1
  10. package/lib/components/molecules/features-list/features-list.component.d.ts +1 -1
  11. package/lib/components/molecules/load-more/load-more.component.d.ts +1 -1
  12. package/lib/components/molecules/metric-card/metric-card.component.d.ts +1 -1
  13. package/lib/components/molecules/operation-reference/operation-reference.component.d.ts +1 -1
  14. package/lib/components/organisms/account-view/account-view.component.d.ts +1 -1
  15. package/lib/components/organisms/article/article.component.d.ts +5 -5
  16. package/lib/components/organisms/auth-cta/auth-cta.component.d.ts +1 -1
  17. package/lib/components/organisms/notification-preferences-view/notification-preferences-view.component.d.ts +1 -1
  18. package/lib/components/organisms/organization-view/organization-view.component.d.ts +1 -1
  19. package/lib/components/organisms/survey-builder/survey-builder.component.d.ts +1 -0
  20. package/lib/components/organisms/survey-builder/types.d.ts +10 -0
  21. package/lib/services/errors/error-logging.interceptor.d.ts +9 -1
  22. package/lib/services/i18n/i18n.service.d.ts +14 -1
  23. package/lib/version.d.ts +1 -1
  24. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, makeEnvironmentProviders, inject, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, Component, Input, ChangeDetectionStrategy, input, output, Injector, TemplateRef, ViewContainerRef, Directive, ElementRef, Renderer2, HostListener, EventEmitter, Output, HostBinding, SecurityContext, NgZone, ViewChild, ChangeDetectorRef, ContentChild, model, ViewEncapsulation, untracked, ViewChildren, viewChild, isSignal } from '@angular/core';
3
- import { BehaviorSubject, throwError, Subject, map, distinctUntilChanged, filter as filter$1, take as take$1, firstValueFrom, timeout as timeout$1, catchError as catchError$1, of, from, EMPTY, Observable, interval, defer, timer, merge, concat, debounceTime, switchMap as switchMap$1, takeUntil, isObservable, forkJoin, race, shareReplay as shareReplay$1, tap as tap$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';
3
+ import { BehaviorSubject, throwError, timer, Subject, map, distinctUntilChanged, filter as filter$1, take as take$1, firstValueFrom, timeout as timeout$1, catchError as catchError$1, of, from, EMPTY, Observable, interval, defer, merge, concat, debounceTime, switchMap as switchMap$1, takeUntil, isObservable, forkJoin, race, shareReplay as shareReplay$1, tap as tap$1 } from 'rxjs';
4
+ import { catchError, switchMap, finalize, filter, take, timeout, retry, map as map$1, tap, shareReplay, distinctUntilChanged as distinctUntilChanged$1, 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, HttpContextToken, HttpClient, HttpErrorResponse, HttpContext, HttpParams } from '@angular/common/http';
7
7
  import * as i1$1 from '@angular/fire/firestore';
@@ -70,7 +70,7 @@ import fixWebmDuration from 'fix-webm-duration';
70
70
  * Current version of valtech-components.
71
71
  * This is automatically updated during the publish process.
72
72
  */
73
- const VERSION = '4.0.990';
73
+ const VERSION = '4.0.992';
74
74
 
75
75
  function evaluateValtechAccess(rule, context, features = {}, visitedFeatures = new Set()) {
76
76
  if (rule == null)
@@ -1500,6 +1500,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
1500
1500
  args: [PLATFORM_ID]
1501
1501
  }] }] });
1502
1502
 
1503
+ /**
1504
+ * Códigos de status que ameritan reintento — cold-start / infra tibia, no un
1505
+ * error de negocio. Nunca 4xx: eso es la app pidiendo algo mal, reintentar no
1506
+ * lo arregla.
1507
+ */
1508
+ const RETRYABLE_STATUSES = new Set([502, 503, 504]);
1509
+ /** Backoff corto entre reintentos — no queremos que la UI perciba una espera larga. */
1510
+ const RETRY_DELAY_MS = 400;
1503
1511
  /**
1504
1512
  * Marca un request cuyo 404 es un ESTADO ESPERADO del dominio, no un error —
1505
1513
  * ej. `GET /v1/game-profile/me` cuando el usuario todavía no creó su perfil
@@ -1517,7 +1525,15 @@ const EXPECTED_NOT_FOUND = new HttpContextToken(() => false);
1517
1525
  * Interceptor HTTP de observabilidad (Capa 1 del estándar de manejo de errores).
1518
1526
  *
1519
1527
  * Para CADA respuesta HTTP con error:
1520
- * 1. Normaliza el error con `interpretError`.
1528
+ * 0. Si es un GET (idempotente) que falló con 502/503/504, reintenta hasta 2
1529
+ * veces con un backoff corto (400ms/800ms) ANTES de pasar al resto del
1530
+ * pipeline — el caso típico es un cold-start de Lambda en dev: 3-4
1531
+ * requests en paralelo al bootstrap (auth/profile + runs + org/{id})
1532
+ * pegan contra lambdas frías al mismo tiempo, todas 504, y ~2s después ya
1533
+ * están tibias y funcionan. Detectado en Merotz dev 2026-08-17. Nunca
1534
+ * reintenta POST/PUT/DELETE/PATCH (no son idempotentes) ni 4xx (error de
1535
+ * negocio, reintentar no lo arregla).
1536
+ * 1. Si sigue fallando tras los reintentos: normaliza el error con `interpretError`.
1521
1537
  * 2. Loguea un evento estructurado a consola con el prefijo `[HTTP]`.
1522
1538
  * 3. Reporta el error a Firebase Analytics (`source: 'http'`), si hay analytics.
1523
1539
  *
@@ -1541,7 +1557,16 @@ const errorLoggingInterceptor = (request, next) => {
1541
1557
  // `AnalyticsService` puede no estar provisto (apps sin Firebase). El inject
1542
1558
  // funcional con `optional: true` devuelve `null` en ese caso.
1543
1559
  const analytics = inject(AnalyticsService, { optional: true });
1544
- return next(request).pipe(catchError((error) => {
1560
+ return next(request).pipe(retry({
1561
+ count: 2,
1562
+ delay: (error, retryCount) => {
1563
+ const status = error?.status;
1564
+ if (request.method !== 'GET' || !RETRYABLE_STATUSES.has(status)) {
1565
+ return throwError(() => error);
1566
+ }
1567
+ return timer(RETRY_DELAY_MS * retryCount);
1568
+ },
1569
+ }), catchError((error) => {
1545
1570
  const interpreted = interpretError(error);
1546
1571
  const status = interpreted.status ?? error?.status;
1547
1572
  // 401 → ruido del refresh de auth. Log informativo, sin Analytics.
@@ -1933,7 +1958,20 @@ class I18nService {
1933
1958
  return namespace in this._content();
1934
1959
  }
1935
1960
  /**
1936
- * Carga idioma guardado en localStorage o detecta del navegador
1961
+ * Carga el idioma guardado en localStorage, o adivina desde el navegador.
1962
+ *
1963
+ * La detección de acá es PROVISIONAL y NO se persiste, a propósito. El
1964
+ * constructor corre antes que el APP_INITIALIZER de `provideValtechI18n`,
1965
+ * que es quien conoce la config real de la app. Cuando esto persistía el
1966
+ * idioma detectado, el initializer leía esa misma clave un instante después,
1967
+ * la tomaba por preferencia guardada del usuario y entraba por la rama
1968
+ * `stored` — así que `detectBrowserLanguage: false` no tenía efecto en
1969
+ * ninguna app del factory. Escribir acá fabricaba una preferencia que el
1970
+ * usuario nunca expresó.
1971
+ *
1972
+ * Persistir es responsabilidad de `setLanguage()`, que se llama cuando la
1973
+ * elección sí es del usuario (o cuando el initializer ya decidió con la
1974
+ * config a la vista).
1937
1975
  */
1938
1976
  loadStoredLanguage() {
1939
1977
  // SSR: sin localStorage/navigator. Mantenemos el default; el browser
@@ -1946,11 +1984,11 @@ class I18nService {
1946
1984
  this._lang.set(stored);
1947
1985
  return;
1948
1986
  }
1949
- // Detectar idioma del navegador
1987
+ // Adivinanza provisional mientras el initializer no haya corrido. Sin
1988
+ // persistir: ver el comentario del método.
1950
1989
  const browserLang = navigator.language.split('-')[0];
1951
1990
  if (this.isValidLanguage(browserLang)) {
1952
1991
  this._lang.set(browserLang);
1953
- localStorage.setItem(LANG_STORAGE_KEY$1, browserLang);
1954
1992
  }
1955
1993
  }
1956
1994
  /**
@@ -40767,13 +40805,16 @@ class SurveyBuilderComponent {
40767
40805
  }
40768
40806
  }
40769
40807
  async ngOnInit() {
40808
+ // Sembrado directo: la app ya tenía la encuesta, no hace falta leerla.
40809
+ if (this.props.initial) {
40810
+ this.hydrate(this.props.initial.label, this.props.initial.subtitle, this.props.initial.questions);
40811
+ return;
40812
+ }
40770
40813
  if (!this.props.typeId)
40771
40814
  return;
40772
40815
  try {
40773
40816
  const cfg = await firstValueFrom(this.requests.getRequestType(this.props.typeId));
40774
- this.titleControl.setValue(cfg.label);
40775
- this.subtitleControl.setValue(cfg.subtitle ?? '');
40776
- this.questions.set([...cfg.fieldSchema].sort((a, b) => a.order - b.order).map(f => this.rowFromField(f)));
40817
+ this.hydrate(cfg.label, cfg.subtitle ?? '', cfg.fieldSchema);
40777
40818
  }
40778
40819
  catch (err) {
40779
40820
  this.errors.handle(err, {
@@ -40960,6 +41001,11 @@ class SurveyBuilderComponent {
40960
41001
  });
40961
41002
  }
40962
41003
  }
41004
+ hydrate(label, subtitle, questions) {
41005
+ this.titleControl.setValue(label ?? '');
41006
+ this.subtitleControl.setValue(subtitle ?? '');
41007
+ this.questions.set([...(questions ?? [])].sort((a, b) => a.order - b.order).map(f => this.rowFromField(f)));
41008
+ }
40963
41009
  rowFromField(f) {
40964
41010
  return {
40965
41011
  id: `row-${rowUid++}`,