http-request-manager 18.16.2 → 18.16.4

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.
@@ -1868,10 +1868,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
1868
1868
  */
1869
1869
  class WebSocketManagerService {
1870
1870
  constructor() {
1871
+ this.isConnecting$ = WebSocketManagerService.isConnectingSubject.asObservable();
1871
1872
  this.retryCount$ = WebSocketManagerService.retryCountSubject.asObservable();
1872
1873
  this.maxRetries$ = WebSocketManagerService.maxRetriesSubject.asObservable();
1873
1874
  this.messages$ = WebSocketManagerService.messages.asObservable();
1874
1875
  this.connectionStatus$ = WebSocketManagerService.connectionStatus.asObservable();
1876
+ this.connectionError$ = WebSocketManagerService.connectionError.asObservable();
1875
1877
  this.subscribedChannels$ = WebSocketManagerService.subscribedChannels.asObservable();
1876
1878
  this.onReconnect$ = WebSocketManagerService.onReconnect.asObservable();
1877
1879
  }
@@ -1879,8 +1881,9 @@ class WebSocketManagerService {
1879
1881
  // STATIC SINGLETON STATE (Shared across ALL instances)
1880
1882
  // ═══════════════════════════════════════════════════════════════════════════
1881
1883
  static { this.socket = null; }
1882
- static { this.isConnecting = false; }
1884
+ static { this.isConnectingSubject = new BehaviorSubject(false); }
1883
1885
  static { this.connectionInitialized = false; }
1886
+ static { this.shouldRetry = true; }
1884
1887
  // Store last options for reconnection
1885
1888
  static { this.lastOptions = null; }
1886
1889
  static { this.lastJwtToken = ''; }
@@ -1897,6 +1900,7 @@ class WebSocketManagerService {
1897
1900
  // ═══════════════════════════════════════════════════════════════════════════
1898
1901
  static { this.messages = new BehaviorSubject(null); }
1899
1902
  static { this.connectionStatus = new BehaviorSubject(false); }
1903
+ static { this.connectionError = new BehaviorSubject(null); }
1900
1904
  static { this.isSubscribed = false; }
1901
1905
  // Track currently subscribed channels
1902
1906
  static { this.subscribedChannels = new BehaviorSubject(new Set()); }
@@ -1939,6 +1943,7 @@ class WebSocketManagerService {
1939
1943
  // Cancel any pending retry timer before attempting a new connection
1940
1944
  WebSocketManagerService.retrySubscription?.unsubscribe();
1941
1945
  WebSocketManagerService.retrySubscription = null;
1946
+ WebSocketManagerService.connectionError.next(null);
1942
1947
  // Check if connection already exists and is open
1943
1948
  if (WebSocketManagerService.socket) {
1944
1949
  if (WebSocketManagerService.socket.readyState === WebSocket.OPEN) {
@@ -1958,7 +1963,7 @@ class WebSocketManagerService {
1958
1963
  }
1959
1964
  }
1960
1965
  // Prevent duplicate connection attempts
1961
- if (WebSocketManagerService.isConnecting) {
1966
+ if (WebSocketManagerService.isConnectingSubject.value) {
1962
1967
  console.log('⏳ Connection already in progress...');
1963
1968
  return;
1964
1969
  }
@@ -1980,12 +1985,15 @@ class WebSocketManagerService {
1980
1985
  else {
1981
1986
  WebSocketManagerService.retryDelay = 5000;
1982
1987
  }
1983
- // Mark as connecting connectionStatus true while connecting/retrying, false only when exhausted
1984
- WebSocketManagerService.isConnecting = true;
1988
+ // Reset shouldRetry flag for new connection attempts
1989
+ WebSocketManagerService.shouldRetry = true;
1990
+ // Mark as connecting — connectionStatus false while connecting, true only when connected
1991
+ WebSocketManagerService.isConnectingSubject.next(true);
1985
1992
  WebSocketManagerService.isSubscribed = false;
1986
1993
  WebSocketManagerService.connectionReadyNotified = false;
1987
1994
  WebSocketManagerService.subscribedChannels.next(new Set());
1988
- WebSocketManagerService.connectionStatus.next(true);
1995
+ // Don't set connectionStatus to true here - only set to true when connection is actually established
1996
+ // WebSocketManagerService.connectionStatus.next(true);
1989
1997
  const sessionId = this.getSessionId();
1990
1998
  const URL = (jwtToken) ? `${options.wsServer}?token=${jwtToken}&sessionId=${sessionId}` : `${options.wsServer}?sessionId=${sessionId}`;
1991
1999
  console.log(`🔌 Initiating WebSocket connection to: ${options.wsServer}`);
@@ -1999,17 +2007,22 @@ class WebSocketManagerService {
1999
2007
  // Do NOT reset retryCount here — reset happens only on confirmed stable connection
2000
2008
  // (onmessage first valid response). Resetting here would cause the counter to always
2001
2009
  // show 1/N because onopen fires before onclose increments the counter.
2002
- WebSocketManagerService.isConnecting = false;
2010
+ WebSocketManagerService.isConnectingSubject.next(false);
2003
2011
  WebSocketManagerService.connectionInitialized = true;
2012
+ // Do NOT set connectionStatus to true here - wait for server to confirm authentication via onmessage
2004
2013
  };
2005
2014
  WebSocketManagerService.socket.onmessage = (event) => {
2006
2015
  try {
2007
2016
  const data = JSON.parse(event.data);
2008
2017
  if (data.error) {
2009
2018
  WebSocketManagerService.messages.next(data);
2010
- // Log the server error and close — onclose will drive the retry logic
2011
2019
  if (data.error === 'JWT_INVALID' || data.error === 'AUTH_BLOCKED') {
2012
- console.error(`🚫 ${data.error}: ${data.message || 'Authentication error'} — will retry`);
2020
+ console.error(`🚫 ${data.error}: ${data.message || 'Authentication error'} — stopping, no retry`);
2021
+ WebSocketManagerService.lastOptions = null;
2022
+ WebSocketManagerService.connectionError.next('Invalid or Expired JWT');
2023
+ WebSocketManagerService.connectionStatus.next(false);
2024
+ // Stop retrying for authentication errors
2025
+ WebSocketManagerService.shouldRetry = false;
2013
2026
  }
2014
2027
  else {
2015
2028
  console.error(`❌ Server error: ${data.error} — will retry`);
@@ -2027,6 +2040,8 @@ class WebSocketManagerService {
2027
2040
  WebSocketManagerService.retryCountSubject.next(0);
2028
2041
  }
2029
2042
  WebSocketManagerService.connectionReadyNotified = true;
2043
+ // Set connection status to true only when server confirms authentication
2044
+ WebSocketManagerService.connectionStatus.next(true);
2030
2045
  console.log(`🔄 Emitting reconnect event for MessageTrackerService`);
2031
2046
  WebSocketManagerService.onReconnect.next();
2032
2047
  }
@@ -2038,13 +2053,21 @@ class WebSocketManagerService {
2038
2053
  };
2039
2054
  WebSocketManagerService.socket.onclose = (event) => {
2040
2055
  console.log(`🔴 WebSocket closed (code: ${event.code})`);
2041
- WebSocketManagerService.isConnecting = false;
2056
+ WebSocketManagerService.isConnectingSubject.next(false);
2042
2057
  WebSocketManagerService.connectionReadyNotified = false;
2043
2058
  WebSocketManagerService.socket = null;
2044
2059
  WebSocketManagerService.subscribedChannels.next(new Set());
2060
+ if (event.code === 4000 || event.code === 4001 || event.code === 4003) {
2061
+ WebSocketManagerService.connectionError.next('Invalid or Expired JWT');
2062
+ WebSocketManagerService.connectionStatus.next(false);
2063
+ // Stop retrying for authentication errors
2064
+ WebSocketManagerService.shouldRetry = false;
2065
+ return;
2066
+ }
2045
2067
  const maxRetries = WebSocketManagerService.maxRetries;
2046
2068
  const retryDelay = WebSocketManagerService.retryDelay;
2047
- if (WebSocketManagerService.lastOptions && WebSocketManagerService.retryCount < maxRetries) {
2069
+ // Only retry if shouldRetry is true and we haven't exceeded max retries
2070
+ if (WebSocketManagerService.shouldRetry && WebSocketManagerService.lastOptions && WebSocketManagerService.retryCount < maxRetries) {
2048
2071
  WebSocketManagerService.retryCount++;
2049
2072
  WebSocketManagerService.retryCountSubject.next(WebSocketManagerService.retryCount);
2050
2073
  console.log(`🔄 Reconnect attempt ${WebSocketManagerService.retryCount}/${maxRetries}...`);
@@ -2054,13 +2077,19 @@ class WebSocketManagerService {
2054
2077
  else {
2055
2078
  console.error(`❌ WebSocket failed after ${maxRetries} retries. Giving up.`);
2056
2079
  WebSocketManagerService.connectionStatus.next(false);
2080
+ // Set error message if not already set
2081
+ if (!WebSocketManagerService.connectionError.value) {
2082
+ WebSocketManagerService.connectionError.next('Connection failed after maximum retries');
2083
+ }
2057
2084
  WebSocketManagerService.retryCount = maxRetries;
2058
2085
  WebSocketManagerService.retryCountSubject.next(maxRetries);
2086
+ // Reset shouldRetry flag for future connection attempts
2087
+ WebSocketManagerService.shouldRetry = true;
2059
2088
  }
2060
2089
  };
2061
2090
  WebSocketManagerService.socket.onerror = (error) => {
2062
2091
  console.error('❌ WebSocket error:', error);
2063
- WebSocketManagerService.isConnecting = false;
2092
+ WebSocketManagerService.isConnectingSubject.next(false);
2064
2093
  // onclose will fire after onerror and drive retry/give-up logic
2065
2094
  };
2066
2095
  }
@@ -3784,8 +3813,10 @@ class HTTPManagerService extends RequestService {
3784
3813
  this.connectionStatus$ = this.wsManager.connectionStatus$;
3785
3814
  this.messages$ = this.messageTracker.messages$; // Messages flow through MessageTrackerService
3786
3815
  this.subscribedChannels$ = this.wsManager.subscribedChannels$;
3816
+ this.isConnecting$ = this.wsManager.isConnecting$;
3787
3817
  this.retryCount$ = this.wsManager.retryCount$;
3788
3818
  this.maxRetries$ = this.wsManager.maxRetries$;
3819
+ this.connectionError$ = this.wsManager.connectionError$;
3789
3820
  this.countdown = new BehaviorSubject(0);
3790
3821
  this.countdown$ = this.countdown.asObservable();
3791
3822
  this.error = new BehaviorSubject(false);
@@ -6647,8 +6678,10 @@ class HTTPManagerStateService extends ComponentStore {
6647
6678
  this.wsOptions = WSOptions.adapt();
6648
6679
  // Expose raw WS connection status directly to UI (from singleton WebSocketManagerService)
6649
6680
  this.connectionStatus$ = this.httpManagerService.connectionStatus$;
6681
+ this.isConnecting$ = this.httpManagerService.isConnecting$;
6650
6682
  this.wsRetryCount$ = this.httpManagerService.retryCount$;
6651
6683
  this.wsMaxRetries$ = this.httpManagerService.maxRetries$;
6684
+ this.connectionError$ = this.httpManagerService.connectionError$;
6652
6685
  // WebSocket
6653
6686
  this.initWS = this.effect((wsOptions$) => wsOptions$.pipe(switchMap((wsOptions) => merge(this.httpManagerService.connectionStatus$.pipe(tap((isConnected) => {
6654
6687
  if (isConnected) {
@@ -12407,6 +12440,8 @@ class RequestManagerWsDemoComponent {
12407
12440
  this.retryCount$ = this.stateService.wsRetryCount$;
12408
12441
  this.maxRetries$ = this.stateService.wsMaxRetries$;
12409
12442
  this.connectionStatus$ = this.stateService.connectionStatus$;
12443
+ this.isConnecting$ = this.stateService.isConnecting$;
12444
+ this.connectionError$ = this.stateService.connectionError$;
12410
12445
  this.data$ = this.stateService.data$;
12411
12446
  this.isPending$ = this.stateService.isPending$;
12412
12447
  }
@@ -12414,11 +12449,11 @@ class RequestManagerWsDemoComponent {
12414
12449
  this.stateService.updateConnection(this.server, this.wsServer, this.jwtToken, this.user, this.path);
12415
12450
  }
12416
12451
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
12417
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: RequestManagerWsDemoComponent, selector: "app-request-manager-ws-demo", inputs: { server: "server", wsServer: "wsServer", jwtToken: "jwtToken", user: "user", path: "path" }, ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <h2 style=\"display: flex;\">\n <span style=\"flex:1\">HTTP Request State Manager - Websockets</span>\n @if ((connectionStatus$ | async); as connected) {\n <span>\n WS -\n <span style=\"color: green;\">Connected</span>\n </span>\n } @else {\n <span style=\"color: red;\">Disconnected {{ retryCount$ | async }} / {{ maxRetries$ | async }}</span>\n }\n </h2>\n\n <div>\n\n @if ((user$ | async); as userInfo) {\n <div>\n <mat-toolbar>\n <div style=\"display: flex; flex:1\">\n <div style=\"flex:1\">{{ userInfo.name }}</div>\n <div>({{ userInfo.ldap }})</div>\n </div>\n </mat-toolbar>\n </div>\n }\n\n @if (!(connectionStatus$ | async) && ((retryCount$ | async) ?? 0) < ((maxRetries$ | async) ?? 0)) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n }\n\n <mat-tab-group animationDuration=\"0ms\" [selectedIndex]=\"1\">\n\n <mat-tab label=\"WS - Data Control\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- DATA CONTROL -->\n <app-ws-data-control\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-data-control>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Messaging\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- MESSAGING -->\n <app-ws-messaging\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-messaging>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Notifications\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- WS - Notifications -->\n <app-ws-notifications\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n ></app-ws-notifications>\n </mat-tab>\n\n <mat-tab label=\"WS - Chats\" [disabled]=\"true\">\n <!-- WS - Chats -->\n <app-ws-chats></app-ws-chats>\n </mat-tab>\n\n <mat-tab label=\"WS - AI Messaging\" [disabled]=\"true\">\n <!-- WS - AI Messaging -->\n <app-ws-ai-messaging></app-ws-ai-messaging>\n </mat-tab>\n\n </mat-tab-group>\n</div>\n\n</div>\n\n", styles: [""], dependencies: [{ kind: "component", type: i1$2.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i1$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "component", type: i8$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i3$2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: WsDataControlComponent, selector: "app-ws-data-control", inputs: ["server", "wsServer", "jwtToken", "user", "path"] }, { kind: "component", type: WsMessagingComponent, selector: "app-ws-messaging", inputs: ["server", "wsServer", "jwtToken", "user", "path"] }, { kind: "component", type: WsNotificationsComponent, selector: "app-ws-notifications", inputs: ["server", "wsServer", "jwtToken", "user"] }, { kind: "component", type: WsAiMessagingComponent, selector: "app-ws-ai-messaging" }, { kind: "component", type: WsChatsComponent, selector: "app-ws-chats" }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }] }); }
12452
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: RequestManagerWsDemoComponent, selector: "app-request-manager-ws-demo", inputs: { server: "server", wsServer: "wsServer", jwtToken: "jwtToken", user: "user", path: "path" }, ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <h2 style=\"display: flex;\">\n <span style=\"flex:1\">HTTP Request State Manager - Websockets</span>\n @if ((connectionStatus$ | async); as connected) {\n <span>\n WS -\n <span style=\"color: green;\">Connected</span>\n </span>\n } @else if (connectionError$ | async) {\n <span style=\"color: red;\">{{ connectionError$ | async }}</span>\n } @else if (isConnecting$ | async) {\n <span style=\"color: orange;\">Connecting... {{ retryCount$ | async }} / {{ maxRetries$ | async }}</span>\n } @else {\n <span style=\"color: red;\">Disconnected</span>\n }\n </h2>\n\n <div>\n\n @if ((user$ | async); as userInfo) {\n <div>\n <mat-toolbar>\n <div style=\"display: flex; flex:1\">\n <div style=\"flex:1\">{{ userInfo.name }}</div>\n <div>({{ userInfo.ldap }})</div>\n </div>\n </mat-toolbar>\n </div>\n }\n\n @if ((isConnecting$ | async) && !(connectionStatus$ | async) && !(connectionError$ | async)) {\n <div style=\"display: flex; align-items: center; gap: 1rem; padding: 0.5rem; background: #e3f2fd; border-radius: 4px; margin-bottom: 0.5rem;\">\n <span>Connecting to WebSocket...</span>\n <mat-progress-bar mode=\"indeterminate\" style=\"flex: 1;\"></mat-progress-bar>\n </div>\n }\n\n @if (connectionError$ | async; as errorMsg) {\n <div style=\"padding: 0.75rem 1rem; background: #fdecea; color: #b00020; border-left: 4px solid #b00020; border-radius: 2px; margin-bottom: 0.5rem;\">\n {{ errorMsg }}\n </div>\n }\n\n <mat-tab-group animationDuration=\"0ms\" [selectedIndex]=\"1\">\n\n <mat-tab label=\"WS - Data Control\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- DATA CONTROL -->\n <app-ws-data-control\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-data-control>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Messaging\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- MESSAGING -->\n <app-ws-messaging\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-messaging>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Notifications\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- WS - Notifications -->\n <app-ws-notifications\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n ></app-ws-notifications>\n </mat-tab>\n\n <mat-tab label=\"WS - Chats\" [disabled]=\"true\">\n <!-- WS - Chats -->\n <app-ws-chats></app-ws-chats>\n </mat-tab>\n\n <mat-tab label=\"WS - AI Messaging\" [disabled]=\"true\">\n <!-- WS - AI Messaging -->\n <app-ws-ai-messaging></app-ws-ai-messaging>\n </mat-tab>\n\n </mat-tab-group>\n</div>\n\n</div>\n\n", styles: [""], dependencies: [{ kind: "component", type: i1$2.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i1$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "component", type: i8$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i3$2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: WsDataControlComponent, selector: "app-ws-data-control", inputs: ["server", "wsServer", "jwtToken", "user", "path"] }, { kind: "component", type: WsMessagingComponent, selector: "app-ws-messaging", inputs: ["server", "wsServer", "jwtToken", "user", "path"] }, { kind: "component", type: WsNotificationsComponent, selector: "app-ws-notifications", inputs: ["server", "wsServer", "jwtToken", "user"] }, { kind: "component", type: WsAiMessagingComponent, selector: "app-ws-ai-messaging" }, { kind: "component", type: WsChatsComponent, selector: "app-ws-chats" }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }] }); }
12418
12453
  }
12419
12454
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, decorators: [{
12420
12455
  type: Component,
12421
- args: [{ selector: 'app-request-manager-ws-demo', standalone: false, template: "<div style=\"margin: 2rem;\">\n\n <h2 style=\"display: flex;\">\n <span style=\"flex:1\">HTTP Request State Manager - Websockets</span>\n @if ((connectionStatus$ | async); as connected) {\n <span>\n WS -\n <span style=\"color: green;\">Connected</span>\n </span>\n } @else {\n <span style=\"color: red;\">Disconnected {{ retryCount$ | async }} / {{ maxRetries$ | async }}</span>\n }\n </h2>\n\n <div>\n\n @if ((user$ | async); as userInfo) {\n <div>\n <mat-toolbar>\n <div style=\"display: flex; flex:1\">\n <div style=\"flex:1\">{{ userInfo.name }}</div>\n <div>({{ userInfo.ldap }})</div>\n </div>\n </mat-toolbar>\n </div>\n }\n\n @if (!(connectionStatus$ | async) && ((retryCount$ | async) ?? 0) < ((maxRetries$ | async) ?? 0)) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n }\n\n <mat-tab-group animationDuration=\"0ms\" [selectedIndex]=\"1\">\n\n <mat-tab label=\"WS - Data Control\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- DATA CONTROL -->\n <app-ws-data-control\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-data-control>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Messaging\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- MESSAGING -->\n <app-ws-messaging\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-messaging>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Notifications\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- WS - Notifications -->\n <app-ws-notifications\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n ></app-ws-notifications>\n </mat-tab>\n\n <mat-tab label=\"WS - Chats\" [disabled]=\"true\">\n <!-- WS - Chats -->\n <app-ws-chats></app-ws-chats>\n </mat-tab>\n\n <mat-tab label=\"WS - AI Messaging\" [disabled]=\"true\">\n <!-- WS - AI Messaging -->\n <app-ws-ai-messaging></app-ws-ai-messaging>\n </mat-tab>\n\n </mat-tab-group>\n</div>\n\n</div>\n\n" }]
12456
+ args: [{ selector: 'app-request-manager-ws-demo', standalone: false, template: "<div style=\"margin: 2rem;\">\n\n <h2 style=\"display: flex;\">\n <span style=\"flex:1\">HTTP Request State Manager - Websockets</span>\n @if ((connectionStatus$ | async); as connected) {\n <span>\n WS -\n <span style=\"color: green;\">Connected</span>\n </span>\n } @else if (connectionError$ | async) {\n <span style=\"color: red;\">{{ connectionError$ | async }}</span>\n } @else if (isConnecting$ | async) {\n <span style=\"color: orange;\">Connecting... {{ retryCount$ | async }} / {{ maxRetries$ | async }}</span>\n } @else {\n <span style=\"color: red;\">Disconnected</span>\n }\n </h2>\n\n <div>\n\n @if ((user$ | async); as userInfo) {\n <div>\n <mat-toolbar>\n <div style=\"display: flex; flex:1\">\n <div style=\"flex:1\">{{ userInfo.name }}</div>\n <div>({{ userInfo.ldap }})</div>\n </div>\n </mat-toolbar>\n </div>\n }\n\n @if ((isConnecting$ | async) && !(connectionStatus$ | async) && !(connectionError$ | async)) {\n <div style=\"display: flex; align-items: center; gap: 1rem; padding: 0.5rem; background: #e3f2fd; border-radius: 4px; margin-bottom: 0.5rem;\">\n <span>Connecting to WebSocket...</span>\n <mat-progress-bar mode=\"indeterminate\" style=\"flex: 1;\"></mat-progress-bar>\n </div>\n }\n\n @if (connectionError$ | async; as errorMsg) {\n <div style=\"padding: 0.75rem 1rem; background: #fdecea; color: #b00020; border-left: 4px solid #b00020; border-radius: 2px; margin-bottom: 0.5rem;\">\n {{ errorMsg }}\n </div>\n }\n\n <mat-tab-group animationDuration=\"0ms\" [selectedIndex]=\"1\">\n\n <mat-tab label=\"WS - Data Control\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- DATA CONTROL -->\n <app-ws-data-control\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-data-control>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Messaging\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- MESSAGING -->\n <app-ws-messaging\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-messaging>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Notifications\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- WS - Notifications -->\n <app-ws-notifications\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n ></app-ws-notifications>\n </mat-tab>\n\n <mat-tab label=\"WS - Chats\" [disabled]=\"true\">\n <!-- WS - Chats -->\n <app-ws-chats></app-ws-chats>\n </mat-tab>\n\n <mat-tab label=\"WS - AI Messaging\" [disabled]=\"true\">\n <!-- WS - AI Messaging -->\n <app-ws-ai-messaging></app-ws-ai-messaging>\n </mat-tab>\n\n </mat-tab-group>\n</div>\n\n</div>\n\n" }]
12422
12457
  }], propDecorators: { server: [{
12423
12458
  type: Input
12424
12459
  }], wsServer: [{