http-request-manager 18.16.23 → 18.16.25

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, DestroyRef, EventEmitter, Input, Output, ViewEncapsulation, Component, NgModule, ViewChild } from '@angular/core';
2
+ import { inject, Injectable, APP_ID, Inject, InjectionToken, isDevMode, signal, DestroyRef, computed, effect, Injector, Optional, EventEmitter, Input, Output, ViewEncapsulation, Component, NgModule, ViewChild } from '@angular/core';
3
3
  import { ComponentStore } from '@ngrx/component-store';
4
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
7
  import { from, BehaviorSubject, EMPTY, timer, throwError, defer, interval, Subject, of, merge, Subscription, take as take$1, firstValueFrom, 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';
8
+ import { takeUntilDestroyed, toObservable, toSignal } 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 { Parser } from 'node-sql-parser/build/mysql';
@@ -2629,29 +2629,41 @@ class WebSocketSignalsManagerService {
2629
2629
  static { this.connectionStatusSignal = signal(false); }
2630
2630
  static { this.messagesSignal = signal(null); }
2631
2631
  static { this.subscribedChannelsSignal = signal(new Set()); }
2632
+ static { this.isConnectingSignal = signal(false); }
2633
+ static { this.retryCountSignal = signal(0); }
2634
+ static { this.maxRetriesSignal = signal(0); }
2635
+ static { this.connectionErrorSignal = signal(null); }
2632
2636
  constructor() {
2633
2637
  this.wsManager = inject(WebSocketManagerService);
2638
+ this.destroyRef = inject(DestroyRef);
2634
2639
  this.connectionStatus = WebSocketSignalsManagerService.connectionStatusSignal.asReadonly();
2635
- this.connectionStatus$ = toObservable(WebSocketSignalsManagerService.connectionStatusSignal);
2636
2640
  this.messages = WebSocketSignalsManagerService.messagesSignal.asReadonly();
2637
- this.messages$ = toObservable(WebSocketSignalsManagerService.messagesSignal);
2638
2641
  this.subscribedChannels = WebSocketSignalsManagerService.subscribedChannelsSignal.asReadonly();
2639
- this.subscribedChannels$ = toObservable(WebSocketSignalsManagerService.subscribedChannelsSignal);
2640
- // Sync with WebSocketManagerService state
2641
- effect(() => {
2642
- // This effect keeps our signals in sync with the BehaviorSubject-based manager
2643
- // In a future refactor, we can make WebSocketManagerService signal-based too
2644
- });
2645
- // Subscribe to WebSocket messages and update signals
2646
- this.wsManager.messages$.subscribe(message => {
2642
+ this.isConnecting = WebSocketSignalsManagerService.isConnectingSignal.asReadonly();
2643
+ this.retryCount = WebSocketSignalsManagerService.retryCountSignal.asReadonly();
2644
+ this.maxRetries = WebSocketSignalsManagerService.maxRetriesSignal.asReadonly();
2645
+ this.connectionError = WebSocketSignalsManagerService.connectionErrorSignal.asReadonly();
2646
+ this.wsManager.messages$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(message => {
2647
2647
  WebSocketSignalsManagerService.messagesSignal.set(message);
2648
2648
  });
2649
- this.wsManager.connectionStatus$.subscribe(status => {
2649
+ this.wsManager.connectionStatus$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(status => {
2650
2650
  WebSocketSignalsManagerService.connectionStatusSignal.set(status);
2651
2651
  });
2652
- this.wsManager.subscribedChannels$.subscribe(channels => {
2652
+ this.wsManager.subscribedChannels$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(channels => {
2653
2653
  WebSocketSignalsManagerService.subscribedChannelsSignal.set(channels);
2654
2654
  });
2655
+ this.wsManager.isConnecting$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(status => {
2656
+ WebSocketSignalsManagerService.isConnectingSignal.set(status);
2657
+ });
2658
+ this.wsManager.retryCount$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(count => {
2659
+ WebSocketSignalsManagerService.retryCountSignal.set(count);
2660
+ });
2661
+ this.wsManager.maxRetries$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(max => {
2662
+ WebSocketSignalsManagerService.maxRetriesSignal.set(max);
2663
+ });
2664
+ this.wsManager.connectionError$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(err => {
2665
+ WebSocketSignalsManagerService.connectionErrorSignal.set(err);
2666
+ });
2655
2667
  }
2656
2668
  // Connection Management
2657
2669
  connect(options, jwtToken) {
@@ -2731,12 +2743,140 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
2731
2743
  }]
2732
2744
  }], ctorParameters: () => [] });
2733
2745
 
2746
+ /**
2747
+ * ChannelPresenceSignalsService - Signal-based channel presence and metadata tracking.
2748
+ *
2749
+ * Tracks WebSocket messages, channel metadata, and user presence using pure signals.
2750
+ * No Observable bridges — consumers use `toObservable()` at the call site if needed.
2751
+ */
2752
+ class ChannelPresenceSignalsService {
2753
+ constructor() {
2754
+ this.wsManager = inject(WebSocketSignalsManagerService);
2755
+ // Signal-based state
2756
+ this.messagesSignal = signal(null);
2757
+ this.messages = this.messagesSignal.asReadonly();
2758
+ this.channelMetadataSignal = signal(new Map());
2759
+ this.channelMetadata = this.channelMetadataSignal.asReadonly();
2760
+ this.usersInChannelsSignal = signal(new Map());
2761
+ this.usersInChannels = this.usersInChannelsSignal.asReadonly();
2762
+ // Computed signals for derived state
2763
+ this.messageCount = computed(() => {
2764
+ const metadata = this.channelMetadataSignal();
2765
+ let count = 0;
2766
+ metadata.forEach(data => count += data.count);
2767
+ return count;
2768
+ });
2769
+ this.activeChannels = computed(() => {
2770
+ return Array.from(this.channelMetadataSignal().keys());
2771
+ });
2772
+ // Track messages from WebSocket
2773
+ effect(() => {
2774
+ const message = this.wsManager.messages();
2775
+ if (message) {
2776
+ this.trackMessage(message);
2777
+ }
2778
+ });
2779
+ // Track connection status
2780
+ effect(() => {
2781
+ const connected = this.wsManager.connectionStatus();
2782
+ if (!connected) {
2783
+ this.onDisconnect();
2784
+ }
2785
+ });
2786
+ }
2787
+ trackMessage(message) {
2788
+ this.messagesSignal.set(message);
2789
+ if (message.channel) {
2790
+ this.updateChannelMetadata(message.channel, message);
2791
+ }
2792
+ if (message.user && message.channel) {
2793
+ this.updateUserPresence(message.channel, message.user);
2794
+ }
2795
+ }
2796
+ updateChannelMetadata(channel, message) {
2797
+ this.channelMetadataSignal.update(metadata => {
2798
+ const updated = new Map(metadata);
2799
+ const current = updated.get(channel) || { count: 0, lastMessage: null, lastUpdated: 0 };
2800
+ updated.set(channel, {
2801
+ ...current,
2802
+ count: current.count + 1,
2803
+ lastMessage: message,
2804
+ lastUpdated: Date.now()
2805
+ });
2806
+ return updated;
2807
+ });
2808
+ }
2809
+ updateUserPresence(channel, user) {
2810
+ this.usersInChannelsSignal.update(users => {
2811
+ const updated = new Map(users);
2812
+ const channelUsers = new Set(updated.get(channel) || []);
2813
+ channelUsers.add(user);
2814
+ updated.set(channel, channelUsers);
2815
+ return updated;
2816
+ });
2817
+ }
2818
+ removeUserFromChannel(channel, user) {
2819
+ this.usersInChannelsSignal.update(users => {
2820
+ const updated = new Map(users);
2821
+ const channelUsers = updated.get(channel);
2822
+ if (channelUsers) {
2823
+ channelUsers.delete(user);
2824
+ updated.set(channel, channelUsers);
2825
+ }
2826
+ return updated;
2827
+ });
2828
+ }
2829
+ subscribeToChannel(channel) {
2830
+ this.wsManager.subscribeToChannel(channel);
2831
+ }
2832
+ unsubscribeFromChannel(channel) {
2833
+ this.wsManager.unsubscribeFromChannel(channel);
2834
+ this.removeUserFromChannel(channel, 'current-user');
2835
+ }
2836
+ // Selectors
2837
+ getMessageCount(channel) {
2838
+ const metadata = this.channelMetadataSignal();
2839
+ return metadata.get(channel)?.count || 0;
2840
+ }
2841
+ getLastMessage(channel) {
2842
+ const metadata = this.channelMetadataSignal();
2843
+ return metadata.get(channel)?.lastMessage || null;
2844
+ }
2845
+ getActiveChannels() {
2846
+ return Array.from(this.channelMetadataSignal().keys());
2847
+ }
2848
+ getUsersInChannel(channel) {
2849
+ const users = this.usersInChannelsSignal().get(channel);
2850
+ return users ? Array.from(users) : [];
2851
+ }
2852
+ onDisconnect() {
2853
+ this.messagesSignal.set(null);
2854
+ this.channelMetadataSignal.set(new Map());
2855
+ this.usersInChannelsSignal.set(new Map());
2856
+ }
2857
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChannelPresenceSignalsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2858
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChannelPresenceSignalsService, providedIn: 'root' }); }
2859
+ }
2860
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChannelPresenceSignalsService, decorators: [{
2861
+ type: Injectable,
2862
+ args: [{
2863
+ providedIn: 'root',
2864
+ }]
2865
+ }], ctorParameters: () => [] });
2866
+
2867
+ /**
2868
+ * @deprecated Use `ChannelPresenceSignalsService` instead.
2869
+ * This file is kept for backwards compatibility only.
2870
+ */
2734
2871
  /**
2735
2872
  * MessageTrackerSignalsService - Signal-based message tracking
2736
2873
  *
2737
2874
  * Tracks WebSocket messages, channel metadata, and user presence using signals.
2738
2875
  * Provides real-time reactivity for message-driven applications.
2739
2876
  */
2877
+ /**
2878
+ * @deprecated Use `ChannelPresenceSignalsService` from `channel-presence-signals.service.ts` instead.
2879
+ */
2740
2880
  class MessageTrackerSignalsService {
2741
2881
  constructor() {
2742
2882
  this.wsManager = inject(WebSocketSignalsManagerService);
@@ -4301,6 +4441,7 @@ class RequestSignalsService extends WebsocketService {
4301
4441
  this.headersService = inject(HeadersService);
4302
4442
  this.isPending = signal(false);
4303
4443
  this.progress = signal(0);
4444
+ this.streamProgress = signal(new StreamProgressModel());
4304
4445
  this.isIdle = computed(() => !this.isPending());
4305
4446
  }
4306
4447
  // Implementation
@@ -4314,7 +4455,7 @@ class RequestSignalsService extends WebsocketService {
4314
4455
  observe: 'events',
4315
4456
  responseType: 'text',
4316
4457
  reportProgress: true
4317
- }).pipe(requestStreaming(StreamConfigModel.adapt({ streamType: options.streamType || StreamType.AI_STREAMING })), this.requestStreamingOperator(options), this.handleFinalize())
4458
+ }).pipe(requestStreaming(StreamConfigModel.adapt({ streamType: options.streamType || StreamType.NDJSON, totalHeader: 'X-Total-Count' })), this.requestStreamingOperator(options), this.handleFinalize())
4318
4459
  : this.http.get(urlPath, headers).pipe(this.request(options), this.handleFinalize());
4319
4460
  }
4320
4461
  // Implementation
@@ -4328,7 +4469,7 @@ class RequestSignalsService extends WebsocketService {
4328
4469
  observe: 'events',
4329
4470
  responseType: 'text',
4330
4471
  reportProgress: true
4331
- }).pipe(requestStreaming(StreamConfigModel.adapt({ streamType: options.streamType || StreamType.AI_STREAMING })), this.requestStreamingOperator(options), this.handleFinalize())
4472
+ }).pipe(requestStreaming(StreamConfigModel.adapt({ streamType: options.streamType || StreamType.NDJSON, totalHeader: 'X-Total-Count' })), this.requestStreamingOperator(options), this.handleFinalize())
4332
4473
  : this.http.post(urlPath, data, headers).pipe(this.request(options), this.handleFinalize());
4333
4474
  }
4334
4475
  updateRecordRequest(options, data) {
@@ -4372,6 +4513,7 @@ class RequestSignalsService extends WebsocketService {
4372
4513
  return (source$) => {
4373
4514
  return source$.pipe(tap(output => {
4374
4515
  this.progress.set(output.progress.received);
4516
+ this.streamProgress.set({ ...output.progress, stage: 'streaming' });
4375
4517
  }), map(output => {
4376
4518
  const data = output.data;
4377
4519
  if (!data || (Array.isArray(data) && data.length === 0)) {
@@ -4381,6 +4523,9 @@ class RequestSignalsService extends WebsocketService {
4381
4523
  return data.map((item) => options.adapter(item));
4382
4524
  }
4383
4525
  return data;
4526
+ }), finalize(() => this.streamProgress.update(p => ({ ...p, stage: 'complete' }))), catchError(err => {
4527
+ this.streamProgress.update(p => ({ ...p, stage: 'error' }));
4528
+ return throwError(() => err);
4384
4529
  }));
4385
4530
  };
4386
4531
  }
@@ -4404,9 +4549,10 @@ class RequestSignalsService extends WebsocketService {
4404
4549
  case HttpEventType.Response:
4405
4550
  try {
4406
4551
  const fileNamePath = (options?.saveAs) ? options.saveAs : (options.path) ? options.path[options.path.length - 1] : [];
4407
- const header_content = event.headers.get('Content-Disposition') || '';
4552
+ const fileContentHeader = options.fileContentHeader || 'Content-Disposition';
4553
+ const header_content = event.headers.get(fileContentHeader) || '';
4408
4554
  const file = (header_content) ? header_content.split('=')[1].substring(0, header_content.split('=')[1].length) : '';
4409
- const fileName = (fileNamePath !== '') ? fileNamePath : file;
4555
+ const fileName = file ? file : fileNamePath;
4410
4556
  if (fileName === '') {
4411
4557
  this.isPending.set(false);
4412
4558
  throw new Error('Save File: (file name and extension) not found in Headers or Path');
@@ -4588,6 +4734,10 @@ class HTTPManagerSignalsService extends RequestSignalsService {
4588
4734
  this.countdown = signal(0);
4589
4735
  this.error = signal(false);
4590
4736
  this.data = signal(null);
4737
+ this.isConnecting = toSignal(this.wsManager.isConnecting$, { initialValue: false });
4738
+ this.retryCount = toSignal(this.wsManager.retryCount$, { initialValue: 0 });
4739
+ this.maxRetries = toSignal(this.wsManager.maxRetries$, { initialValue: 0 });
4740
+ this.connectionError = toSignal(this.wsManager.connectionError$, { initialValue: null });
4591
4741
  this.polling$ = new Subject();
4592
4742
  this.config = ApiRequest.adapt();
4593
4743
  this.config = configOptions
@@ -4727,6 +4877,7 @@ class HTTPManagerSignalsService extends RequestSignalsService {
4727
4877
  getRequest(options, params) {
4728
4878
  this.isPending.set(true);
4729
4879
  this.data.set(null);
4880
+ this.streamProgress.set(new StreamProgressModel());
4730
4881
  const updatedOptions = this.defineReqOptions(options, params);
4731
4882
  const func = this.getRecordRequest;
4732
4883
  const requests = this.createRequest(func, updatedOptions);
@@ -4798,6 +4949,7 @@ class HTTPManagerSignalsService extends RequestSignalsService {
4798
4949
  }
4799
4950
  downloadRequest(options, params, saveAs) {
4800
4951
  this.isPending.set(true);
4952
+ this.streamProgress.set(new StreamProgressModel());
4801
4953
  const updatedOptions = this.defineReqOptions(options, params);
4802
4954
  const func = this.downloadFileRequest;
4803
4955
  const requests = this.createRequest(func, updatedOptions);
@@ -4891,7 +5043,7 @@ class HTTPManagerSignalsService extends RequestSignalsService {
4891
5043
  return { options: options, data: data };
4892
5044
  }
4893
5045
  handleError(error) {
4894
- this.error.set(error.message || `${error.status} - ${error.statusText}`);
5046
+ this.error.set(true);
4895
5047
  return throwError(() => error);
4896
5048
  }
4897
5049
  handleErrorWithSnackBar(error, message) {
@@ -5536,6 +5688,18 @@ class LocalStorageManagerService extends ComponentStore {
5536
5688
  }
5537
5689
  }
5538
5690
  settings.forEach(store => {
5691
+ // normalize expiresIn → expires so TTL is always a numeric timestamp
5692
+ if ((!store.options?.expires || store.options.expires === 0) && store.options?.expiresIn) {
5693
+ try {
5694
+ const computed = this.utils.expires(store.options.expiresIn);
5695
+ if (store.options)
5696
+ store.options.expires = computed || 0;
5697
+ }
5698
+ catch {
5699
+ if (store.options)
5700
+ store.options.expires = 0;
5701
+ }
5702
+ }
5539
5703
  const expired = (store.options?.expires || 0) > 0 && this.utils.hasExpired(store.options?.expires || 0);
5540
5704
  if (!expired) {
5541
5705
  const hasStorage = this.hasGlobalStorage(store.options?.storage, store.id || '');
@@ -5708,7 +5872,7 @@ class LocalStorageSignalsManagerService {
5708
5872
  this.storeExists = (store) => computed(() => !!this.state().settings.find(item => item.name === store));
5709
5873
  this.store = (store) => computed(() => {
5710
5874
  const data = this.state();
5711
- const foundStore = data.settings.find(item => item.name === store);
5875
+ const foundStore = [...data.settings].reverse().find(item => item.name === store);
5712
5876
  if (!foundStore)
5713
5877
  return null;
5714
5878
  const options = SettingOptions.adapt(foundStore.options);
@@ -5782,6 +5946,9 @@ class LocalStorageSignalsManagerService {
5782
5946
  const settings = StorageOption.adapt(store);
5783
5947
  settings.options = this.objectMergerService.mergeStorageOptions(settings.options);
5784
5948
  store.name = this.validStoreName(store.name);
5949
+ if (!this.hasGlobalStorage(store.options?.storage, store.id)) {
5950
+ return state;
5951
+ }
5785
5952
  const str = this.encryptionTest.isEncrypted(store.data) ? store.data : JSON.stringify(store.data);
5786
5953
  const dataStr = this.isObjectOrArray(str) && store.options.encrypted
5787
5954
  ? this.encryption.encrypt(str, this.app.appID)
@@ -6514,6 +6681,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
6514
6681
  }]
6515
6682
  }], ctorParameters: () => [] });
6516
6683
 
6684
+ class DatabaseManagerSignalsService {
6685
+ constructor() {
6686
+ this.dbManager = inject(DatabaseManagerService);
6687
+ this.isPendingSignal = signal(false);
6688
+ this.tablesSignal = signal([]);
6689
+ this.databaseReadySignal = signal(false);
6690
+ this.isPending = this.isPendingSignal.asReadonly();
6691
+ this.tables = this.tablesSignal.asReadonly();
6692
+ this.databaseReady = this.databaseReadySignal.asReadonly();
6693
+ }
6694
+ getDatabaseTables() {
6695
+ this.isPendingSignal.set(true);
6696
+ return this.dbManager.getDatabaseTables().pipe(tap((t) => this.tablesSignal.set(t)), finalize(() => this.isPendingSignal.set(false)));
6697
+ }
6698
+ databaseExists() {
6699
+ this.isPendingSignal.set(true);
6700
+ return this.dbManager.databaseExists().pipe(tap((exists) => this.databaseReadySignal.set(exists)), finalize(() => this.isPendingSignal.set(false)));
6701
+ }
6702
+ hasDatabaseTable(table) {
6703
+ this.isPendingSignal.set(true);
6704
+ return this.dbManager.hasDatabaseTable(table).pipe(finalize(() => this.isPendingSignal.set(false)));
6705
+ }
6706
+ getDatabaseTable(table) {
6707
+ this.isPendingSignal.set(true);
6708
+ return this.dbManager.getDatabaseTable(table).pipe(finalize(() => this.isPendingSignal.set(false)));
6709
+ }
6710
+ getDatabaseTableSchema(table) {
6711
+ this.isPendingSignal.set(true);
6712
+ return this.dbManager.getDatabaseTableSchema(table).pipe(finalize(() => this.isPendingSignal.set(false)));
6713
+ }
6714
+ createDatabaseTable(tableDef) {
6715
+ this.isPendingSignal.set(true);
6716
+ return this.dbManager.createDatabaseTable(tableDef).pipe(tap(() => this.getDatabaseTables().subscribe()), finalize(() => this.isPendingSignal.set(false)));
6717
+ }
6718
+ updateDatabaseTableSchema(tableDef) {
6719
+ this.isPendingSignal.set(true);
6720
+ return this.dbManager.updateDatabaseTableSchema(tableDef).pipe(finalize(() => this.isPendingSignal.set(false)));
6721
+ }
6722
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatabaseManagerSignalsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
6723
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatabaseManagerSignalsService, providedIn: 'root' }); }
6724
+ }
6725
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatabaseManagerSignalsService, decorators: [{
6726
+ type: Injectable,
6727
+ args: [{
6728
+ providedIn: 'root'
6729
+ }]
6730
+ }] });
6731
+
6517
6732
  class ChannelMessage {
6518
6733
  constructor(messageId, channel, isReplay, sessionId = null, content = null, timestamp) {
6519
6734
  this.messageId = messageId;
@@ -7363,7 +7578,7 @@ class HTTPManagerStateService extends ComponentStore {
7363
7578
  Object.keys(currentStateData).length > 0) {
7364
7579
  return of({ data: currentStateData, fromCache: true });
7365
7580
  }
7366
- return of({ data: this.dataType === DataType.ARRAY ? [] : {}, fromCache: true });
7581
+ return fetchStreamFromAPI();
7367
7582
  }));
7368
7583
  }
7369
7584
  return fetchStreamFromAPI();
@@ -8036,6 +8251,7 @@ class HTTPManagerStateService extends ComponentStore {
8036
8251
  data: { ...this.databaseOptions, expires: 0 }
8037
8252
  });
8038
8253
  this._requestCachePaths.delete(tableName);
8254
+ this.clearRequestCacheMetadata(tableName);
8039
8255
  this.dbManagerService.clearTable(tableName).subscribe({
8040
8256
  next: () => {
8041
8257
  if (this.dataType === DataType.ARRAY) {
@@ -8188,6 +8404,7 @@ class HTTPManagerStateService extends ComponentStore {
8188
8404
  const currentCache = storeData?.requestCache || {};
8189
8405
  const currentEntry = currentCache[type] || {};
8190
8406
  const currentQueryParams = { ...(currentEntry.queryParams || {}) };
8407
+ const currentQueryCombinations = [...(currentEntry.queryCombinations || [])];
8191
8408
  const currentQueryParamsExpires = currentEntry.queryParamsExpires ?? null;
8192
8409
  this.localStorageManagerService.updateStore({
8193
8410
  name: tableName,
@@ -8201,6 +8418,7 @@ class HTTPManagerStateService extends ComponentStore {
8201
8418
  savedAt: Date.now(),
8202
8419
  path: this.resolvePath(options?.path),
8203
8420
  headers: this.filterHeaders(options?.headers),
8421
+ queryCombinations: currentQueryCombinations,
8204
8422
  queryParams: currentQueryParams,
8205
8423
  queryParamsExpires: currentQueryParamsExpires,
8206
8424
  }
@@ -8252,10 +8470,13 @@ class HTTPManagerStateService extends ComponentStore {
8252
8470
  });
8253
8471
  }
8254
8472
  });
8473
+ const sortedKeys = Object.keys(query).sort();
8474
+ const queryString = sortedKeys.map((k) => `${k}=${query[k]}`).join('&');
8255
8475
  return {
8256
8476
  pathKey: this.trackerNormalizePathSegments(pathSegments),
8257
8477
  query,
8258
- hasQuery: Object.keys(query).length > 0,
8478
+ queryString,
8479
+ hasQuery: sortedKeys.length > 0,
8259
8480
  };
8260
8481
  }
8261
8482
  trackerParsePathSegment(rawSegment) {
@@ -8352,27 +8573,57 @@ class HTTPManagerStateService extends ComponentStore {
8352
8573
  }
8353
8574
  const meta = this.getRequestCacheMetadata(storeData, type) || {};
8354
8575
  const now = Math.floor(Date.now() / 1000);
8355
- let queryParams = { ...(meta.queryParams || {}) };
8576
+ // Build the combination string from the filtered query (deterministic because keys are sorted)
8577
+ const combinationString = keys.sort().map((k) => `${k}=${filtered[k]}`).join('&');
8578
+ // Legacy per-key queryParams for backward compatibility (read-only)
8579
+ const queryParams = { ...(meta.queryParams || {}) };
8356
8580
  let queryParamsExpires = meta.queryParamsExpires ?? null;
8357
- // Reset queryParams if the request path has changed (different endpoint)
8358
- const storedPathKey = meta.path ? this.trackerNormalizePathSegments(meta.path.filter((p) => typeof p === 'string' || typeof p === 'number').map(String)) : null;
8581
+ // New combination-based tracking
8582
+ let queryCombinations = [...(meta.queryCombinations || [])];
8583
+ // Reset combinations if the request path has changed (different endpoint)
8584
+ // Use trackerNormalizePath so inline query strings (e.g. 'items?a=1') are stripped
8585
+ // before comparing, matching the same normalization applied to the current request.
8586
+ const storedPathKey = meta.path
8587
+ ? this.trackerNormalizePath(meta.path.filter((p) => typeof p === 'string' || typeof p === 'number').map(String)).pathKey
8588
+ : null;
8359
8589
  if (storedPathKey && storedPathKey !== normalized.pathKey) {
8360
- queryParams = {};
8590
+ queryCombinations = [];
8591
+ // Also clear legacy per-key tracking so old data from a different path doesn't block
8592
+ Object.keys(queryParams).forEach((k) => delete queryParams[k]);
8361
8593
  queryParamsExpires = null;
8362
8594
  }
8363
8595
  if (queryParamsExpires !== null && queryParamsExpires <= now) {
8364
- queryParams = {};
8596
+ queryCombinations = [];
8365
8597
  queryParamsExpires = null;
8598
+ Object.keys(queryParams).forEach((k) => delete queryParams[k]);
8599
+ }
8600
+ // Determine if request is accepted (not yet tracked)
8601
+ // Use combination-based tracking when available; fall back to legacy per-key tracking
8602
+ let accepted;
8603
+ if (queryCombinations.length > 0) {
8604
+ accepted = !queryCombinations.includes(combinationString);
8605
+ }
8606
+ else if (Object.keys(queryParams).length > 0) {
8607
+ // Legacy per-key backward compatibility
8608
+ accepted = !keys.every((key) => {
8609
+ const consumed = queryParams[key] || [];
8610
+ return consumed.includes(filtered[key]);
8611
+ });
8612
+ }
8613
+ else {
8614
+ accepted = true;
8615
+ }
8616
+ if (accepted) {
8617
+ queryCombinations = [...queryCombinations, combinationString];
8618
+ // Also update legacy queryParams so existing consumers still work
8619
+ keys.forEach(key => {
8620
+ const value = filtered[key];
8621
+ const consumed = queryParams[key] || [];
8622
+ if (!consumed.includes(value)) {
8623
+ queryParams[key] = [...consumed, value];
8624
+ }
8625
+ });
8366
8626
  }
8367
- let accepted = false;
8368
- keys.forEach(key => {
8369
- const value = filtered[key];
8370
- const consumed = queryParams[key] || [];
8371
- if (!consumed.includes(value)) {
8372
- queryParams[key] = [...consumed, value];
8373
- accepted = true;
8374
- }
8375
- });
8376
8627
  const newExpiry = this.trackerBuildExpiryEpoch(options?.queryParamsExpiresIn);
8377
8628
  if (newExpiry !== null) {
8378
8629
  queryParamsExpires = newExpiry;
@@ -8389,6 +8640,7 @@ class HTTPManagerStateService extends ComponentStore {
8389
8640
  ...currentCache,
8390
8641
  [type]: {
8391
8642
  ...currentEntry,
8643
+ queryCombinations,
8392
8644
  queryParams,
8393
8645
  queryParamsExpires,
8394
8646
  }
@@ -8412,6 +8664,214 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
8412
8664
  args: ["dataType"]
8413
8665
  }] }, { type: DatabaseStorage }] });
8414
8666
 
8667
+ class HTTPManagerStateSignalsService {
8668
+ constructor() {
8669
+ // --- Injected services ---
8670
+ this.httpManagerSignalsService = inject(HTTPManagerSignalsService);
8671
+ this.databaseManagerSignalsService = inject(DatabaseManagerSignalsService);
8672
+ this.localStorageSignalsManagerService = inject(LocalStorageSignalsManagerService);
8673
+ this.utils = inject(UtilsService);
8674
+ this.logger = inject(LoggerService);
8675
+ this.destroyRef = inject(DestroyRef);
8676
+ this.injector = inject(Injector);
8677
+ // --- Own state signals (private writable, public readonly) ---
8678
+ this.dataSignal = signal([]);
8679
+ this.dataObjectSignal = signal(null);
8680
+ this.operationSuccessSignal = signal(null);
8681
+ this.pageSignal = signal(0);
8682
+ this.totalPagesSignal = signal(0);
8683
+ this.percentageSignal = signal(0);
8684
+ this.streamedResponseSignal = signal([]);
8685
+ this.messagesSignal = signal([]);
8686
+ // --- Public readonly state ---
8687
+ this.data = this.dataSignal.asReadonly();
8688
+ this.dataObject = this.dataObjectSignal.asReadonly();
8689
+ this.operationSuccess = this.operationSuccessSignal.asReadonly();
8690
+ this.page = this.pageSignal.asReadonly();
8691
+ this.totalPages = this.totalPagesSignal.asReadonly();
8692
+ this.percentage = this.percentageSignal.asReadonly();
8693
+ this.streamedResponse = this.streamedResponseSignal.asReadonly();
8694
+ this.messages = this.messagesSignal.asReadonly();
8695
+ // --- Delegated signals from HTTPManagerSignalsService ---
8696
+ this.error = this.httpManagerSignalsService.error;
8697
+ this.isPending = this.httpManagerSignalsService.isPending;
8698
+ this.isConnecting = this.httpManagerSignalsService.isConnecting;
8699
+ this.retryCount = this.httpManagerSignalsService.retryCount;
8700
+ this.maxRetries = this.httpManagerSignalsService.maxRetries;
8701
+ this.connectionError = this.httpManagerSignalsService.connectionError;
8702
+ // Accumulate WS messages via effect instead of scan() operators
8703
+ effect(() => {
8704
+ const msg = this.httpManagerSignalsService.data();
8705
+ if (msg !== null && msg !== undefined) {
8706
+ this.messagesSignal.update(msgs => [...msgs, msg]);
8707
+ }
8708
+ }, { injector: this.injector });
8709
+ }
8710
+ // --- State setters ---
8711
+ setData(items) {
8712
+ this.dataSignal.set(items);
8713
+ }
8714
+ setDataObject(item) {
8715
+ this.dataObjectSignal.set(item);
8716
+ }
8717
+ setOperationSuccess(result) {
8718
+ this.operationSuccessSignal.set(result);
8719
+ }
8720
+ setPage(n) {
8721
+ this.pageSignal.set(n);
8722
+ }
8723
+ setTotalPages(n) {
8724
+ this.totalPagesSignal.set(n);
8725
+ }
8726
+ setPercentage(n) {
8727
+ this.percentageSignal.set(n);
8728
+ }
8729
+ appendStreamedItem(item) {
8730
+ this.streamedResponseSignal.update(items => [...items, item]);
8731
+ }
8732
+ clearStreamedResponse() {
8733
+ this.streamedResponseSignal.set([]);
8734
+ }
8735
+ clearMessages() {
8736
+ this.messagesSignal.set([]);
8737
+ }
8738
+ // --- HTTP methods delegated to HTTPManagerSignalsService ---
8739
+ getRequest(options, params) {
8740
+ return this.httpManagerSignalsService.getRequest(options, params);
8741
+ }
8742
+ postRequest(data, options, params) {
8743
+ return this.httpManagerSignalsService.postRequest(data, options, params);
8744
+ }
8745
+ putRequest(data, options, params) {
8746
+ return this.httpManagerSignalsService.putRequest(data, options, params);
8747
+ }
8748
+ deleteRequest(options, params) {
8749
+ return this.httpManagerSignalsService.deleteRequest(options, params);
8750
+ }
8751
+ downloadRequest(options, params, saveAs) {
8752
+ return this.httpManagerSignalsService.downloadRequest(options, params, saveAs);
8753
+ }
8754
+ uploadRequest(files, options, params) {
8755
+ return this.httpManagerSignalsService.uploadRequest(files, options, params);
8756
+ }
8757
+ getBatchRequests(requests, options) {
8758
+ return this.httpManagerSignalsService.getBatchRequests(requests, options);
8759
+ }
8760
+ getSequentialRequest(requests, options) {
8761
+ return this.httpManagerSignalsService.getSequentialRequest(requests, options);
8762
+ }
8763
+ getParallelRequest(requests, options) {
8764
+ return this.httpManagerSignalsService.getParallelRequest(requests, options);
8765
+ }
8766
+ // --- WS control methods delegated to HTTPManagerSignalsService ---
8767
+ connect(options, jwtToken) {
8768
+ this.httpManagerSignalsService.connect(options, jwtToken);
8769
+ }
8770
+ disconnect() {
8771
+ this.httpManagerSignalsService.disconnect();
8772
+ }
8773
+ subscribeToChannel(channel, userData) {
8774
+ this.httpManagerSignalsService.subscribeToChannel(channel, userData);
8775
+ }
8776
+ subscribeToChannels(channels, userData) {
8777
+ this.httpManagerSignalsService.subscribeToChannels(channels, userData);
8778
+ }
8779
+ unsubscribeFromChannel(channel) {
8780
+ this.httpManagerSignalsService.unsubscribeFromChannel(channel);
8781
+ }
8782
+ getSubscribedChannels() {
8783
+ return this.httpManagerSignalsService.getSubscribedChannels();
8784
+ }
8785
+ sendBroadcast(content) {
8786
+ this.httpManagerSignalsService.sendBroadcast(content);
8787
+ }
8788
+ sendMessageInChannel(channel, content) {
8789
+ this.httpManagerSignalsService.sendMessageInChannel(channel, content);
8790
+ }
8791
+ sendChannelMessage(channel, content) {
8792
+ this.httpManagerSignalsService.sendChannelMessage(channel, content);
8793
+ }
8794
+ sendChannelMessageToChannels(channels, content) {
8795
+ this.httpManagerSignalsService.sendChannelMessageToChannels(channels, content);
8796
+ }
8797
+ sendMessageToUser(user, content) {
8798
+ this.httpManagerSignalsService.sendMessageToUser(user, content);
8799
+ }
8800
+ getAllChannels() {
8801
+ this.httpManagerSignalsService.getAllChannels();
8802
+ }
8803
+ createChannel(channel) {
8804
+ this.httpManagerSignalsService.createChannel(channel);
8805
+ }
8806
+ deleteChannel(channel) {
8807
+ this.httpManagerSignalsService.deleteChannel(channel);
8808
+ }
8809
+ getUsersInChannel(channel) {
8810
+ this.httpManagerSignalsService.getUsersInChannel(channel);
8811
+ }
8812
+ createNotificationChannel(channel) {
8813
+ this.httpManagerSignalsService.createNotificationChannel(channel);
8814
+ }
8815
+ getNotificationChannels() {
8816
+ this.httpManagerSignalsService.getNotificationChannels();
8817
+ }
8818
+ getTodaysNotificationChannels() {
8819
+ this.httpManagerSignalsService.getTodaysNotificationChannels();
8820
+ }
8821
+ subscribeToNotificationChannel(channel, options, user) {
8822
+ this.httpManagerSignalsService.subscribeToNotificationChannel(channel, options, user);
8823
+ }
8824
+ unsubscribeFromNotificationChannel(channel) {
8825
+ this.httpManagerSignalsService.unsubscribeFromNotificationChannel(channel);
8826
+ }
8827
+ sendNotification(channel, content) {
8828
+ this.httpManagerSignalsService.sendNotification(channel, content);
8829
+ }
8830
+ // --- DB methods delegated to DatabaseManagerSignalsService ---
8831
+ getDatabaseTables() {
8832
+ return this.databaseManagerSignalsService.getDatabaseTables();
8833
+ }
8834
+ databaseExists() {
8835
+ return this.databaseManagerSignalsService.databaseExists();
8836
+ }
8837
+ hasDatabaseTable(table) {
8838
+ return this.databaseManagerSignalsService.hasDatabaseTable(table);
8839
+ }
8840
+ getDatabaseTable(table) {
8841
+ return this.databaseManagerSignalsService.getDatabaseTable(table);
8842
+ }
8843
+ getDatabaseTableSchema(table) {
8844
+ return this.databaseManagerSignalsService.getDatabaseTableSchema(table);
8845
+ }
8846
+ createDatabaseTable(tableDef) {
8847
+ return this.databaseManagerSignalsService.createDatabaseTable(tableDef);
8848
+ }
8849
+ updateDatabaseTableSchema(tableDef) {
8850
+ return this.databaseManagerSignalsService.updateDatabaseTableSchema(tableDef);
8851
+ }
8852
+ // --- localStorage methods delegated to LocalStorageSignalsManagerService ---
8853
+ createStore(store) {
8854
+ this.localStorageSignalsManagerService.createStore(store);
8855
+ }
8856
+ setStore(store) {
8857
+ this.localStorageSignalsManagerService.setStore(store);
8858
+ }
8859
+ updateStore(store) {
8860
+ this.localStorageSignalsManagerService.updateStore(store);
8861
+ }
8862
+ deleteStore(store) {
8863
+ this.localStorageSignalsManagerService.deleteStore(store);
8864
+ }
8865
+ getStore(storeName) {
8866
+ return this.localStorageSignalsManagerService.store(storeName);
8867
+ }
8868
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HTTPManagerStateSignalsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
8869
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HTTPManagerStateSignalsService }); }
8870
+ }
8871
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HTTPManagerStateSignalsService, decorators: [{
8872
+ type: Injectable
8873
+ }], ctorParameters: () => [] });
8874
+
8415
8875
  class StateStorageOptions {
8416
8876
  constructor(store, options, model) {
8417
8877
  this.store = store;
@@ -8567,6 +9027,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
8567
9027
  class StoreStateManagerSignalsService {
8568
9028
  constructor() {
8569
9029
  this.localStorageManagerService = inject(LocalStorageSignalsManagerService);
9030
+ this.injector = inject(Injector);
8570
9031
  this.state = signal(null);
8571
9032
  this.isRestoring = false;
8572
9033
  this.settings = null;
@@ -8583,6 +9044,8 @@ class StoreStateManagerSignalsService {
8583
9044
  });
8584
9045
  }
8585
9046
  init(options) {
9047
+ if (this.settings !== null)
9048
+ return;
8586
9049
  this.settings = options;
8587
9050
  const storeName = options.store ?? 'temp';
8588
9051
  // Create store in localStorage
@@ -8600,7 +9063,7 @@ class StoreStateManagerSignalsService {
8600
9063
  if (storeData && !this.isRestoring) {
8601
9064
  this.state.set(storeData);
8602
9065
  }
8603
- });
9066
+ }, { injector: this.injector });
8604
9067
  }
8605
9068
  restoreState() {
8606
9069
  if (!this.settings)
@@ -13772,5 +14235,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
13772
14235
  * Generated bundle index. Do not edit.
13773
14236
  */
13774
14237
 
13775
- export { ApiRequest, AppService, AsymmetricalEncryptionService, BatchOptions, BatchResult, CONFIG_SETTINGS_TOKEN, ChannelType, ConfigHTTPOptions, ConfigOptions, DataType, DatabaseDataDemoComponent, DatabaseManagerService, DatabaseStorage, DbService, DexieSqlService, ErrorDisplaySettings, ExecutionPlanType, GlobalStoreOptions, HTTPManagerService, HTTPManagerSignalsService, HTTPManagerStateService, HeadersService, HttpRequestManagerModule, HttpRequestServicesDemoComponent, InvalidFileInfoModel, LocalStorageDemoComponent, LocalStorageManagerService, LocalStorageOptions, LocalStorageSignalsDemoComponent, LocalStorageSignalsManagerService, LoggerService, NotificationMessage, OperationResultModel, ParsingResultModel, PathQueryService, PublicMessage, Random, RandomHSLColor, RandomHexColor, RandomNumber, RandomNumbers, RandomNumbersUnique, RandomPaletteColor, RandomSignature, RandomStr, RandomVisibleColor, RequestErrorInterceptor, RequestHeadersInterceptor, RequestManagerDemoComponent, RequestManagerStateDemoComponent, RequestOptions, RequestService, RequestSignalsService, RetryOptions, SettingOptions, SqlParseError, SqlValidationError, StateMessage, StateOperationResult, StateStorageOptions, StorageData, StorageOption, StorageType, StoreStateManagerService, StoreStateManagerSignalsService, StoreStateSignalsDemoComponent, StreamConfigModel, StreamEventMetadataModel, StreamEventModel, StreamOutputModel, StreamProgressModel, StreamType, SymmetricalEncryptionService, TableSchemaDef, UUID, UUID_STR, UploadDemoComponent, UploadValidationErrorModel, UserData, UtilsService, WSOptions, WebSocketMessageService, WithCredentialsInterceptor, calculateBatchProgress, countdown, createChannelName, delayedRetry, isErrorState, isPendingState, isSuccessState, requestPolling, requestStreaming, streamAI, streamAuto, streamEvents, streamJSON, streamNDJSON };
14238
+ export { ApiRequest, AppService, AsymmetricalEncryptionService, BatchOptions, BatchResult, CONFIG_SETTINGS_TOKEN, ChannelType, ConfigHTTPOptions, ConfigOptions, DataType, DatabaseDataDemoComponent, DatabaseManagerService, DatabaseManagerSignalsService, DatabaseStorage, DbService, DexieSqlService, ErrorDisplaySettings, ExecutionPlanType, GlobalStoreOptions, HTTPManagerService, HTTPManagerSignalsService, HTTPManagerStateService, HTTPManagerStateSignalsService, HeadersService, HttpRequestManagerModule, HttpRequestServicesDemoComponent, InvalidFileInfoModel, LocalStorageDemoComponent, LocalStorageManagerService, LocalStorageOptions, LocalStorageSignalsDemoComponent, LocalStorageSignalsManagerService, LoggerService, NotificationMessage, OperationResultModel, ParsingResultModel, PathQueryService, PublicMessage, Random, RandomHSLColor, RandomHexColor, RandomNumber, RandomNumbers, RandomNumbersUnique, RandomPaletteColor, RandomSignature, RandomStr, RandomVisibleColor, RequestErrorInterceptor, RequestHeadersInterceptor, RequestManagerDemoComponent, RequestManagerStateDemoComponent, RequestOptions, RequestService, RequestSignalsService, RetryOptions, SettingOptions, SqlParseError, SqlValidationError, StateMessage, StateOperationResult, StateStorageOptions, StorageData, StorageOption, StorageType, StoreStateManagerService, StoreStateManagerSignalsService, StoreStateSignalsDemoComponent, StreamConfigModel, StreamEventMetadataModel, StreamEventModel, StreamOutputModel, StreamProgressModel, StreamType, SymmetricalEncryptionService, TableSchemaDef, UUID, UUID_STR, UploadDemoComponent, UploadValidationErrorModel, UserData, UtilsService, WSOptions, WebSocketMessageService, WithCredentialsInterceptor, calculateBatchProgress, countdown, createChannelName, delayedRetry, isErrorState, isPendingState, isSuccessState, requestPolling, requestStreaming, streamAI, streamAuto, streamEvents, streamJSON, streamNDJSON };
13776
14239
  //# sourceMappingURL=http-request-manager.mjs.map