@yuuvis/client-core 2.10.2 → 2.11.0

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.
@@ -5,7 +5,7 @@ import { HttpErrorResponse, HttpClient, HttpHeaders, HttpRequest, HttpParams, Ht
5
5
  import * as i0 from '@angular/core';
6
6
  import { inject, Injectable, InjectionToken, NgZone, Inject, signal, Directive, Pipe, makeEnvironmentProviders, importProvidersFrom, provideAppInitializer } from '@angular/core';
7
7
  import { tap, finalize, shareReplay, catchError, map, switchMap, first, filter, scan, delay } from 'rxjs/operators';
8
- import { EMPTY, of, forkJoin, Observable, ReplaySubject, Subject, BehaviorSubject, tap as tap$1, map as map$1, merge, fromEvent, filter as filter$1, debounceTime, throwError, catchError as catchError$1, switchMap as switchMap$1, isObservable } from 'rxjs';
8
+ import { EMPTY, Subject, of, forkJoin, Observable, ReplaySubject, BehaviorSubject, tap as tap$1, map as map$1, merge, fromEvent, filter as filter$1, debounceTime, throwError, catchError as catchError$1, switchMap as switchMap$1, isObservable } from 'rxjs';
9
9
  import { StorageMap } from '@ngx-pwa/local-storage';
10
10
  import { __decorate, __param, __metadata } from 'tslib';
11
11
  import { coerceBooleanProperty } from '@angular/cdk/coercion';
@@ -969,10 +969,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
969
969
  }], ctorParameters: () => [{ type: ConfigService }] });
970
970
 
971
971
  /**
972
- * Service for http communication with the yuuvis Momentum backend. Apps
973
- * should use this service to communicate with the backend instead of default
974
- * httpClient because required headers are managed and apps do not have
975
- * to care about prerequisites.
972
+ * Service for HTTP communication with the yuuvis Momentum backend.
973
+ *
974
+ * This service wraps Angular's HttpClient and provides:
975
+ * - Automatic base URI management for different backend services
976
+ * - Centralized header management (authorization, content-type, etc.)
977
+ * - Response caching with configurable TTL
978
+ * - HTTP activity tracking for session management
979
+ * - Standardized error handling and logging
980
+ *
981
+ * **Why Use This Service:**
982
+ * Applications should use BackendService instead of HttpClient directly because
983
+ * required headers (authentication, content-type) are automatically managed,
984
+ * and apps don't have to handle backend URL construction and prerequisites.
985
+ *
986
+ * **HTTP Activity Tracking:**
987
+ * All HTTP requests emit events via `httpCommunicationOccurred$`, which is used by
988
+ * SessionService and other consumers to detect user activity and keep sessions alive.
989
+ *
990
+ * @see {@link SessionService} for session management integration (Task HAR-2975)
976
991
  */
977
992
  class BackendService {
978
993
  constructor() {
@@ -984,12 +999,55 @@ class BackendService {
984
999
  this.#headers = new HttpHeaders({
985
1000
  'Content-Type': 'application/json'
986
1001
  });
1002
+ /**
1003
+ * Observable that emits every time HTTP communication occurs with the server.
1004
+ *
1005
+ * This observable is used by:
1006
+ * - **SessionService**: To detect user activity and automatically extend sessions (Task 2975)
1007
+ * - **Other consumers**: Potentially for activity tracking, analytics, or loading indicators
1008
+ *
1009
+ * Events are emitted on every successful HTTP GET request. POST, PUT, DELETE, and PATCH
1010
+ * requests may also trigger events depending on the specific method implementation.
1011
+ *
1012
+ * **Usage Example:**
1013
+ * ```typescript
1014
+ * backendService.httpCommunicationOccurred$.subscribe(() => {
1015
+ * console.log('HTTP activity detected');
1016
+ * sessionService.extendSession();
1017
+ * });
1018
+ * ```
1019
+ *
1020
+ * @internal The private Subject should not be accessed directly; use the public observable
1021
+ */
1022
+ this.#httpCallOccurred$ = new Subject();
1023
+ this.httpCommunicationOccurred$ = this.#httpCallOccurred$.asObservable();
987
1024
  }
988
1025
  #http;
989
1026
  #logger;
990
1027
  #cache;
991
1028
  #temp;
992
1029
  #headers;
1030
+ /**
1031
+ * Observable that emits every time HTTP communication occurs with the server.
1032
+ *
1033
+ * This observable is used by:
1034
+ * - **SessionService**: To detect user activity and automatically extend sessions (Task 2975)
1035
+ * - **Other consumers**: Potentially for activity tracking, analytics, or loading indicators
1036
+ *
1037
+ * Events are emitted on every successful HTTP GET request. POST, PUT, DELETE, and PATCH
1038
+ * requests may also trigger events depending on the specific method implementation.
1039
+ *
1040
+ * **Usage Example:**
1041
+ * ```typescript
1042
+ * backendService.httpCommunicationOccurred$.subscribe(() => {
1043
+ * console.log('HTTP activity detected');
1044
+ * sessionService.extendSession();
1045
+ * });
1046
+ * ```
1047
+ *
1048
+ * @internal The private Subject should not be accessed directly; use the public observable
1049
+ */
1050
+ #httpCallOccurred$;
993
1051
  /**
994
1052
  * OpenIdConnect authorization headers
995
1053
  */
@@ -1018,7 +1076,7 @@ class BackendService {
1018
1076
  * @returns The data retrieved from the given endpoint
1019
1077
  */
1020
1078
  get(uri, base, requestOptions) {
1021
- return this.#http.get(this.getApiBase(base) + uri, this.getHttpOptions(requestOptions));
1079
+ return this.#http.get(this.getApiBase(base) + uri, this.getHttpOptions(requestOptions)).pipe(tap(() => this.#httpCallOccurred$.next()));
1022
1080
  }
1023
1081
  /**
1024
1082
  * Wrapped HTTP POST method
@@ -1031,7 +1089,7 @@ class BackendService {
1031
1089
  post(uri, data, base, requestOptions) {
1032
1090
  const baseUri = this.getApiBase(base);
1033
1091
  const payload = data && typeof data === 'object' ? JSON.stringify(data) : data || '';
1034
- return this.#http.post(`${baseUri}${uri}`, payload, this.getHttpOptions(requestOptions));
1092
+ return this.#http.post(`${baseUri}${uri}`, payload, this.getHttpOptions(requestOptions)).pipe(tap(() => this.#httpCallOccurred$.next()));
1035
1093
  }
1036
1094
  /**
1037
1095
  * Performs a multipart form data POST request.
@@ -1048,7 +1106,7 @@ class BackendService {
1048
1106
  // and the request would fail.
1049
1107
  // As our post method already sets the Content-Type to application/json we can't use it for multipart requests.
1050
1108
  const req = new HttpRequest('POST', `${this.getApiBase(base)}${uri}`, formData, requestOptions);
1051
- return this.#http.request(req);
1109
+ return this.#http.request(req).pipe(tap(() => this.#httpCallOccurred$.next()));
1052
1110
  }
1053
1111
  /**
1054
1112
  * Wrapped HTTP PATCH method
@@ -1061,7 +1119,7 @@ class BackendService {
1061
1119
  patch(uri, data, base, requestOptions) {
1062
1120
  const baseUri = this.getApiBase(base);
1063
1121
  const payload = data ? JSON.stringify(data) : '';
1064
- return this.#http.patch(`${baseUri}${uri}`, payload, this.getHttpOptions(requestOptions));
1122
+ return this.#http.patch(`${baseUri}${uri}`, payload, this.getHttpOptions(requestOptions)).pipe(tap(() => this.#httpCallOccurred$.next()));
1065
1123
  }
1066
1124
  /**
1067
1125
  * Wrapped HTTP PUT method
@@ -1072,7 +1130,7 @@ class BackendService {
1072
1130
  * @returns The return value of the target PUT endpoint
1073
1131
  */
1074
1132
  put(uri, data, base, requestOptions) {
1075
- return this.#http.put(this.getApiBase(base) + uri, data, this.getHttpOptions(requestOptions));
1133
+ return this.#http.put(this.getApiBase(base) + uri, data, this.getHttpOptions(requestOptions)).pipe(tap(() => this.#httpCallOccurred$.next()));
1076
1134
  }
1077
1135
  /**
1078
1136
  * Wrapped HTTP DELETE method
@@ -1082,7 +1140,7 @@ class BackendService {
1082
1140
  * @returns The return value of the target DELETE endpoint
1083
1141
  */
1084
1142
  delete(uri, base, requestOptions) {
1085
- return this.#http.delete(this.getApiBase(base) + uri, this.getHttpOptions(requestOptions));
1143
+ return this.#http.delete(this.getApiBase(base) + uri, this.getHttpOptions(requestOptions)).pipe(tap(() => this.#httpCallOccurred$.next()));
1086
1144
  }
1087
1145
  /**
1088
1146
  * @ignore
@@ -1159,6 +1217,7 @@ class BackendService {
1159
1217
  * Batch service
1160
1218
  */
1161
1219
  batch(requests) {
1220
+ this.#httpCallOccurred$.next();
1162
1221
  const httpRequests = requests.map((r) => this[(r.method || 'get').toLowerCase()]
1163
1222
  .apply(this, [r.uri, r.body, r.base, r.requestOptions].filter((a) => a))
1164
1223
  .pipe(catchError((err) => of({ _error: err }))));