http-request-manager 18.15.27 → 18.15.31
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.
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Injectable, APP_ID, Inject, InjectionToken, isDevMode, signal, effect, computed, Injector, Optional, EventEmitter, Input, Output, ViewEncapsulation, Component, NgModule, ViewChild } from '@angular/core';
|
|
2
|
+
import { inject, Injectable, APP_ID, Inject, InjectionToken, isDevMode, signal, effect, computed, Injector, Optional, DestroyRef, EventEmitter, Input, Output, ViewEncapsulation, Component, NgModule, ViewChild } from '@angular/core';
|
|
3
3
|
import { ComponentStore } from '@ngrx/component-store';
|
|
4
|
-
import { map, catchError, filter, tap, finalize, takeWhile, retry, startWith, mergeMap, takeUntil, concatMap, toArray, withLatestFrom, switchMap,
|
|
4
|
+
import { map, catchError, filter, take, tap, finalize, takeWhile, retry, startWith, mergeMap, takeUntil, concatMap, toArray, withLatestFrom, switchMap, delay, scan, distinctUntilChanged } from 'rxjs/operators';
|
|
5
5
|
import { HttpClient, HttpHeaders, HttpEventType, HttpHeaderResponse, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
6
6
|
import * as CryptoJS from 'crypto-js';
|
|
7
|
-
import { from, BehaviorSubject, EMPTY, throwError, defer, interval,
|
|
8
|
-
import { toObservable } from '@angular/core/rxjs-interop';
|
|
7
|
+
import { from, BehaviorSubject, EMPTY, timer, throwError, defer, interval, Subject, of, merge, Subscription, take as take$1, catchError as catchError$1, map as map$1, tap as tap$1, switchMap as switchMap$1, startWith as startWith$1, distinctUntilChanged as distinctUntilChanged$1, combineLatest, filter as filter$1, takeUntil as takeUntil$1, ReplaySubject } from 'rxjs';
|
|
8
|
+
import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
9
9
|
import { ToastMessageDisplayService, ToastDisplay, ToastColors, ToastMessageDisplayModule } from 'toast-message-display';
|
|
10
10
|
import Dexie from 'dexie';
|
|
11
11
|
import * as i1 from '@ngx-translate/core';
|
|
@@ -1854,6 +1854,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
1854
1854
|
*/
|
|
1855
1855
|
class WebSocketManagerService {
|
|
1856
1856
|
constructor() {
|
|
1857
|
+
this.retryCount$ = WebSocketManagerService.retryCountSubject.asObservable();
|
|
1858
|
+
this.maxRetries$ = WebSocketManagerService.maxRetriesSubject.asObservable();
|
|
1857
1859
|
this.messages$ = WebSocketManagerService.messages.asObservable();
|
|
1858
1860
|
this.connectionStatus$ = WebSocketManagerService.connectionStatus.asObservable();
|
|
1859
1861
|
this.subscribedChannels$ = WebSocketManagerService.subscribedChannels.asObservable();
|
|
@@ -1870,7 +1872,11 @@ class WebSocketManagerService {
|
|
|
1870
1872
|
static { this.lastJwtToken = ''; }
|
|
1871
1873
|
// Retry configuration
|
|
1872
1874
|
static { this.retryCount = 0; }
|
|
1873
|
-
static { this.
|
|
1875
|
+
static { this.retryDelay = 5000; }
|
|
1876
|
+
static { this.retrySubscription = null; }
|
|
1877
|
+
static { this.maxRetries = 10; }
|
|
1878
|
+
static { this.retryCountSubject = new BehaviorSubject(0); }
|
|
1879
|
+
static { this.maxRetriesSubject = new BehaviorSubject(10); }
|
|
1874
1880
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1875
1881
|
// INSTANCE OBSERVABLES (Shared across ALL instances via static BehaviorSubjects)
|
|
1876
1882
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -1915,6 +1921,9 @@ class WebSocketManagerService {
|
|
|
1915
1921
|
* @param jwtToken - Optional JWT token for authentication
|
|
1916
1922
|
*/
|
|
1917
1923
|
connect(options, jwtToken) {
|
|
1924
|
+
// Cancel any pending retry timer before attempting a new connection
|
|
1925
|
+
WebSocketManagerService.retrySubscription?.unsubscribe();
|
|
1926
|
+
WebSocketManagerService.retrySubscription = null;
|
|
1918
1927
|
// Check if connection already exists and is open
|
|
1919
1928
|
if (WebSocketManagerService.socket) {
|
|
1920
1929
|
if (WebSocketManagerService.socket.readyState === WebSocket.OPEN) {
|
|
@@ -1941,82 +1950,105 @@ class WebSocketManagerService {
|
|
|
1941
1950
|
// Store jwt token for retry
|
|
1942
1951
|
WebSocketManagerService.lastJwtToken = jwtToken;
|
|
1943
1952
|
WebSocketManagerService.lastOptions = options;
|
|
1944
|
-
|
|
1945
|
-
|
|
1953
|
+
// Always set maxRetries and delay from latest options
|
|
1954
|
+
if (options?.retry?.times) {
|
|
1955
|
+
WebSocketManagerService.maxRetries = options.retry.times;
|
|
1956
|
+
WebSocketManagerService.maxRetriesSubject.next(options.retry.times);
|
|
1957
|
+
}
|
|
1958
|
+
else {
|
|
1959
|
+
WebSocketManagerService.maxRetries = 10;
|
|
1960
|
+
WebSocketManagerService.maxRetriesSubject.next(10);
|
|
1961
|
+
}
|
|
1962
|
+
if (options?.retry?.delay) {
|
|
1963
|
+
WebSocketManagerService.retryDelay = options.retry.delay * 1000;
|
|
1964
|
+
}
|
|
1965
|
+
else {
|
|
1966
|
+
WebSocketManagerService.retryDelay = 5000;
|
|
1967
|
+
}
|
|
1968
|
+
// Mark as connecting — connectionStatus true while connecting/retrying, false only when exhausted
|
|
1946
1969
|
WebSocketManagerService.isConnecting = true;
|
|
1947
1970
|
WebSocketManagerService.isSubscribed = false;
|
|
1948
1971
|
WebSocketManagerService.subscribedChannels.next(new Set());
|
|
1972
|
+
WebSocketManagerService.connectionStatus.next(true);
|
|
1949
1973
|
const sessionId = this.getSessionId();
|
|
1950
1974
|
const URL = (jwtToken) ? `${options.wsServer}?token=${jwtToken}&sessionId=${sessionId}` : `${options.wsServer}?sessionId=${sessionId}`;
|
|
1951
1975
|
console.log(`🔌 Initiating WebSocket connection to: ${options.wsServer}`);
|
|
1952
1976
|
// Create new WebSocket instance (static)
|
|
1953
1977
|
WebSocketManagerService.socket = new WebSocket(URL);
|
|
1954
1978
|
WebSocketManagerService.socket.onopen = () => {
|
|
1955
|
-
console.log(`📡
|
|
1979
|
+
console.log(`📡 WebSocket handshake complete — awaiting server confirmation`);
|
|
1956
1980
|
// Force clear subscribedChannels on new connection - server lost our subscriptions
|
|
1957
1981
|
console.log('🧹 Clearing subscribedChannels on connect (was:', WebSocketManagerService.subscribedChannels.value.size, 'channels)');
|
|
1958
1982
|
WebSocketManagerService.subscribedChannels.next(new Set());
|
|
1959
|
-
|
|
1960
|
-
|
|
1983
|
+
// Do NOT reset retryCount here — reset happens only on confirmed stable connection
|
|
1984
|
+
// (onmessage first valid response). Resetting here would cause the counter to always
|
|
1985
|
+
// show 1/N because onopen fires before onclose increments the counter.
|
|
1961
1986
|
WebSocketManagerService.isConnecting = false;
|
|
1962
1987
|
WebSocketManagerService.connectionInitialized = true;
|
|
1963
|
-
// Emit reconnect event - MessageTrackerService will handle subscriptions with lastSeenId
|
|
1964
|
-
console.log(`🔄 Emitting reconnect event for MessageTrackerService`);
|
|
1965
|
-
WebSocketManagerService.onReconnect.next();
|
|
1966
1988
|
};
|
|
1967
1989
|
WebSocketManagerService.socket.onmessage = (event) => {
|
|
1968
1990
|
try {
|
|
1969
1991
|
const data = JSON.parse(event.data);
|
|
1970
|
-
if (data.error
|
|
1971
|
-
console.error(`🚫 ${data.error}: ${data.message || 'Authentication error'}`);
|
|
1972
|
-
WebSocketManagerService.jwtInvalidClose = true;
|
|
1992
|
+
if (data.error) {
|
|
1973
1993
|
WebSocketManagerService.messages.next(data);
|
|
1974
|
-
|
|
1994
|
+
// Log the server error and close — onclose will drive the retry logic
|
|
1995
|
+
if (data.error === 'JWT_INVALID' || data.error === 'AUTH_BLOCKED') {
|
|
1996
|
+
console.error(`🚫 ${data.error}: ${data.message || 'Authentication error'} — will retry`);
|
|
1997
|
+
}
|
|
1998
|
+
else {
|
|
1999
|
+
console.error(`❌ Server error: ${data.error} — will retry`);
|
|
2000
|
+
}
|
|
1975
2001
|
WebSocketManagerService.socket?.close();
|
|
1976
2002
|
return;
|
|
1977
2003
|
}
|
|
2004
|
+
// First valid (non-error) message confirms the server accepted auth.
|
|
2005
|
+
// Reset retry counter now that we have a stable connection.
|
|
2006
|
+
if (WebSocketManagerService.retryCount > 0) {
|
|
2007
|
+
console.log(`✅ Server confirmed connection after ${WebSocketManagerService.retryCount} retries.`);
|
|
2008
|
+
WebSocketManagerService.retryCount = 0;
|
|
2009
|
+
WebSocketManagerService.retryCountSubject.next(0);
|
|
2010
|
+
console.log(`🔄 Emitting reconnect event for MessageTrackerService`);
|
|
2011
|
+
WebSocketManagerService.onReconnect.next();
|
|
2012
|
+
}
|
|
1978
2013
|
WebSocketManagerService.messages.next(data);
|
|
1979
2014
|
}
|
|
1980
2015
|
catch (error) {
|
|
1981
2016
|
console.error('Error parsing WebSocket message:', event.data);
|
|
1982
2017
|
}
|
|
1983
2018
|
};
|
|
1984
|
-
WebSocketManagerService.socket.onclose = () => {
|
|
1985
|
-
console.log(
|
|
1986
|
-
console.log('🧹 Clearing subscribedChannels (was:', WebSocketManagerService.subscribedChannels.value.size, 'channels)');
|
|
1987
|
-
WebSocketManagerService.connectionStatus.next(false);
|
|
2019
|
+
WebSocketManagerService.socket.onclose = (event) => {
|
|
2020
|
+
console.log(`🔴 WebSocket closed (code: ${event.code})`);
|
|
1988
2021
|
WebSocketManagerService.isConnecting = false;
|
|
1989
2022
|
WebSocketManagerService.socket = null;
|
|
1990
|
-
// Clear subscribed channels - server lost our subscriptions
|
|
1991
2023
|
WebSocketManagerService.subscribedChannels.next(new Set());
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
console.error('🚫 WebSocket closed due to authentication block/invalid token. Not retrying.');
|
|
1995
|
-
WebSocketManagerService.retryCount = 0;
|
|
1996
|
-
return;
|
|
1997
|
-
}
|
|
1998
|
-
const maxRetries = WebSocketManagerService.lastOptions?.retry?.times || 3;
|
|
1999
|
-
const retryDelay = (WebSocketManagerService.lastOptions?.retry?.delay && WebSocketManagerService.lastOptions.retry.delay * 1000) || 5000;
|
|
2024
|
+
const maxRetries = WebSocketManagerService.maxRetries;
|
|
2025
|
+
const retryDelay = WebSocketManagerService.retryDelay;
|
|
2000
2026
|
if (WebSocketManagerService.lastOptions && WebSocketManagerService.retryCount < maxRetries) {
|
|
2001
2027
|
WebSocketManagerService.retryCount++;
|
|
2028
|
+
WebSocketManagerService.retryCountSubject.next(WebSocketManagerService.retryCount);
|
|
2002
2029
|
console.log(`🔄 Reconnect attempt ${WebSocketManagerService.retryCount}/${maxRetries}...`);
|
|
2003
|
-
|
|
2030
|
+
// connectionStatus stays true — still actively retrying
|
|
2031
|
+
WebSocketManagerService.retrySubscription = timer(retryDelay).pipe(take(1)).subscribe(() => this.connect(WebSocketManagerService.lastOptions, WebSocketManagerService.lastJwtToken));
|
|
2004
2032
|
}
|
|
2005
|
-
else
|
|
2006
|
-
console.error(`❌ WebSocket failed after ${maxRetries}
|
|
2007
|
-
WebSocketManagerService.
|
|
2033
|
+
else {
|
|
2034
|
+
console.error(`❌ WebSocket failed after ${maxRetries} retries. Giving up.`);
|
|
2035
|
+
WebSocketManagerService.connectionStatus.next(false);
|
|
2036
|
+
WebSocketManagerService.retryCount = maxRetries;
|
|
2037
|
+
WebSocketManagerService.retryCountSubject.next(maxRetries);
|
|
2008
2038
|
}
|
|
2009
2039
|
};
|
|
2010
2040
|
WebSocketManagerService.socket.onerror = (error) => {
|
|
2011
2041
|
console.error('❌ WebSocket error:', error);
|
|
2012
|
-
WebSocketManagerService.connectionStatus.next(false);
|
|
2013
2042
|
WebSocketManagerService.isConnecting = false;
|
|
2043
|
+
// onclose will fire after onerror and drive retry/give-up logic
|
|
2014
2044
|
};
|
|
2015
2045
|
}
|
|
2016
2046
|
/**
|
|
2017
2047
|
* Disconnect from WebSocket server
|
|
2018
2048
|
*/
|
|
2019
2049
|
disconnect() {
|
|
2050
|
+
WebSocketManagerService.retrySubscription?.unsubscribe();
|
|
2051
|
+
WebSocketManagerService.retrySubscription = null;
|
|
2020
2052
|
if (WebSocketManagerService.socket) {
|
|
2021
2053
|
console.log('🔌 Disconnecting WebSocket...');
|
|
2022
2054
|
WebSocketManagerService.socket.close();
|
|
@@ -3374,10 +3406,10 @@ class MessageTrackerService {
|
|
|
3374
3406
|
* Map<channel, retryCount>
|
|
3375
3407
|
*/
|
|
3376
3408
|
this.gapRetryCount = new Map();
|
|
3377
|
-
/** Batch acknowledgment timer */
|
|
3378
|
-
this.batchAckTimer = null;
|
|
3379
3409
|
/** Subscription to WebSocket messages */
|
|
3380
3410
|
this.messagesSubscription = null;
|
|
3411
|
+
/** Subject to signal destroy for takeUntil */
|
|
3412
|
+
this.destroy$ = new Subject();
|
|
3381
3413
|
/**
|
|
3382
3414
|
* Track channels we want to be subscribed to (survives disconnect/reconnect)
|
|
3383
3415
|
* This is separate from WebSocketManagerService.subscribedChannels which tracks
|
|
@@ -3391,7 +3423,9 @@ class MessageTrackerService {
|
|
|
3391
3423
|
this.restoreLastSeen();
|
|
3392
3424
|
this.restoreIntendedChannels();
|
|
3393
3425
|
// Start batch acknowledgment timer
|
|
3394
|
-
this.
|
|
3426
|
+
interval(this.BATCH_ACK_INTERVAL_MS)
|
|
3427
|
+
.pipe(takeUntil(this.destroy$))
|
|
3428
|
+
.subscribe(() => this.sendAllBatchAcks());
|
|
3395
3429
|
// Subscribe to all incoming WebSocket messages
|
|
3396
3430
|
this.messagesSubscription = this.wsManager.messages$.subscribe(msg => {
|
|
3397
3431
|
if (msg) {
|
|
@@ -3406,7 +3440,8 @@ class MessageTrackerService {
|
|
|
3406
3440
|
console.log('✅ MessageTrackerService initialized');
|
|
3407
3441
|
}
|
|
3408
3442
|
ngOnDestroy() {
|
|
3409
|
-
this.
|
|
3443
|
+
this.destroy$.next();
|
|
3444
|
+
this.destroy$.complete();
|
|
3410
3445
|
this.persistLastSeen(); // This now also persists intendedChannels
|
|
3411
3446
|
this.messagesSubscription?.unsubscribe();
|
|
3412
3447
|
console.log('🛑 MessageTrackerService destroyed');
|
|
@@ -3492,23 +3527,6 @@ class MessageTrackerService {
|
|
|
3492
3527
|
}
|
|
3493
3528
|
this.pendingAcks.get(channel).add(messageId);
|
|
3494
3529
|
}
|
|
3495
|
-
/**
|
|
3496
|
-
* Start batch acknowledgment timer
|
|
3497
|
-
*/
|
|
3498
|
-
startBatchAckTimer() {
|
|
3499
|
-
this.batchAckTimer = setInterval(() => {
|
|
3500
|
-
this.sendAllBatchAcks();
|
|
3501
|
-
}, this.BATCH_ACK_INTERVAL_MS);
|
|
3502
|
-
}
|
|
3503
|
-
/**
|
|
3504
|
-
* Stop batch acknowledgment timer
|
|
3505
|
-
*/
|
|
3506
|
-
stopBatchAckTimer() {
|
|
3507
|
-
if (this.batchAckTimer) {
|
|
3508
|
-
clearInterval(this.batchAckTimer);
|
|
3509
|
-
this.batchAckTimer = null;
|
|
3510
|
-
}
|
|
3511
|
-
}
|
|
3512
3530
|
/**
|
|
3513
3531
|
* Send batch acknowledgments for all channels with pending acks
|
|
3514
3532
|
*/
|
|
@@ -3745,6 +3763,8 @@ class HTTPManagerService extends RequestService {
|
|
|
3745
3763
|
this.connectionStatus$ = this.wsManager.connectionStatus$;
|
|
3746
3764
|
this.messages$ = this.messageTracker.messages$; // Messages flow through MessageTrackerService
|
|
3747
3765
|
this.subscribedChannels$ = this.wsManager.subscribedChannels$;
|
|
3766
|
+
this.retryCount$ = this.wsManager.retryCount$;
|
|
3767
|
+
this.maxRetries$ = this.wsManager.maxRetries$;
|
|
3748
3768
|
this.countdown = new BehaviorSubject(0);
|
|
3749
3769
|
this.countdown$ = this.countdown.asObservable();
|
|
3750
3770
|
this.error = new BehaviorSubject(false);
|
|
@@ -5664,6 +5684,7 @@ class LocalStorageSignalsManagerService {
|
|
|
5664
5684
|
this.defaultOptions = SettingOptions.adapt();
|
|
5665
5685
|
this.stateRetrieved = false;
|
|
5666
5686
|
this.encrypted = false;
|
|
5687
|
+
this.destroyRef = inject(DestroyRef);
|
|
5667
5688
|
this.app = inject(AppService);
|
|
5668
5689
|
this.utils = inject(UtilsService);
|
|
5669
5690
|
this.objectMergerService = inject(ObjectMergerService);
|
|
@@ -5726,7 +5747,7 @@ class LocalStorageSignalsManagerService {
|
|
|
5726
5747
|
}
|
|
5727
5748
|
});
|
|
5728
5749
|
// Expiration timer every 3s
|
|
5729
|
-
|
|
5750
|
+
interval(3000).pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
|
5730
5751
|
const state = this.state();
|
|
5731
5752
|
const expired = this.expired(state);
|
|
5732
5753
|
if (expired.length > 0) {
|
|
@@ -5740,7 +5761,7 @@ class LocalStorageSignalsManagerService {
|
|
|
5740
5761
|
this.state.set(updated);
|
|
5741
5762
|
this.persistState(updated);
|
|
5742
5763
|
}
|
|
5743
|
-
}
|
|
5764
|
+
});
|
|
5744
5765
|
}
|
|
5745
5766
|
// --- STATE MUTATORS ---
|
|
5746
5767
|
setStore(store) {
|
|
@@ -6518,53 +6539,40 @@ class QueryParamsTrackerService {
|
|
|
6518
6539
|
sessionStorage.removeItem(TRACKER_SESSION_INIT_KEY);
|
|
6519
6540
|
}
|
|
6520
6541
|
}
|
|
6521
|
-
|
|
6522
|
-
this.
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
.subscribe((storedState) => {
|
|
6528
|
-
if (!storedState?.paths?.[pathKey])
|
|
6529
|
-
return;
|
|
6530
|
-
const updatedPaths = { ...storedState.paths };
|
|
6531
|
-
delete updatedPaths[pathKey];
|
|
6532
|
-
const updatedState = { ...storedState, paths: updatedPaths };
|
|
6533
|
-
this.localStorageManager.updateStore({ name: TRACKER_STORE_NAME, data: updatedState });
|
|
6534
|
-
if (this.stateRestored && this.state.paths[pathKey]) {
|
|
6535
|
-
delete this.state.paths[pathKey];
|
|
6536
|
-
}
|
|
6537
|
-
});
|
|
6542
|
+
clearTrackingForPath(pathKey) {
|
|
6543
|
+
this.ensureStateRestored();
|
|
6544
|
+
if (this.state.paths[pathKey]) {
|
|
6545
|
+
delete this.state.paths[pathKey];
|
|
6546
|
+
this.persistState();
|
|
6547
|
+
}
|
|
6538
6548
|
}
|
|
6539
6549
|
checkRequestOptions(requestOptions = [], options = {}) {
|
|
6540
6550
|
this.ensureStateRestored();
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
return !pathSeenBefore;
|
|
6554
|
-
}
|
|
6555
|
-
if (options.mode === 'exact') {
|
|
6556
|
-
return this.checkExact(normalized, options);
|
|
6551
|
+
if (!this.ready$.value) {
|
|
6552
|
+
return true;
|
|
6553
|
+
}
|
|
6554
|
+
const normalized = this.normalizeRequestOptions(requestOptions);
|
|
6555
|
+
if (!normalized.pathKey)
|
|
6556
|
+
return false;
|
|
6557
|
+
this.cleanupExpiredEntries();
|
|
6558
|
+
if (!normalized.hasQuery) {
|
|
6559
|
+
const pathState = this.ensurePathState(normalized.pathKey);
|
|
6560
|
+
const pathSeenBefore = Object.keys(pathState.consumedValuesByKey).length > 0;
|
|
6561
|
+
if (!pathSeenBefore) {
|
|
6562
|
+
this.persistState();
|
|
6557
6563
|
}
|
|
6558
|
-
return
|
|
6559
|
-
}
|
|
6564
|
+
return !pathSeenBefore;
|
|
6565
|
+
}
|
|
6566
|
+
if (options.mode === 'exact') {
|
|
6567
|
+
return this.checkExact(normalized, options);
|
|
6568
|
+
}
|
|
6569
|
+
return this.checkVariation(normalized, options);
|
|
6560
6570
|
}
|
|
6561
6571
|
matchesPath(requestOptions = [], expectedPathOptions = []) {
|
|
6562
6572
|
this.ensureStateRestored();
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
return Boolean(requestPath) && requestPath === expectedPath;
|
|
6567
|
-
}));
|
|
6573
|
+
const requestPath = this.normalizeRequestOptions(requestOptions).pathKey;
|
|
6574
|
+
const expectedPath = this.normalizeRequestOptions(expectedPathOptions).pathKey;
|
|
6575
|
+
return Boolean(requestPath) && requestPath === expectedPath;
|
|
6568
6576
|
}
|
|
6569
6577
|
checkExact(normalized, options) {
|
|
6570
6578
|
const pathState = this.ensurePathState(normalized.pathKey);
|
|
@@ -6956,6 +6964,8 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
6956
6964
|
this.wsOptions = WSOptions.adapt();
|
|
6957
6965
|
// Expose raw WS connection status directly to UI (from singleton WebSocketManagerService)
|
|
6958
6966
|
this.connectionStatus$ = this.httpManagerService.connectionStatus$;
|
|
6967
|
+
this.wsRetryCount$ = this.httpManagerService.retryCount$;
|
|
6968
|
+
this.wsMaxRetries$ = this.httpManagerService.maxRetries$;
|
|
6959
6969
|
// WebSocket
|
|
6960
6970
|
this.initWS = this.effect((wsOptions$) => wsOptions$.pipe(switchMap((wsOptions) => merge(this.httpManagerService.connectionStatus$.pipe(tap((isConnected) => {
|
|
6961
6971
|
if (isConnected) {
|
|
@@ -8464,7 +8474,7 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
8464
8474
|
}
|
|
8465
8475
|
}
|
|
8466
8476
|
if (Array.isArray(pathArray) && pathArray.length > 0) {
|
|
8467
|
-
this.queryParamsTrackerService.
|
|
8477
|
+
this.queryParamsTrackerService.clearTrackingForPath(pathArray.join('/'));
|
|
8468
8478
|
this._requestCachePaths.delete(tableName);
|
|
8469
8479
|
}
|
|
8470
8480
|
if (!storeData)
|
|
@@ -8602,10 +8612,10 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
8602
8612
|
}
|
|
8603
8613
|
checkTrackerAllowsRequest(tableName, path, options, storeData) {
|
|
8604
8614
|
if (options && 'watchParams' in options) {
|
|
8605
|
-
return this.queryParamsTrackerService.checkRequestOptions(path, {
|
|
8615
|
+
return of(this.queryParamsTrackerService.checkRequestOptions(path, {
|
|
8606
8616
|
watchParams: options.watchParams,
|
|
8607
8617
|
watchExpiresAt: options?.watchExpiresAt,
|
|
8608
|
-
});
|
|
8618
|
+
}));
|
|
8609
8619
|
}
|
|
8610
8620
|
const normalized = this.trackerNormalizePath(path);
|
|
8611
8621
|
const ignoreQueryParams = Array.isArray(options?.ignoreQueryParams) ? options.ignoreQueryParams : [];
|
|
@@ -11701,11 +11711,8 @@ class WsMessagingComponent {
|
|
|
11701
11711
|
this.stateService.updateConnection(this.server, this.wsServer, this.jwtToken, this.user, this.path);
|
|
11702
11712
|
// Only trigger once when connection becomes true
|
|
11703
11713
|
this.connectionStatus$.pipe(filter$1(status => status === true), take$1(1), takeUntil$1(this.destroy$)).subscribe(() => {
|
|
11704
|
-
|
|
11705
|
-
|
|
11706
|
-
console.log('📋 Fetching channels after connection...');
|
|
11707
|
-
this.messageService.getAllChannels();
|
|
11708
|
-
}, 500); // 500ms delay to ensure subscription is processed
|
|
11714
|
+
console.log('📋 Fetching channels after connection...');
|
|
11715
|
+
this.messageService.getAllChannels();
|
|
11709
11716
|
});
|
|
11710
11717
|
// Subscribe to latest messages and display using rule-based routing
|
|
11711
11718
|
this.latestCommunicationMessages$.pipe(filter$1(message => !!message), takeUntil$1(this.destroy$)).subscribe((message) => {
|
|
@@ -12051,8 +12058,8 @@ class RequestManagerWsDemoComponent {
|
|
|
12051
12058
|
this.fb = inject(FormBuilder);
|
|
12052
12059
|
this.path = ['ai', 'tests'];
|
|
12053
12060
|
this.user$ = this.stateService.user$;
|
|
12054
|
-
this.
|
|
12055
|
-
this.
|
|
12061
|
+
this.retryCount$ = this.stateService.wsRetryCount$;
|
|
12062
|
+
this.maxRetries$ = this.stateService.wsMaxRetries$;
|
|
12056
12063
|
this.connectionStatus$ = this.stateService.connectionStatus$;
|
|
12057
12064
|
this.data$ = this.stateService.data$;
|
|
12058
12065
|
this.isPending$ = this.stateService.isPending$;
|
|
@@ -12061,11 +12068,11 @@ class RequestManagerWsDemoComponent {
|
|
|
12061
12068
|
this.stateService.updateConnection(this.server, this.wsServer, this.jwtToken, this.user, this.path);
|
|
12062
12069
|
}
|
|
12063
12070
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12064
|
-
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 {{
|
|
12071
|
+
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" }] }); }
|
|
12065
12072
|
}
|
|
12066
12073
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, decorators: [{
|
|
12067
12074
|
type: Component,
|
|
12068
|
-
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 {{
|
|
12075
|
+
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" }]
|
|
12069
12076
|
}], propDecorators: { server: [{
|
|
12070
12077
|
type: Input
|
|
12071
12078
|
}], wsServer: [{
|