@ethlete/query 5.24.0 → 5.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import * as i1 from '@ethlete/core';
2
- import { createDestroy, computedTillTruthy, syncSignal, getCookie, setCookie, deleteCookie, DelayableDirective, nextFrame, RuntimeError, isObject, getDomain, previousSignalValue, injectQueryParamChanges, injectQueryParams, clone, equal, ET_PROPERTY_REMOVED } from '@ethlete/core';
3
- import { Observable, takeUntil, startWith, pairwise, tap, switchMap, of, BehaviorSubject, Subject, fromEvent, timer, take, filter, takeWhile, map, ReplaySubject, shareReplay, combineLatest, interval, skip, withLatestFrom, debounceTime, Subscription, retry, throwError, catchError, merge } from 'rxjs';
2
+ import { createDestroy, computedTillTruthy, syncSignal, getCookie, setCookie, deleteCookie, DelayableDirective, nextFrame, RuntimeError, isObject, injectRoute, getDomain, previousSignalValue, injectQueryParamChanges, injectQueryParams, clone, equal, ET_PROPERTY_REMOVED } from '@ethlete/core';
3
+ import { Observable, takeUntil, startWith, pairwise, tap, switchMap, of, BehaviorSubject, Subject, fromEvent, timer, take, filter, takeWhile, map, shareReplay, ReplaySubject, combineLatest, interval, skip, withLatestFrom, debounceTime, Subscription, retry, throwError, catchError, merge } from 'rxjs';
4
4
  import * as i0 from '@angular/core';
5
5
  import { assertInInjectionContext, inject, Injector, computed, signal, isDevMode, untracked, TemplateRef, ViewContainerRef, ErrorHandler, ChangeDetectorRef, Directive, Input, InjectionToken, ElementRef, Pipe, effect, Component, ChangeDetectionStrategy, ViewEncapsulation, runInInjectionContext, EnvironmentInjector, createEnvironmentInjector, DestroyRef, NgZone } from '@angular/core';
6
6
  import { toSignal, toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
@@ -13,7 +13,6 @@ import { io } from 'socket.io-client';
13
13
  import { Router, ActivatedRoute } from '@angular/router';
14
14
 
15
15
  class CustomHeaderAuthProvider {
16
- _config;
17
16
  get header() {
18
17
  return { [this._config.name]: this._config.value };
19
18
  }
@@ -26,7 +25,6 @@ class CustomHeaderAuthProvider {
26
25
  }
27
26
 
28
27
  class BasicAuthProvider {
29
- _config;
30
28
  get header() {
31
29
  return { Authorization: `Basic ${this._basicAuthString}` };
32
30
  }
@@ -43,7 +41,6 @@ class BasicAuthProvider {
43
41
 
44
42
  const buildErrorMessage = (code, message) => `[@ethlete\\query:${code}] ${message}`;
45
43
  class QueryError extends Error {
46
- data;
47
44
  constructor(code, message, data) {
48
45
  super(buildErrorMessage(code, message));
49
46
  this.name = 'QueryError';
@@ -699,71 +696,67 @@ const deepFreeze = (object) => {
699
696
  const def = () => null;
700
697
 
701
698
  class QueryCreator {
702
- _queryConfig;
703
- _client;
704
- _store;
705
699
  constructor(_queryConfig, _client, _store) {
706
700
  this._queryConfig = _queryConfig;
707
701
  this._client = _client;
708
702
  this._store = _store;
709
- }
710
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
711
- // @ts-ignore
712
- prepare = (args) => {
713
- const route = buildRoute({
714
- base: this._client.config.baseRoute,
715
- route: this._queryConfig.route,
716
- pathParams: args?.pathParams,
717
- queryParams: computeQueryQueryParams({ config: this._queryConfig, client: this._client, args }),
718
- queryParamConfig: this._client.config.request?.queryParams,
719
- });
720
- const cacheKey = (args?.config?.queryStoreCacheKey ?? '') + buildQueryCacheKey$1(route, args);
721
- if (shouldCacheQuery$1(this._queryConfig.method) && !args?.config?.skipQueryStore) {
722
- const existingQuery = this._store.get(cacheKey);
723
- if (existingQuery) {
724
- return existingQuery;
703
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
704
+ // @ts-ignore
705
+ this.prepare = (args) => {
706
+ const route = buildRoute({
707
+ base: this._client.config.baseRoute,
708
+ route: this._queryConfig.route,
709
+ pathParams: args?.pathParams,
710
+ queryParams: computeQueryQueryParams({ config: this._queryConfig, client: this._client, args }),
711
+ queryParamConfig: this._client.config.request?.queryParams,
712
+ });
713
+ const cacheKey = (args?.config?.queryStoreCacheKey ?? '') + buildQueryCacheKey$1(route, args);
714
+ if (shouldCacheQuery$1(this._queryConfig.method) && !args?.config?.skipQueryStore) {
715
+ const existingQuery = this._store.get(cacheKey);
716
+ if (existingQuery) {
717
+ return existingQuery;
718
+ }
725
719
  }
726
- }
727
- const query = new Query(this._client, this._queryConfig, route, args ?? {}, cacheKey);
728
- if (shouldCacheQuery$1(this._queryConfig.method) && !args?.config?.skipQueryStore) {
729
- this._store.add(cacheKey, query);
730
- }
731
- this._store._dispatchQueryCreated(query);
732
- return query;
733
- };
734
- createSubject = (initialValue, config) => {
735
- assertInInjectionContext(this.createSubject);
736
- const subject = new BehaviorSubject(initialValue ?? null);
737
- addQueryContainerHandling(subject, () => subject.getValue(), config);
738
- return subject;
739
- };
740
- createSignal = (initialValue, config) => {
741
- assertInInjectionContext(this.createSignal);
742
- const _signal = signal(initialValue ?? null);
743
- addQueryContainerHandling(toObservable(_signal), () => _signal(), config);
744
- return _signal;
745
- };
746
- /**
747
- * @deprecated Use `myQuery.createSubject()` or `myQuery.createSignal()` instead. Will be removed in v6.
748
- */
749
- behaviorSubject = (initialValue) => new BehaviorSubject(initialValue ?? null);
720
+ const query = new Query(this._client, this._queryConfig, route, args ?? {}, cacheKey);
721
+ if (shouldCacheQuery$1(this._queryConfig.method) && !args?.config?.skipQueryStore) {
722
+ this._store.add(cacheKey, query);
723
+ }
724
+ this._store._dispatchQueryCreated(query);
725
+ return query;
726
+ };
727
+ this.createSubject = (initialValue, config) => {
728
+ assertInInjectionContext(this.createSubject);
729
+ const subject = new BehaviorSubject(initialValue ?? null);
730
+ addQueryContainerHandling(subject, () => subject.getValue(), config);
731
+ return subject;
732
+ };
733
+ this.createSignal = (initialValue, config) => {
734
+ assertInInjectionContext(this.createSignal);
735
+ const _signal = signal(initialValue ?? null);
736
+ addQueryContainerHandling(toObservable(_signal), () => _signal(), config);
737
+ return _signal;
738
+ };
739
+ /**
740
+ * @deprecated Use `myQuery.createSubject()` or `myQuery.createSignal()` instead. Will be removed in v6.
741
+ */
742
+ this.behaviorSubject = (initialValue) => new BehaviorSubject(initialValue ?? null);
743
+ }
750
744
  }
751
745
 
752
746
  class QueryStore {
753
- _config;
754
- /**
755
- * @internal
756
- */
757
- _store = new Map();
758
- _garbageCollector = null;
759
- _isInLowResourceMode = false;
760
- _lastBlurTimestamp = Date.now();
761
- _storeChange$ = new Subject();
762
- _queryCreated$ = new Subject();
763
- storeChange$ = this._storeChange$.asObservable();
764
- queryCreated$ = this._queryCreated$.asObservable();
765
747
  constructor(_config) {
766
748
  this._config = _config;
749
+ /**
750
+ * @internal
751
+ */
752
+ this._store = new Map();
753
+ this._garbageCollector = null;
754
+ this._isInLowResourceMode = false;
755
+ this._lastBlurTimestamp = Date.now();
756
+ this._storeChange$ = new Subject();
757
+ this._queryCreated$ = new Subject();
758
+ this.storeChange$ = this._storeChange$.asObservable();
759
+ this.queryCreated$ = this._queryCreated$.asObservable();
767
760
  this._initSmartQueryHandling();
768
761
  }
769
762
  add(id, query) {
@@ -894,11 +887,6 @@ class QueryStore {
894
887
  }
895
888
 
896
889
  class QueryClient {
897
- _clientConfig;
898
- /**
899
- * @internal
900
- */
901
- _store;
902
890
  get config() {
903
891
  return this._clientConfig;
904
892
  }
@@ -908,9 +896,64 @@ class QueryClient {
908
896
  get authProvider$() {
909
897
  return this._authProvider$.asObservable() ?? this._clientConfig.parent?._authProvider$.asObservable() ?? null;
910
898
  }
911
- _authProvider$ = new BehaviorSubject(null);
912
899
  constructor(_clientConfig) {
913
900
  this._clientConfig = _clientConfig;
901
+ this._authProvider$ = new BehaviorSubject(null);
902
+ this.get = (queryConfig) => this.fetch({
903
+ ...queryConfig,
904
+ method: 'GET',
905
+ });
906
+ this.post = (queryConfig) => this.fetch({
907
+ ...queryConfig,
908
+ method: 'POST',
909
+ });
910
+ this.put = (queryConfig) => this.fetch({
911
+ ...queryConfig,
912
+ method: 'PUT',
913
+ });
914
+ this.patch = (queryConfig) => this.fetch({
915
+ ...queryConfig,
916
+ method: 'PATCH',
917
+ });
918
+ this.delete = (queryConfig) => this.fetch({
919
+ ...queryConfig,
920
+ method: 'DELETE',
921
+ });
922
+ this.gqlQuery = (queryConfig) => this.fetch({
923
+ ...queryConfig,
924
+ method: 'GQL_QUERY',
925
+ });
926
+ this.gqlMutate = (queryConfig) => this.fetch({
927
+ ...queryConfig,
928
+ method: 'GQL_MUTATE',
929
+ });
930
+ this.fetch = (queryConfig) => new QueryCreator(queryConfig, this, this._store);
931
+ this.setAuthProvider = (authProvider) => {
932
+ if (this.authProvider) {
933
+ this.authProvider?.cleanUp();
934
+ }
935
+ this._authProvider$.next(authProvider);
936
+ };
937
+ this.setDefaultHeaders = (config) => {
938
+ if (!this._clientConfig.request) {
939
+ this._clientConfig.request = {
940
+ headers: config.headers ?? undefined,
941
+ };
942
+ }
943
+ else {
944
+ this._clientConfig.request.headers = config.headers ?? undefined;
945
+ }
946
+ if (config.refreshQueriesInUse) {
947
+ this._store.refreshQueriesInUse({ purgeUnused: true, ignoreCacheValidity: true });
948
+ }
949
+ };
950
+ this.clearAuthProvider = () => {
951
+ this.authProvider?.cleanUp();
952
+ this._authProvider$.next(null);
953
+ };
954
+ this._updateBaseRoute = (route) => {
955
+ this._clientConfig.baseRoute = route;
956
+ };
914
957
  this._store = new QueryStore({
915
958
  enableChangeLogging: _clientConfig.logging?.queryStateChanges,
916
959
  enableGarbageCollectorLogging: _clientConfig.logging?.queryStateGarbageCollector,
@@ -918,61 +961,6 @@ class QueryClient {
918
961
  enableSmartPolling: _clientConfig.request?.enableSmartPolling ?? true,
919
962
  });
920
963
  }
921
- get = (queryConfig) => this.fetch({
922
- ...queryConfig,
923
- method: 'GET',
924
- });
925
- post = (queryConfig) => this.fetch({
926
- ...queryConfig,
927
- method: 'POST',
928
- });
929
- put = (queryConfig) => this.fetch({
930
- ...queryConfig,
931
- method: 'PUT',
932
- });
933
- patch = (queryConfig) => this.fetch({
934
- ...queryConfig,
935
- method: 'PATCH',
936
- });
937
- delete = (queryConfig) => this.fetch({
938
- ...queryConfig,
939
- method: 'DELETE',
940
- });
941
- gqlQuery = (queryConfig) => this.fetch({
942
- ...queryConfig,
943
- method: 'GQL_QUERY',
944
- });
945
- gqlMutate = (queryConfig) => this.fetch({
946
- ...queryConfig,
947
- method: 'GQL_MUTATE',
948
- });
949
- fetch = (queryConfig) => new QueryCreator(queryConfig, this, this._store);
950
- setAuthProvider = (authProvider) => {
951
- if (this.authProvider) {
952
- this.authProvider?.cleanUp();
953
- }
954
- this._authProvider$.next(authProvider);
955
- };
956
- setDefaultHeaders = (config) => {
957
- if (!this._clientConfig.request) {
958
- this._clientConfig.request = {
959
- headers: config.headers ?? undefined,
960
- };
961
- }
962
- else {
963
- this._clientConfig.request.headers = config.headers ?? undefined;
964
- }
965
- if (config.refreshQueriesInUse) {
966
- this._store.refreshQueriesInUse({ purgeUnused: true, ignoreCacheValidity: true });
967
- }
968
- };
969
- clearAuthProvider = () => {
970
- this.authProvider?.cleanUp();
971
- this._authProvider$.next(null);
972
- };
973
- _updateBaseRoute = (route) => {
974
- this._clientConfig.baseRoute = route;
975
- };
976
964
  }
977
965
 
978
966
  const shouldCacheQuery$1 = (method) => {
@@ -1264,36 +1252,6 @@ const paginatedEntityValueUpdater = (findFn) => ({ response, rawResponse, entity
1264
1252
 
1265
1253
  let _nextQueryId = 0;
1266
1254
  class Query {
1267
- _client;
1268
- _queryConfig;
1269
- _routeWithParams;
1270
- _arguments;
1271
- _queryStoreKey;
1272
- _id = _nextQueryId++;
1273
- _currentLocalId = 0;
1274
- _pollingSubscription = null;
1275
- _onAbort$ = new Subject();
1276
- _currentPollConfig = null;
1277
- /**
1278
- * @internal
1279
- * Used to track which components depend on this query.
1280
- * The key is the component's _tNode index.
1281
- * The value is the number of times the component has subscribed to this query.
1282
- * The value might increase since we cant distinguish between a component and a host directive applied to it.
1283
- */
1284
- _dependents = {};
1285
- /**
1286
- * @internal
1287
- */
1288
- _dependentsChanged$ = new ReplaySubject();
1289
- /**
1290
- * @internal
1291
- */
1292
- _isPollingPaused = false;
1293
- _state$ = new BehaviorSubject({
1294
- type: "PREPARED" /* QueryStateType.Prepared */,
1295
- meta: { id: this._currentLocalId, triggeredVia: 'program' },
1296
- });
1297
1255
  get _nextId() {
1298
1256
  return ++this._currentLocalId;
1299
1257
  }
@@ -1387,6 +1345,31 @@ class Query {
1387
1345
  this._routeWithParams = _routeWithParams;
1388
1346
  this._arguments = _arguments;
1389
1347
  this._queryStoreKey = _queryStoreKey;
1348
+ this._id = _nextQueryId++;
1349
+ this._currentLocalId = 0;
1350
+ this._pollingSubscription = null;
1351
+ this._onAbort$ = new Subject();
1352
+ this._currentPollConfig = null;
1353
+ /**
1354
+ * @internal
1355
+ * Used to track which components depend on this query.
1356
+ * The key is the component's _tNode index.
1357
+ * The value is the number of times the component has subscribed to this query.
1358
+ * The value might increase since we cant distinguish between a component and a host directive applied to it.
1359
+ */
1360
+ this._dependents = {};
1361
+ /**
1362
+ * @internal
1363
+ */
1364
+ this._dependentsChanged$ = new ReplaySubject();
1365
+ /**
1366
+ * @internal
1367
+ */
1368
+ this._isPollingPaused = false;
1369
+ this._state$ = new BehaviorSubject({
1370
+ type: "PREPARED" /* QueryStateType.Prepared */,
1371
+ meta: { id: this._currentLocalId, triggeredVia: 'program' },
1372
+ });
1390
1373
  }
1391
1374
  execute(options = {}) {
1392
1375
  const { skipCache = false, _triggeredVia: triggeredVia = 'program', cancelPrevious = false } = options;
@@ -1715,13 +1698,6 @@ const decryptBearer = (token) => {
1715
1698
  };
1716
1699
 
1717
1700
  class BearerAuthProvider {
1718
- _config;
1719
- _destroy$ = new Subject();
1720
- _currentRefreshQuery$ = new BehaviorSubject(null);
1721
- _tokens$ = new BehaviorSubject({
1722
- token: null,
1723
- refreshToken: null,
1724
- });
1725
1701
  get header() {
1726
1702
  return { Authorization: `Bearer ${this._tokens$.getValue().token}` };
1727
1703
  }
@@ -1744,6 +1720,12 @@ class BearerAuthProvider {
1744
1720
  }
1745
1721
  constructor(_config) {
1746
1722
  this._config = _config;
1723
+ this._destroy$ = new Subject();
1724
+ this._currentRefreshQuery$ = new BehaviorSubject(null);
1725
+ this._tokens$ = new BehaviorSubject({
1726
+ token: null,
1727
+ refreshToken: null,
1728
+ });
1747
1729
  const cookieEnabled = _config.refreshConfig?.cookieEnabled ?? true;
1748
1730
  const cookieToken = _config.refreshConfig?.cookieName && cookieEnabled ? (getCookie(_config.refreshConfig.cookieName) ?? null) : null;
1749
1731
  this._tokens$.next({
@@ -1884,22 +1866,25 @@ const isClassValidatorError = (error) => {
1884
1866
  };
1885
1867
 
1886
1868
  class QueryDirective {
1887
- _mainTemplateRef = inject(TemplateRef);
1888
- _viewContainerRef = inject(ViewContainerRef);
1889
- _errorHandler = inject(ErrorHandler);
1890
- _cdr = inject(ChangeDetectorRef);
1891
- _isMainViewCreated = false;
1892
- _subscription = null;
1893
- _viewContext = {
1894
- $implicit: null,
1895
- etQuery: null,
1896
- loading: false,
1897
- refreshing: false,
1898
- error: null,
1899
- progress: null,
1900
- scope: null,
1901
- query: null,
1902
- };
1869
+ constructor() {
1870
+ this._mainTemplateRef = inject(TemplateRef);
1871
+ this._viewContainerRef = inject(ViewContainerRef);
1872
+ this._errorHandler = inject(ErrorHandler);
1873
+ this._cdr = inject(ChangeDetectorRef);
1874
+ this._isMainViewCreated = false;
1875
+ this._subscription = null;
1876
+ this._viewContext = {
1877
+ $implicit: null,
1878
+ etQuery: null,
1879
+ loading: false,
1880
+ refreshing: false,
1881
+ error: null,
1882
+ progress: null,
1883
+ scope: null,
1884
+ query: null,
1885
+ };
1886
+ this._cache = false;
1887
+ }
1903
1888
  get query() {
1904
1889
  return this._query;
1905
1890
  }
@@ -1907,14 +1892,12 @@ class QueryDirective {
1907
1892
  this._query = v;
1908
1893
  this._subscribeToQuery();
1909
1894
  }
1910
- _query;
1911
1895
  get cache() {
1912
1896
  return this._cache;
1913
1897
  }
1914
1898
  set cache(v) {
1915
1899
  this._cache = v;
1916
1900
  }
1917
- _cache = false;
1918
1901
  static ngTemplateContextGuard(dir, ctx) {
1919
1902
  return true;
1920
1903
  }
@@ -1983,8 +1966,8 @@ class QueryDirective {
1983
1966
  this._viewContainerRef.createEmbeddedView(this._mainTemplateRef, this._viewContext);
1984
1967
  }
1985
1968
  }
1986
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: QueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1987
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.4", type: QueryDirective, isStandalone: true, selector: "[etQuery]", inputs: { query: ["etQuery", "query"], cache: ["etQueryCache", "cache"] }, ngImport: i0 });
1969
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: QueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1970
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.4", type: QueryDirective, isStandalone: true, selector: "[etQuery]", inputs: { query: ["etQuery", "query"], cache: ["etQueryCache", "cache"] }, ngImport: i0 }); }
1988
1971
  }
1989
1972
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: QueryDirective, decorators: [{
1990
1973
  type: Directive,
@@ -2001,58 +1984,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImpor
2001
1984
  }] } });
2002
1985
 
2003
1986
  class InfinityQuery {
2004
- _config;
2005
- _destroy$;
2006
- _queries$ = new BehaviorSubject([]);
2007
- _currentPage$ = new BehaviorSubject(null);
2008
- _currentCalculatedPage$ = new BehaviorSubject(null);
2009
- _totalPages$ = new BehaviorSubject(null);
2010
- _itemsPerPage$ = new BehaviorSubject(10);
2011
- _data$ = this._queries$.pipe(switchMap((queries) => {
2012
- if (!queries.length) {
2013
- return of([]);
2014
- }
2015
- return combineLatest(queries.map((query) => query.state$.pipe(filterSuccess(), map((state) => ({ state, query })))));
2016
- }), tap((stateMaps) => {
2017
- const lastState = stateMaps[stateMaps.length - 1]?.state;
2018
- const lastQuery = stateMaps[stateMaps.length - 1]?.query;
2019
- if (!lastState || !lastQuery) {
2020
- return;
2021
- }
2022
- const totalPages = this._config.response.totalPagesExtractor?.({
2023
- response: lastState.response,
2024
- itemsPerPage: this.itemsPerPage,
2025
- args: lastQuery._arguments,
2026
- }) ??
2027
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2028
- lastState.response?.totalPages ??
2029
- null;
2030
- this._totalPages$.next(totalPages);
2031
- }), map((stateMaps) => {
2032
- if (!stateMaps.length) {
2033
- return null;
2034
- }
2035
- const fullData = stateMaps.reduce((acc, stateMap) => {
2036
- const valExtractFn = this._config?.response?.valueExtractor;
2037
- let data = valExtractFn
2038
- ? valExtractFn?.(stateMap.state.response)
2039
- : stateMap.state.response;
2040
- if (this._config.response.reverse) {
2041
- data = [...data].reverse();
2042
- }
2043
- if (this._config.response.appendItemsTo === 'start') {
2044
- acc.unshift(...data);
2045
- }
2046
- else {
2047
- acc.push(...data);
2048
- }
2049
- return acc;
2050
- },
2051
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2052
- []);
2053
- return fullData;
2054
- }), shareReplay({ bufferSize: 1, refCount: true }));
2055
- _lastQuery$ = this._queries$.pipe(map((queries) => queries[queries.length - 1] ?? null), shareReplay({ bufferSize: 1, refCount: true }));
2056
1987
  get currentPage$() {
2057
1988
  return this._currentPage$.asObservable();
2058
1989
  }
@@ -2086,6 +2017,56 @@ class InfinityQuery {
2086
2017
  constructor(_config, _destroy$) {
2087
2018
  this._config = _config;
2088
2019
  this._destroy$ = _destroy$;
2020
+ this._queries$ = new BehaviorSubject([]);
2021
+ this._currentPage$ = new BehaviorSubject(null);
2022
+ this._currentCalculatedPage$ = new BehaviorSubject(null);
2023
+ this._totalPages$ = new BehaviorSubject(null);
2024
+ this._itemsPerPage$ = new BehaviorSubject(10);
2025
+ this._data$ = this._queries$.pipe(switchMap((queries) => {
2026
+ if (!queries.length) {
2027
+ return of([]);
2028
+ }
2029
+ return combineLatest(queries.map((query) => query.state$.pipe(filterSuccess(), map((state) => ({ state, query })))));
2030
+ }), tap((stateMaps) => {
2031
+ const lastState = stateMaps[stateMaps.length - 1]?.state;
2032
+ const lastQuery = stateMaps[stateMaps.length - 1]?.query;
2033
+ if (!lastState || !lastQuery) {
2034
+ return;
2035
+ }
2036
+ const totalPages = this._config.response.totalPagesExtractor?.({
2037
+ response: lastState.response,
2038
+ itemsPerPage: this.itemsPerPage,
2039
+ args: lastQuery._arguments,
2040
+ }) ??
2041
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2042
+ lastState.response?.totalPages ??
2043
+ null;
2044
+ this._totalPages$.next(totalPages);
2045
+ }), map((stateMaps) => {
2046
+ if (!stateMaps.length) {
2047
+ return null;
2048
+ }
2049
+ const fullData = stateMaps.reduce((acc, stateMap) => {
2050
+ const valExtractFn = this._config?.response?.valueExtractor;
2051
+ let data = valExtractFn
2052
+ ? valExtractFn?.(stateMap.state.response)
2053
+ : stateMap.state.response;
2054
+ if (this._config.response.reverse) {
2055
+ data = [...data].reverse();
2056
+ }
2057
+ if (this._config.response.appendItemsTo === 'start') {
2058
+ acc.unshift(...data);
2059
+ }
2060
+ else {
2061
+ acc.push(...data);
2062
+ }
2063
+ return acc;
2064
+ },
2065
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2066
+ []);
2067
+ return fullData;
2068
+ }), shareReplay({ bufferSize: 1, refCount: true }));
2069
+ this._lastQuery$ = this._queries$.pipe(map((queries) => queries[queries.length - 1] ?? null), shareReplay({ bufferSize: 1, refCount: true }));
2089
2070
  this._itemsPerPage$.next(this._config.limitParam?.value ?? 10);
2090
2071
  }
2091
2072
  nextPage() {
@@ -2178,28 +2159,6 @@ const skipPaginationPageParamCalculator = ({ page, itemsPerPage }) => itemsPerPa
2178
2159
  /* eslint-disable @typescript-eslint/no-explicit-any */
2179
2160
  const INFINITY_QUERY_TOKEN = new InjectionToken('INFINITY_QUERY_TOKEN');
2180
2161
  class InfinityQueryDirective {
2181
- _queryConfigChanged$ = new Subject();
2182
- _viewContext = {
2183
- $implicit: null,
2184
- etInfinityQuery: null,
2185
- loading: false,
2186
- error: null,
2187
- isFirstLoad: false,
2188
- canLoadMore: false,
2189
- currentPage: null,
2190
- currentCalculatedPage: null,
2191
- totalPages: null,
2192
- itemsPerPage: null,
2193
- currentQuery: null,
2194
- };
2195
- _infinityQueryInstance = null;
2196
- _destroy$ = createDestroy();
2197
- _cdr = inject(ChangeDetectorRef);
2198
- _viewContainerRef = inject(ViewContainerRef);
2199
- _mainTemplateRef = inject((TemplateRef));
2200
- _errorHandler = inject(ErrorHandler);
2201
- _delayable = inject(DelayableDirective, { host: true });
2202
- _data$ = new BehaviorSubject([]);
2203
2162
  get infinityQuery() {
2204
2163
  return this._infinityQuery;
2205
2164
  }
@@ -2209,7 +2168,6 @@ class InfinityQueryDirective {
2209
2168
  this._infinityQueryInstance = this._setupInfinityQuery(v);
2210
2169
  this._infinityQueryInstance.nextPage();
2211
2170
  }
2212
- _infinityQuery;
2213
2171
  get context() {
2214
2172
  return this._viewContext;
2215
2173
  }
@@ -2219,11 +2177,33 @@ class InfinityQueryDirective {
2219
2177
  get data$() {
2220
2178
  return this._data$.asObservable();
2221
2179
  }
2222
- data = toSignal(this._data$, { requireSync: true });
2223
2180
  static ngTemplateContextGuard(dir, ctx) {
2224
2181
  return true;
2225
2182
  }
2226
2183
  constructor() {
2184
+ this._queryConfigChanged$ = new Subject();
2185
+ this._viewContext = {
2186
+ $implicit: null,
2187
+ etInfinityQuery: null,
2188
+ loading: false,
2189
+ error: null,
2190
+ isFirstLoad: false,
2191
+ canLoadMore: false,
2192
+ currentPage: null,
2193
+ currentCalculatedPage: null,
2194
+ totalPages: null,
2195
+ itemsPerPage: null,
2196
+ currentQuery: null,
2197
+ };
2198
+ this._infinityQueryInstance = null;
2199
+ this._destroy$ = createDestroy();
2200
+ this._cdr = inject(ChangeDetectorRef);
2201
+ this._viewContainerRef = inject(ViewContainerRef);
2202
+ this._mainTemplateRef = inject((TemplateRef));
2203
+ this._errorHandler = inject(ErrorHandler);
2204
+ this._delayable = inject(DelayableDirective, { host: true });
2205
+ this._data$ = new BehaviorSubject([]);
2206
+ this.data = toSignal(this._data$, { requireSync: true });
2227
2207
  this._viewContainerRef.createEmbeddedView(this._mainTemplateRef, this._viewContext);
2228
2208
  }
2229
2209
  _setupInfinityQuery(config) {
@@ -2297,8 +2277,8 @@ class InfinityQueryDirective {
2297
2277
  this._viewContext.currentQuery = null;
2298
2278
  this._data$.next([]);
2299
2279
  }
2300
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: InfinityQueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2301
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.4", type: InfinityQueryDirective, isStandalone: true, selector: "[etInfinityQuery]", inputs: { infinityQuery: ["etInfinityQuery", "infinityQuery"] }, providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }], exportAs: ["etInfinityQuery"], hostDirectives: [{ directive: i1.DelayableDirective }], ngImport: i0 });
2280
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: InfinityQueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2281
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.4", type: InfinityQueryDirective, isStandalone: true, selector: "[etInfinityQuery]", inputs: { infinityQuery: ["etInfinityQuery", "infinityQuery"] }, providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }], exportAs: ["etInfinityQuery"], hostDirectives: [{ directive: i1.DelayableDirective }], ngImport: i0 }); }
2302
2282
  }
2303
2283
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: InfinityQueryDirective, decorators: [{
2304
2284
  type: Directive,
@@ -2315,12 +2295,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImpor
2315
2295
  }] } });
2316
2296
 
2317
2297
  class InfinityQueryTriggerDirective {
2318
- _elementRef = inject((ElementRef));
2319
- _infinityQuery = inject(INFINITY_QUERY_TOKEN);
2320
- _destroy = new Subject();
2321
- _observer = null;
2322
- click$ = fromEvent(this._elementRef.nativeElement, 'click');
2323
- scrollContainerSelector = null;
2298
+ constructor() {
2299
+ this._elementRef = inject((ElementRef));
2300
+ this._infinityQuery = inject(INFINITY_QUERY_TOKEN);
2301
+ this._destroy = new Subject();
2302
+ this._observer = null;
2303
+ this.click$ = fromEvent(this._elementRef.nativeElement, 'click');
2304
+ this.scrollContainerSelector = null;
2305
+ }
2324
2306
  ngOnInit() {
2325
2307
  const isInteractive = this._elementRef.nativeElement.tagName === 'BUTTON';
2326
2308
  if (isInteractive) {
@@ -2350,8 +2332,8 @@ class InfinityQueryTriggerDirective {
2350
2332
  });
2351
2333
  this._observer.observe(this._elementRef.nativeElement);
2352
2334
  }
2353
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: InfinityQueryTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2354
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.4", type: InfinityQueryTriggerDirective, isStandalone: true, selector: "[etInfinityQueryTrigger], et-infinity-query-trigger", inputs: { scrollContainerSelector: "scrollContainerSelector" }, ngImport: i0 });
2335
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: InfinityQueryTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2336
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.4", type: InfinityQueryTriggerDirective, isStandalone: true, selector: "[etInfinityQueryTrigger], et-infinity-query-trigger", inputs: { scrollContainerSelector: "scrollContainerSelector" }, ngImport: i0 }); }
2355
2337
  }
2356
2338
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: InfinityQueryTriggerDirective, decorators: [{
2357
2339
  type: Directive,
@@ -2377,8 +2359,8 @@ class QueryShortNamePipe {
2377
2359
  }
2378
2360
  return route;
2379
2361
  }
2380
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: QueryShortNamePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
2381
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.1.4", ngImport: i0, type: QueryShortNamePipe, isStandalone: true, name: "queryShortName" });
2362
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: QueryShortNamePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
2363
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.1.4", ngImport: i0, type: QueryShortNamePipe, isStandalone: true, name: "queryShortName" }); }
2382
2364
  }
2383
2365
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: QueryShortNamePipe, decorators: [{
2384
2366
  type: Pipe,
@@ -2398,159 +2380,161 @@ const provideQueryClientForDevtools = (queryClient) => {
2398
2380
  };
2399
2381
 
2400
2382
  class QueryDevtoolsComponent {
2401
- _cdr = inject(ChangeDetectorRef);
2402
- _destroy$ = createDestroy();
2403
- queryClientConfigs = inject(QUERY_CLIENT_DEVTOOLS_TOKEN);
2404
- isOpen = signal(false);
2405
- isTranslucent = signal(false);
2406
- snapLayout = signal('full');
2407
- queryListMode = signal('live');
2408
- viewMode = signal('query');
2409
- showResponse = signal(false);
2410
- showRawResponse = signal(false);
2411
- showQueryConfig = signal(false);
2412
- showEntityStoreValue = signal(false);
2413
- showArguments = signal(false);
2414
- selectedClientIdCtrl = new FormControl(0);
2415
- selectedClientId = toSignal(this.selectedClientIdCtrl.valueChanges.pipe(startWith(this.selectedClientIdCtrl.value)));
2416
- selectedQueryId = signal(null);
2417
- selectedClientConfig = computed(() => {
2418
- if (this.queryClientConfigs.length === 1) {
2419
- return this.queryClientConfigs[0];
2420
- }
2421
- const index = this.selectedClientId() ?? 0;
2422
- const cfg = this.queryClientConfigs[index];
2423
- if (!cfg) {
2424
- return this.queryClientConfigs[0];
2425
- }
2426
- return cfg;
2427
- });
2428
- queryStore = computed(() => {
2429
- const config = this.selectedClientConfig();
2430
- return config.client._store;
2431
- });
2432
- queryStore$ = toObservable(this.queryStore);
2433
- _queries$ = new BehaviorSubject([]);
2434
- queries = toSignal(this._queries$);
2435
- selectedQuery = computed(() => {
2436
- const id = this.selectedQueryId();
2437
- const mode = this.queryListMode();
2438
- if (id === null || !mode) {
2439
- return null;
2440
- }
2441
- if (mode === 'live') {
2442
- return this.queries()?.find((q) => q._id === id) ?? null;
2443
- }
2444
- return this.queryHistory$.getValue()?.find((q) => q._id === id) ?? null;
2445
- });
2446
- selectedQuery$ = toObservable(this.selectedQuery);
2447
- selectedQueryEntityStore = computed(() => {
2448
- const query = this.selectedQuery();
2449
- if (!query)
2450
- return null;
2451
- return query.store;
2452
- });
2453
- selectedQueryEntityStore$ = toObservable(this.selectedQueryEntityStore);
2454
- selectedQueryEntityStoreValue$ = this.selectedQueryEntityStore$.pipe(switchMap((s) => s?._change$.pipe(startWith(''), map(() => {
2455
- if (!s._dictionary)
2456
- return null;
2457
- return Array.from(s._dictionary).reduce((obj, [key, value]) => {
2458
- obj[key] = value;
2459
- return obj;
2460
- }, {});
2461
- })) ?? of(null)));
2462
- queryHistory$ = new BehaviorSubject([]);
2463
- stringifiedQueryConfig = computed(() => {
2464
- const query = this.selectedQuery();
2465
- if (!query)
2466
- return null;
2467
- const cfg = query._queryConfig;
2468
- const route = typeof cfg.route === 'string' ? cfg.route : cfg.route ? cfg.route({}).replace(/undefined/g, ':param') : null;
2469
- const sharedCfg = {
2470
- method: cfg.method,
2471
- secure: cfg.secure,
2472
- route,
2473
- reportProgress: cfg.reportProgress,
2474
- responseType: cfg.responseType,
2475
- withCredentials: cfg.withCredentials,
2476
- autoRefreshOn: cfg.autoRefreshOn,
2477
- enableSmartPolling: cfg.enableSmartPolling,
2478
- hasEntityStore: !!cfg.entity,
2479
- };
2480
- if (isGqlQueryConfig(cfg)) {
2481
- return {
2482
- ...sharedCfg,
2483
- query: cfg.query,
2484
- transferVia: cfg.transferVia,
2485
- };
2486
- }
2487
- return {
2488
- ...sharedCfg,
2489
- };
2490
- });
2491
- authProvider = toSignal(toObservable(this.selectedClientConfig).pipe(switchMap((c) => c.client.authProvider$)));
2492
- authProviderDetails = computed(() => {
2493
- const provider = this.authProvider();
2494
- if (!provider)
2495
- return null;
2496
- if (provider instanceof CustomHeaderAuthProvider) {
2497
- return {
2498
- type: 'CustomHeaderAuthProvider',
2499
- header: () => provider.header,
2500
- provider: provider,
2501
- config: {
2502
- name: provider._config.name,
2503
- value: provider._config.value,
2504
- },
2383
+ constructor() {
2384
+ this._cdr = inject(ChangeDetectorRef);
2385
+ this._destroy$ = createDestroy();
2386
+ this.queryClientConfigs = inject(QUERY_CLIENT_DEVTOOLS_TOKEN);
2387
+ this.isOpen = signal(false);
2388
+ this.isTranslucent = signal(false);
2389
+ this.snapLayout = signal('full');
2390
+ this.queryListMode = signal('live');
2391
+ this.viewMode = signal('query');
2392
+ this.showResponse = signal(false);
2393
+ this.showRawResponse = signal(false);
2394
+ this.showQueryConfig = signal(false);
2395
+ this.showEntityStoreValue = signal(false);
2396
+ this.showArguments = signal(false);
2397
+ this.selectedClientIdCtrl = new FormControl(0);
2398
+ this.selectedClientId = toSignal(this.selectedClientIdCtrl.valueChanges.pipe(startWith(this.selectedClientIdCtrl.value)));
2399
+ this.selectedQueryId = signal(null);
2400
+ this.selectedClientConfig = computed(() => {
2401
+ if (this.queryClientConfigs.length === 1) {
2402
+ return this.queryClientConfigs[0];
2403
+ }
2404
+ const index = this.selectedClientId() ?? 0;
2405
+ const cfg = this.queryClientConfigs[index];
2406
+ if (!cfg) {
2407
+ return this.queryClientConfigs[0];
2408
+ }
2409
+ return cfg;
2410
+ });
2411
+ this.queryStore = computed(() => {
2412
+ const config = this.selectedClientConfig();
2413
+ return config.client._store;
2414
+ });
2415
+ this.queryStore$ = toObservable(this.queryStore);
2416
+ this._queries$ = new BehaviorSubject([]);
2417
+ this.queries = toSignal(this._queries$);
2418
+ this.selectedQuery = computed(() => {
2419
+ const id = this.selectedQueryId();
2420
+ const mode = this.queryListMode();
2421
+ if (id === null || !mode) {
2422
+ return null;
2423
+ }
2424
+ if (mode === 'live') {
2425
+ return this.queries()?.find((q) => q._id === id) ?? null;
2426
+ }
2427
+ return this.queryHistory$.getValue()?.find((q) => q._id === id) ?? null;
2428
+ });
2429
+ this.selectedQuery$ = toObservable(this.selectedQuery);
2430
+ this.selectedQueryEntityStore = computed(() => {
2431
+ const query = this.selectedQuery();
2432
+ if (!query)
2433
+ return null;
2434
+ return query.store;
2435
+ });
2436
+ this.selectedQueryEntityStore$ = toObservable(this.selectedQueryEntityStore);
2437
+ this.selectedQueryEntityStoreValue$ = this.selectedQueryEntityStore$.pipe(switchMap((s) => s?._change$.pipe(startWith(''), map(() => {
2438
+ if (!s._dictionary)
2439
+ return null;
2440
+ return Array.from(s._dictionary).reduce((obj, [key, value]) => {
2441
+ obj[key] = value;
2442
+ return obj;
2443
+ }, {});
2444
+ })) ?? of(null)));
2445
+ this.queryHistory$ = new BehaviorSubject([]);
2446
+ this.stringifiedQueryConfig = computed(() => {
2447
+ const query = this.selectedQuery();
2448
+ if (!query)
2449
+ return null;
2450
+ const cfg = query._queryConfig;
2451
+ const route = typeof cfg.route === 'string' ? cfg.route : cfg.route ? cfg.route({}).replace(/undefined/g, ':param') : null;
2452
+ const sharedCfg = {
2453
+ method: cfg.method,
2454
+ secure: cfg.secure,
2455
+ route,
2456
+ reportProgress: cfg.reportProgress,
2457
+ responseType: cfg.responseType,
2458
+ withCredentials: cfg.withCredentials,
2459
+ autoRefreshOn: cfg.autoRefreshOn,
2460
+ enableSmartPolling: cfg.enableSmartPolling,
2461
+ hasEntityStore: !!cfg.entity,
2505
2462
  };
2506
- }
2507
- else if (provider instanceof BasicAuthProvider) {
2463
+ if (isGqlQueryConfig(cfg)) {
2464
+ return {
2465
+ ...sharedCfg,
2466
+ query: cfg.query,
2467
+ transferVia: cfg.transferVia,
2468
+ };
2469
+ }
2508
2470
  return {
2509
- type: 'BasicAuthProvider',
2510
- header: () => provider.header,
2511
- provider: provider,
2512
- config: {
2513
- username: provider._config.username,
2514
- password: provider._config.password,
2515
- },
2471
+ ...sharedCfg,
2516
2472
  };
2517
- }
2518
- else if (isBearerAuthProvider(provider)) {
2519
- const refreshCfg = provider._config.refreshConfig;
2520
- return {
2521
- type: 'BearerAuthProvider',
2522
- header: () => provider.header,
2523
- provider: provider,
2524
- config: {
2525
- token: provider._config.token,
2526
- refreshConfig: {
2527
- refreshOnUnauthorizedResponse: refreshCfg?.refreshOnUnauthorizedResponse ?? 'true (default)',
2528
- token: refreshCfg?.token,
2529
- cookieName: refreshCfg?.cookieName,
2530
- cookieDomain: refreshCfg?.cookieDomain ?? 'current origin (default)',
2531
- cookieExpiresInDays: refreshCfg?.cookieExpiresInDays ?? '30 (default)',
2532
- cookiePath: refreshCfg?.cookiePath ?? '/ (default)',
2533
- cookieEnabled: refreshCfg?.cookieEnabled ?? 'true (default)',
2534
- cookieSameSite: refreshCfg?.cookieSameSite ?? 'lax (default)',
2535
- refreshBuffer: refreshCfg?.refreshBuffer ?? '30000 (default)',
2536
- expiresInPropertyName: refreshCfg?.expiresInPropertyName ?? 'exp (default)',
2537
- strategy: refreshCfg?.strategy ?? 'AuthBearerRefreshStrategy.BeforeExpiration (default)',
2538
- requestArgsAdapter: refreshCfg?.requestArgsAdapter ? 'custom' : 'default',
2539
- responseAdapter: refreshCfg?.responseAdapter ? 'custom' : 'default',
2473
+ });
2474
+ this.authProvider = toSignal(toObservable(this.selectedClientConfig).pipe(switchMap((c) => c.client.authProvider$)));
2475
+ this.authProviderDetails = computed(() => {
2476
+ const provider = this.authProvider();
2477
+ if (!provider)
2478
+ return null;
2479
+ if (provider instanceof CustomHeaderAuthProvider) {
2480
+ return {
2481
+ type: 'CustomHeaderAuthProvider',
2482
+ header: () => provider.header,
2483
+ provider: provider,
2484
+ config: {
2485
+ name: provider._config.name,
2486
+ value: provider._config.value,
2540
2487
  },
2541
- },
2542
- };
2543
- }
2544
- else {
2545
- return {
2546
- type: 'UnknownAuthProvider',
2547
- header: () => provider.header,
2548
- provider: provider,
2549
- config: {},
2550
- };
2551
- }
2552
- });
2553
- constructor() {
2488
+ };
2489
+ }
2490
+ else if (provider instanceof BasicAuthProvider) {
2491
+ return {
2492
+ type: 'BasicAuthProvider',
2493
+ header: () => provider.header,
2494
+ provider: provider,
2495
+ config: {
2496
+ username: provider._config.username,
2497
+ password: provider._config.password,
2498
+ },
2499
+ };
2500
+ }
2501
+ else if (isBearerAuthProvider(provider)) {
2502
+ const refreshCfg = provider._config.refreshConfig;
2503
+ return {
2504
+ type: 'BearerAuthProvider',
2505
+ header: () => provider.header,
2506
+ provider: provider,
2507
+ config: {
2508
+ token: provider._config.token,
2509
+ refreshConfig: {
2510
+ refreshOnUnauthorizedResponse: refreshCfg?.refreshOnUnauthorizedResponse ?? 'true (default)',
2511
+ token: refreshCfg?.token,
2512
+ cookieName: refreshCfg?.cookieName,
2513
+ cookieDomain: refreshCfg?.cookieDomain ?? 'current origin (default)',
2514
+ cookieExpiresInDays: refreshCfg?.cookieExpiresInDays ?? '30 (default)',
2515
+ cookiePath: refreshCfg?.cookiePath ?? '/ (default)',
2516
+ cookieEnabled: refreshCfg?.cookieEnabled ?? 'true (default)',
2517
+ cookieSameSite: refreshCfg?.cookieSameSite ?? 'lax (default)',
2518
+ refreshBuffer: refreshCfg?.refreshBuffer ?? '30000 (default)',
2519
+ expiresInPropertyName: refreshCfg?.expiresInPropertyName ?? 'exp (default)',
2520
+ strategy: refreshCfg?.strategy ?? 'AuthBearerRefreshStrategy.BeforeExpiration (default)',
2521
+ requestArgsAdapter: refreshCfg?.requestArgsAdapter ? 'custom' : 'default',
2522
+ responseAdapter: refreshCfg?.responseAdapter ? 'custom' : 'default',
2523
+ },
2524
+ },
2525
+ };
2526
+ }
2527
+ else {
2528
+ return {
2529
+ type: 'UnknownAuthProvider',
2530
+ header: () => provider.header,
2531
+ provider: provider,
2532
+ config: {},
2533
+ };
2534
+ }
2535
+ });
2536
+ this.trackByClient = (_, { client }) => client.config.baseRoute;
2537
+ this.trackByQuery = (_, { _id }) => _id;
2554
2538
  this.selectedClientIdCtrl.valueChanges
2555
2539
  .pipe(tap(() => this.clearQueryHistory()), takeUntil(this._destroy$))
2556
2540
  .subscribe();
@@ -2630,8 +2614,6 @@ class QueryDevtoolsComponent {
2630
2614
  this.viewMode.set(parsed.viewMode ?? 'query');
2631
2615
  }
2632
2616
  }
2633
- trackByClient = (_, { client }) => client.config.baseRoute;
2634
- trackByQuery = (_, { _id }) => _id;
2635
2617
  toggleOpen() {
2636
2618
  this.isOpen.set(!this.isOpen());
2637
2619
  }
@@ -2671,8 +2653,8 @@ class QueryDevtoolsComponent {
2671
2653
  clearQueryHistory() {
2672
2654
  this.queryHistory$.next([]);
2673
2655
  }
2674
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: QueryDevtoolsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2675
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.4", type: QueryDevtoolsComponent, isStandalone: true, selector: "et-query-devtools", host: { classAttribute: "et-query-devtools" }, ngImport: i0, template: "@if (!isOpen()) {\n <button (click)=\"toggleOpen()\" class=\"et-query-devtools-open-btn et-qd-chip\">Query Devtools</button>\n}\n\n@if (isOpen()) {\n <div\n [class.et-query-devtools-container--transparent]=\"isTranslucent()\"\n class=\"et-query-devtools-container et-query-devtools-container--snap-{{ snapLayout() }}\"\n >\n <header class=\"et-qd-header\">\n <h3 class=\"et-qd-header__title\">Query Devtools</h3>\n\n <div class=\"et-qd-header__select\">\n <label for=\"et-query-client-instance\">Client instance</label>\n <select [formControl]=\"selectedClientIdCtrl\" id=\"et-query-client-instance\">\n @for (clientConfig of queryClientConfigs; track trackByClient(i, clientConfig); let i = $index) {\n <option [value]=\"i\">\n {{ clientConfig.displayName ?? clientConfig.client.config.baseRoute }}\n </option>\n }\n </select>\n </div>\n\n <button (click)=\"toggleOpen()\" class=\"et-qd-btn et-qd-btn-secondary\">Close</button>\n </header>\n\n <div class=\"et-qd-sub-header\">\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !isTranslucent() }\"\n (click)=\"toggleTranslucent()\"\n class=\"et-qd-chip et-qd-translucent-clickable\"\n >\n Translucent\n </button>\n <div class=\"et-qd-sub-header__divider\"></div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'full' }\"\n (click)=\"selectSnapLayout('full')\"\n class=\"et-qd-chip\"\n >\n Fullscreen\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'top' }\"\n (click)=\"selectSnapLayout('top')\"\n class=\"et-qd-chip\"\n >\n Top\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'bottom' }\"\n (click)=\"selectSnapLayout('bottom')\"\n class=\"et-qd-chip\"\n >\n Bottom\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'left' }\"\n (click)=\"selectSnapLayout('left')\"\n class=\"et-qd-chip\"\n >\n Left\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'right' }\"\n (click)=\"selectSnapLayout('right')\"\n class=\"et-qd-chip\"\n >\n Right\n </button>\n </div>\n\n @if (selectedClientConfig(); as cfg) {\n <div class=\"et-qd-client\">\n <p class=\"et-qd-client__title\">{{ cfg.displayName ?? cfg.client.config.baseRoute }}</p>\n\n <div class=\"et-qd-client__actions\">\n <button (click)=\"cfg.client._store.refreshQueriesInUse()\" class=\"et-qd-chip\">Refresh all</button>\n <button (click)=\"cfg.client._store.refreshQueriesInUse({ ignoreCacheValidity: true })\" class=\"et-qd-chip\">\n Refresh all (ignore caches)\n </button>\n <button\n (click)=\"cfg.client._store.refreshQueriesInUse({ ignoreCacheValidity: true, purgeUnused: true })\"\n class=\"et-qd-chip\"\n >\n Refresh all (ignore caches & purge unused)\n </button>\n </div>\n </div>\n }\n\n @if (selectedClientConfig(); as cfg) {\n <div class=\"et-qd-queries\">\n <p class=\"et-qd-queries__title\">Inspector</p>\n <div class=\"et-qd-queries__actions\">\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': queryListMode() !== 'live' || viewMode() !== 'query' }\"\n (click)=\"selectQueryListMode('live'); selectViewMode('query')\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Live Queries ({{ queries()?.length ?? 0 }})\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': queryListMode() !== 'history' || viewMode() !== 'query' }\"\n (click)=\"selectQueryListMode('history'); selectViewMode('query')\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Query History ({{ (queryHistory$ | async)?.length ?? 0 }}/50)\n </button>\n @if (queryListMode() === 'history' && viewMode() === 'query') {\n <div class=\"et-qd-queries__divider\"></div>\n <button (click)=\"clearQueryHistory()\" class=\"et-qd-chip et-qd-chip-bordered\">Clear history</button>\n }\n\n <div class=\"et-qd-queries__divider\"></div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': viewMode() !== 'authProvider' }\"\n (click)=\"selectViewMode('authProvider')\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Auth Provider\n </button>\n </div>\n\n @if (viewMode() === 'query') {\n <div class=\"et-qd-queries__browser\">\n @if (queryListMode() === 'live') {\n <ul class=\"et-qd-queries__browser-list\">\n @for (query of queries(); track trackByQuery($index, query)) {\n <li>\n <button\n [class.et-qd-query--active]=\"selectedQuery()?._id === query._id\"\n (click)=\"selectQuery(query)\"\n >\n <span> {{ query._queryConfig.method }}</span>\n <span> {{ query | queryShortName }}</span>\n </button>\n </li>\n }\n </ul>\n }\n @if (queryListMode() === 'history') {\n <ul class=\"et-qd-queries__browser-list\">\n @for (query of queryHistory$ | async; track trackByQuery($index, query)) {\n <li>\n <button\n [class.et-qd-query--active]=\"selectedQuery()?._id === query._id\"\n (click)=\"selectQuery(query)\"\n >\n <span> {{ query._queryConfig.method }}</span>\n <span> {{ query | queryShortName }}</span>\n </button>\n </li>\n }\n </ul>\n }\n <div class=\"et-qd-queries__browser-detail\">\n @if (selectedQuery(); as query) {\n <p class=\"et-qd-queries__browser-detail__title\">\n {{ query._queryConfig.method }} {{ query._routeWithParams }}\n </p>\n\n <div class=\"et-qd-queries__actions\">\n <button (click)=\"query.execute()\" class=\"et-qd-chip et-qd-chip-bordered\">Execute</button>\n <button (click)=\"query.execute({ skipCache: true })\" class=\"et-qd-chip et-qd-chip-bordered\">\n Execute (ignore cache)\n </button>\n\n <button (click)=\"query.abort()\" class=\"et-qd-chip et-qd-chip-bordered\">Abort</button>\n <div class=\"et-qd-queries__divider\"></div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !query.isPolling }\"\n (click)=\"query.poll({ interval: 5000, takeUntil: _destroy$ })\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Poll\n </button>\n\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': query.isPolling }\"\n (click)=\"query.stopPolling()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Stop polling\n </button>\n @if (query.isPolling || query._isPollingPaused) {\n <button (click)=\"query.pausePolling()\" class=\"et-qd-chip et-qd-chip-secondary et-qd-chip-bordered\">\n Pause polling\n </button>\n <button (click)=\"query.resumePolling()\" class=\"et-qd-chip et-qd-chip-secondary et-qd-chip-bordered\">\n Resume polling\n </button>\n }\n </div>\n\n <div class=\"et-qd-list\">\n <div class=\"et-qd-list-item\">\n <p>State type</p>\n <pre>{{ query.rawState.type }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Dependents</p>\n <pre>{{ query._dependents | json }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Is expired</p>\n <pre>{{ query.isExpired }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Is in use</p>\n <pre>{{ query.isInUse }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Subscriber count</p>\n <pre>{{ query._subscriberCount }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Is polling</p>\n <pre>{{ query.isPolling }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Is polling paused</p>\n <pre>{{ query._isPollingPaused }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Enable smart polling</p>\n <pre>{{ query._enableSmartPolling }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Query store key</p>\n <pre>{{ query._queryStoreKey }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Arguments</p>\n\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showArguments() }\"\n (click)=\"toggleShowArguments()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showArguments()) {\n <pre>{{ query._arguments | json }}</pre>\n }\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>State</p>\n <p><i> Warning, this will cause a subscription if shown!</i></p>\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showResponse() }\"\n (click)=\"toggleShowResponse()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showResponse()) {\n <pre>{{ query.state$ | async | json }}</pre>\n }\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Raw state</p>\n <p><i> The query state unaffected by entity stores</i></p>\n\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showRawResponse() }\"\n (click)=\"toggleShowRawResponse()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showRawResponse()) {\n <pre>{{ query.rawState | json }}</pre>\n }\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Query config</p>\n\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showQueryConfig() }\"\n (click)=\"toggleShowQueryConfig()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showQueryConfig()) {\n <pre>{{ stringifiedQueryConfig() | json }}</pre>\n }\n </div>\n\n @if (!!query._queryConfig.entity) {\n <div class=\"et-qd-list-item\">\n <p>Entity store value</p>\n\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showEntityStoreValue() }\"\n (click)=\"toggleShowEntityStoreValue()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showEntityStoreValue()) {\n <pre>{{ selectedQueryEntityStoreValue$ | async | json }}</pre>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n } @else if (viewMode() === 'authProvider') {\n <div class=\"et-qd-auth-provider__viewer\">\n @if (authProviderDetails(); as details) {\n <div class=\"et-qd-list\">\n <div class=\"et-qd-list-item\">\n <p>Type</p>\n <pre>{{ details.type }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>Header value</p>\n <pre>{{ details.header() | json }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>Config</p>\n <pre>{{ details.config | json }}</pre>\n </div>\n\n @if (details.type === 'BearerAuthProvider') {\n <div class=\"et-qd-list-item\">\n <p>Tokens</p>\n <pre>{{ details.provider.tokens$ | async | json }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Should refresh on unauthorized response</p>\n <pre>{{ details.provider.shouldRefreshOnUnauthorizedResponse }}</pre>\n </div>\n\n <ng-container\n *etQuery=\"\n details.provider.currentRefreshQuery$ | async as response;\n loading as loading;\n error as error;\n query as query\n \"\n >\n <div class=\"et-qd-list-item\">\n <p>Refresh query response</p>\n\n <div>\n <button (click)=\"details.provider._refreshQuery()\" class=\"et-qd-chip et-qd-chip-bordered\">\n Refresh\n </button>\n </div>\n <pre>{{ response | json }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>Refresh query loading</p>\n <pre>{{ loading }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>Refresh query error</p>\n <pre>{{ error ?? 'null' }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>State</p>\n <pre>{{ query?.state$ | async | json }}</pre>\n </div>\n </ng-container>\n }\n </div>\n } @else {\n <p>No auth provider set</p>\n }\n </div>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{position:fixed;top:0;z-index:1000000;font-size:14px;color:#fff}.et-query-devtools-container{position:fixed;inset:0;background-color:#25292e;z-index:10000;overflow:auto;font-family:monospace;display:grid;grid-template-rows:auto auto auto minmax(0,1fr)}.et-query-devtools-container.et-query-devtools-container--transparent{opacity:.25;pointer-events:none}.et-query-devtools-container.et-query-devtools-container--transparent .et-query-devtools-translucent-btn{pointer-events:all}.et-query-devtools-container.et-query-devtools-container--snap-left{inset-inline-start:0;inset-block-start:0;inset-block-end:0;width:50%;border-right:1px solid rgb(37,41,46)}.et-query-devtools-container.et-query-devtools-container--snap-right{inset-inline-start:unset;inset-inline-end:0;inset-block-start:0;inset-block-end:0;width:50%;border-left:1px solid rgb(37,41,46)}.et-query-devtools-container.et-query-devtools-container--snap-top{inset-inline-start:0;inset-block-start:0;inset-inline-end:0;height:50%;border-bottom:1px solid rgb(37,41,46)}.et-query-devtools-container.et-query-devtools-container--snap-bottom{inset-inline-start:0;inset-block-start:unset;inset-block-end:0;inset-inline-end:0;height:50%;border-top:1px solid rgb(37,41,46)}button.et-query-devtools-open-btn{position:fixed;inset-inline-end:20px;inset-block-end:0;z-index:9999;font-family:monospace;border-radius:3px 3px 0 0;line-height:14px;font-size:12px}.et-qd-header{background-color:#00ffa1;padding:12px;display:grid;grid-template-columns:1fr auto auto;gap:12px;align-items:center}.et-qd-header__title{color:#25292e;margin:0;font-size:22px}.et-qd-header__select{display:grid;background-color:#25292e;border-radius:10px;overflow:hidden}.et-qd-header__select select{width:250px;color:#fff;padding:3px 10px 2px;border:none;background-color:#25292e;font-family:monospace}.et-qd-header__select label{padding:3px 10px;color:#25292e;font-size:12px;font-weight:700;color:#fff;border-bottom:1px solid gray}.et-qd-sub-header{background-color:#00b371;padding:12px;display:flex;gap:12px;flex-wrap:wrap}.et-qd-sub-header__divider{width:1px;background-color:#25292e}.et-qd-btn{background-color:#00ffa1;color:#25292e;border:none;padding:12px;cursor:pointer;font-size:14px;font-weight:700;text-align:center;text-decoration:none;display:inline-block;width:100%;transition:all .3s ease-in-out;font-family:monospace;border-radius:10px}.et-qd-btn:hover{background-color:#00cc81}.et-qd-btn.et-qd-btn-secondary{background-color:#25292e;color:#00ffa1}.et-qd-btn.et-qd-btn-secondary:hover{background-color:#3c424a}.et-qd-chip{background-color:#00ffa1;color:#25292e;border:none;padding:4px 9px;cursor:pointer;font-size:12px;font-weight:700;text-align:center;text-decoration:none;display:inline-block;transition:all .3s ease-in-out;font-family:monospace;border-radius:10px}.et-qd-chip:hover{background-color:#00cc81}.et-qd-chip.et-qd-chip-secondary{background-color:#25292e;color:#00ffa1}.et-qd-chip.et-qd-chip-secondary:hover{background-color:#3c424a}.et-qd-chip.et-qd-chip-bordered{border:1px solid rgb(0,255,161)}.et-qd-translucent-clickable{pointer-events:all}.et-qd-client{border-bottom:1px solid rgb(59.734939759,66.1927710843,74.265060241);padding:12px}.et-qd-client__title{margin:0;font-size:14px;color:#fff;font-weight:700}.et-qd-client__actions{display:flex;gap:12px;margin-top:12px}.et-qd-queries{padding:12px;display:grid;grid-template-rows:auto auto minmax(0,1fr)}.et-qd-queries__actions{display:flex;gap:12px;margin-top:12px;margin-bottom:16px}.et-qd-queries__title{margin:0;font-size:14px;color:#fff;font-weight:700}.et-qd-queries__divider{width:1px;background-color:#3c424a}.et-qd-queries__browser{display:grid;grid-template-columns:1fr minmax(0,3fr);margin-left:-12px;margin-right:-12px;border-top:1px solid rgb(59.734939759,66.1927710843,74.265060241);margin-bottom:-12px}.et-qd-queries__browser-list{border-right:1px solid rgb(59.734939759,66.1927710843,74.265060241);list-style:none;padding:0;margin:0;display:grid;grid-auto-flow:row;grid-auto-rows:55px;overflow-y:auto;overflow-x:hidden}.et-qd-queries__browser-list li{margin:0}.et-qd-queries__browser-list li button{all:unset;font-family:monospace;box-sizing:border-box;width:100%;border:none;border-bottom:1px solid rgb(59.734939759,66.1927710843,74.265060241);background-color:#25292e;color:#fff;text-align:left;padding:12px;height:100%;transition:all .3s ease-in-out;cursor:pointer;display:grid;grid-template-columns:auto minmax(0,1fr);gap:2px;display:block}.et-qd-queries__browser-list li button span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.et-qd-queries__browser-list li button span:first-of-type{font-weight:700}.et-qd-queries__browser-list li button:hover,.et-qd-queries__browser-list li button.et-qd-query--active{background-color:#30363c}.et-qd-queries__browser-detail{padding:12px;overflow-y:auto;overflow-x:hidden}.et-qd-queries__browser-detail__title{margin:0;font-size:14px;color:#fff;font-weight:700}.et-qd-auth-provider__viewer{border-top:1px solid rgb(59.734939759,66.1927710843,74.265060241);margin-left:-12px;margin-right:-12px;margin-bottom:-12px;padding:12px;overflow-y:auto;overflow-x:hidden}.et-qd-list{display:grid;gap:12px}.et-qd-list-item{display:grid}.et-qd-list-item p{font-weight:700;margin:0;padding-bottom:8px}.et-qd-list-item p+p{margin-top:-8px}.et-qd-list-item div+pre{margin-top:8px}.et-qd-list-item pre{margin:0;padding:4px;background-color:#0e1012;border-radius:4px;max-height:450px;overflow:auto}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: QueryShortNamePipe, name: "queryShortName" }, { kind: "directive", type: QueryDirective, selector: "[etQuery]", inputs: ["etQuery", "etQueryCache"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
2656
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: QueryDevtoolsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2657
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.4", type: QueryDevtoolsComponent, isStandalone: true, selector: "et-query-devtools", host: { classAttribute: "et-query-devtools" }, ngImport: i0, template: "@if (!isOpen()) {\n <button (click)=\"toggleOpen()\" class=\"et-query-devtools-open-btn et-qd-chip\">Query Devtools</button>\n}\n\n@if (isOpen()) {\n <div\n [class.et-query-devtools-container--transparent]=\"isTranslucent()\"\n class=\"et-query-devtools-container et-query-devtools-container--snap-{{ snapLayout() }}\"\n >\n <header class=\"et-qd-header\">\n <h3 class=\"et-qd-header__title\">Query Devtools</h3>\n\n <div class=\"et-qd-header__select\">\n <label for=\"et-query-client-instance\">Client instance</label>\n <select [formControl]=\"selectedClientIdCtrl\" id=\"et-query-client-instance\">\n @for (clientConfig of queryClientConfigs; track trackByClient(i, clientConfig); let i = $index) {\n <option [value]=\"i\">\n {{ clientConfig.displayName ?? clientConfig.client.config.baseRoute }}\n </option>\n }\n </select>\n </div>\n\n <button (click)=\"toggleOpen()\" class=\"et-qd-btn et-qd-btn-secondary\">Close</button>\n </header>\n\n <div class=\"et-qd-sub-header\">\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !isTranslucent() }\"\n (click)=\"toggleTranslucent()\"\n class=\"et-qd-chip et-qd-translucent-clickable\"\n >\n Translucent\n </button>\n <div class=\"et-qd-sub-header__divider\"></div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'full' }\"\n (click)=\"selectSnapLayout('full')\"\n class=\"et-qd-chip\"\n >\n Fullscreen\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'top' }\"\n (click)=\"selectSnapLayout('top')\"\n class=\"et-qd-chip\"\n >\n Top\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'bottom' }\"\n (click)=\"selectSnapLayout('bottom')\"\n class=\"et-qd-chip\"\n >\n Bottom\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'left' }\"\n (click)=\"selectSnapLayout('left')\"\n class=\"et-qd-chip\"\n >\n Left\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'right' }\"\n (click)=\"selectSnapLayout('right')\"\n class=\"et-qd-chip\"\n >\n Right\n </button>\n </div>\n\n @if (selectedClientConfig(); as cfg) {\n <div class=\"et-qd-client\">\n <p class=\"et-qd-client__title\">{{ cfg.displayName ?? cfg.client.config.baseRoute }}</p>\n\n <div class=\"et-qd-client__actions\">\n <button (click)=\"cfg.client._store.refreshQueriesInUse()\" class=\"et-qd-chip\">Refresh all</button>\n <button (click)=\"cfg.client._store.refreshQueriesInUse({ ignoreCacheValidity: true })\" class=\"et-qd-chip\">\n Refresh all (ignore caches)\n </button>\n <button\n (click)=\"cfg.client._store.refreshQueriesInUse({ ignoreCacheValidity: true, purgeUnused: true })\"\n class=\"et-qd-chip\"\n >\n Refresh all (ignore caches & purge unused)\n </button>\n </div>\n </div>\n }\n\n @if (selectedClientConfig(); as cfg) {\n <div class=\"et-qd-queries\">\n <p class=\"et-qd-queries__title\">Inspector</p>\n <div class=\"et-qd-queries__actions\">\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': queryListMode() !== 'live' || viewMode() !== 'query' }\"\n (click)=\"selectQueryListMode('live'); selectViewMode('query')\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Live Queries ({{ queries()?.length ?? 0 }})\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': queryListMode() !== 'history' || viewMode() !== 'query' }\"\n (click)=\"selectQueryListMode('history'); selectViewMode('query')\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Query History ({{ (queryHistory$ | async)?.length ?? 0 }}/50)\n </button>\n @if (queryListMode() === 'history' && viewMode() === 'query') {\n <div class=\"et-qd-queries__divider\"></div>\n <button (click)=\"clearQueryHistory()\" class=\"et-qd-chip et-qd-chip-bordered\">Clear history</button>\n }\n\n <div class=\"et-qd-queries__divider\"></div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': viewMode() !== 'authProvider' }\"\n (click)=\"selectViewMode('authProvider')\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Auth Provider\n </button>\n </div>\n\n @if (viewMode() === 'query') {\n <div class=\"et-qd-queries__browser\">\n @if (queryListMode() === 'live') {\n <ul class=\"et-qd-queries__browser-list\">\n @for (query of queries(); track trackByQuery($index, query)) {\n <li>\n <button\n [class.et-qd-query--active]=\"selectedQuery()?._id === query._id\"\n (click)=\"selectQuery(query)\"\n >\n <span> {{ query._queryConfig.method }}</span>\n <span> {{ query | queryShortName }}</span>\n </button>\n </li>\n }\n </ul>\n }\n @if (queryListMode() === 'history') {\n <ul class=\"et-qd-queries__browser-list\">\n @for (query of queryHistory$ | async; track trackByQuery($index, query)) {\n <li>\n <button\n [class.et-qd-query--active]=\"selectedQuery()?._id === query._id\"\n (click)=\"selectQuery(query)\"\n >\n <span> {{ query._queryConfig.method }}</span>\n <span> {{ query | queryShortName }}</span>\n </button>\n </li>\n }\n </ul>\n }\n <div class=\"et-qd-queries__browser-detail\">\n @if (selectedQuery(); as query) {\n <p class=\"et-qd-queries__browser-detail__title\">\n {{ query._queryConfig.method }} {{ query._routeWithParams }}\n </p>\n\n <div class=\"et-qd-queries__actions\">\n <button (click)=\"query.execute()\" class=\"et-qd-chip et-qd-chip-bordered\">Execute</button>\n <button (click)=\"query.execute({ skipCache: true })\" class=\"et-qd-chip et-qd-chip-bordered\">\n Execute (ignore cache)\n </button>\n\n <button (click)=\"query.abort()\" class=\"et-qd-chip et-qd-chip-bordered\">Abort</button>\n <div class=\"et-qd-queries__divider\"></div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !query.isPolling }\"\n (click)=\"query.poll({ interval: 5000, takeUntil: _destroy$ })\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Poll\n </button>\n\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': query.isPolling }\"\n (click)=\"query.stopPolling()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Stop polling\n </button>\n @if (query.isPolling || query._isPollingPaused) {\n <button (click)=\"query.pausePolling()\" class=\"et-qd-chip et-qd-chip-secondary et-qd-chip-bordered\">\n Pause polling\n </button>\n <button (click)=\"query.resumePolling()\" class=\"et-qd-chip et-qd-chip-secondary et-qd-chip-bordered\">\n Resume polling\n </button>\n }\n </div>\n\n <div class=\"et-qd-list\">\n <div class=\"et-qd-list-item\">\n <p>State type</p>\n <pre>{{ query.rawState.type }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Dependents</p>\n <pre>{{ query._dependents | json }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Is expired</p>\n <pre>{{ query.isExpired }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Is in use</p>\n <pre>{{ query.isInUse }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Subscriber count</p>\n <pre>{{ query._subscriberCount }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Is polling</p>\n <pre>{{ query.isPolling }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Is polling paused</p>\n <pre>{{ query._isPollingPaused }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Enable smart polling</p>\n <pre>{{ query._enableSmartPolling }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Query store key</p>\n <pre>{{ query._queryStoreKey }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Arguments</p>\n\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showArguments() }\"\n (click)=\"toggleShowArguments()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showArguments()) {\n <pre>{{ query._arguments | json }}</pre>\n }\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>State</p>\n <p><i> Warning, this will cause a subscription if shown!</i></p>\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showResponse() }\"\n (click)=\"toggleShowResponse()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showResponse()) {\n <pre>{{ query.state$ | async | json }}</pre>\n }\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Raw state</p>\n <p><i> The query state unaffected by entity stores</i></p>\n\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showRawResponse() }\"\n (click)=\"toggleShowRawResponse()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showRawResponse()) {\n <pre>{{ query.rawState | json }}</pre>\n }\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Query config</p>\n\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showQueryConfig() }\"\n (click)=\"toggleShowQueryConfig()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showQueryConfig()) {\n <pre>{{ stringifiedQueryConfig() | json }}</pre>\n }\n </div>\n\n @if (!!query._queryConfig.entity) {\n <div class=\"et-qd-list-item\">\n <p>Entity store value</p>\n\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showEntityStoreValue() }\"\n (click)=\"toggleShowEntityStoreValue()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showEntityStoreValue()) {\n <pre>{{ selectedQueryEntityStoreValue$ | async | json }}</pre>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n } @else if (viewMode() === 'authProvider') {\n <div class=\"et-qd-auth-provider__viewer\">\n @if (authProviderDetails(); as details) {\n <div class=\"et-qd-list\">\n <div class=\"et-qd-list-item\">\n <p>Type</p>\n <pre>{{ details.type }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>Header value</p>\n <pre>{{ details.header() | json }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>Config</p>\n <pre>{{ details.config | json }}</pre>\n </div>\n\n @if (details.type === 'BearerAuthProvider') {\n <div class=\"et-qd-list-item\">\n <p>Tokens</p>\n <pre>{{ details.provider.tokens$ | async | json }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Should refresh on unauthorized response</p>\n <pre>{{ details.provider.shouldRefreshOnUnauthorizedResponse }}</pre>\n </div>\n\n <ng-container\n *etQuery=\"\n details.provider.currentRefreshQuery$ | async as response;\n loading as loading;\n error as error;\n query as query\n \"\n >\n <div class=\"et-qd-list-item\">\n <p>Refresh query response</p>\n\n <div>\n <button (click)=\"details.provider._refreshQuery()\" class=\"et-qd-chip et-qd-chip-bordered\">\n Refresh\n </button>\n </div>\n <pre>{{ response | json }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>Refresh query loading</p>\n <pre>{{ loading }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>Refresh query error</p>\n <pre>{{ error ?? 'null' }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>State</p>\n <pre>{{ query?.state$ | async | json }}</pre>\n </div>\n </ng-container>\n }\n </div>\n } @else {\n <p>No auth provider set</p>\n }\n </div>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{position:fixed;top:0;z-index:1000000;font-size:14px;color:#fff}.et-query-devtools-container{position:fixed;inset:0;background-color:#25292e;z-index:10000;overflow:auto;font-family:monospace;display:grid;grid-template-rows:auto auto auto minmax(0,1fr)}.et-query-devtools-container.et-query-devtools-container--transparent{opacity:.25;pointer-events:none}.et-query-devtools-container.et-query-devtools-container--transparent .et-query-devtools-translucent-btn{pointer-events:all}.et-query-devtools-container.et-query-devtools-container--snap-left{inset-inline-start:0;inset-block-start:0;inset-block-end:0;width:50%;border-right:1px solid rgb(37,41,46)}.et-query-devtools-container.et-query-devtools-container--snap-right{inset-inline-start:unset;inset-inline-end:0;inset-block-start:0;inset-block-end:0;width:50%;border-left:1px solid rgb(37,41,46)}.et-query-devtools-container.et-query-devtools-container--snap-top{inset-inline-start:0;inset-block-start:0;inset-inline-end:0;height:50%;border-bottom:1px solid rgb(37,41,46)}.et-query-devtools-container.et-query-devtools-container--snap-bottom{inset-inline-start:0;inset-block-start:unset;inset-block-end:0;inset-inline-end:0;height:50%;border-top:1px solid rgb(37,41,46)}button.et-query-devtools-open-btn{position:fixed;inset-inline-end:20px;inset-block-end:0;z-index:9999;font-family:monospace;border-radius:3px 3px 0 0;line-height:14px;font-size:12px}.et-qd-header{background-color:#00ffa1;padding:12px;display:grid;grid-template-columns:1fr auto auto;gap:12px;align-items:center}.et-qd-header__title{color:#25292e;margin:0;font-size:22px}.et-qd-header__select{display:grid;background-color:#25292e;border-radius:10px;overflow:hidden}.et-qd-header__select select{width:250px;color:#fff;padding:3px 10px 2px;border:none;background-color:#25292e;font-family:monospace}.et-qd-header__select label{padding:3px 10px;color:#25292e;font-size:12px;font-weight:700;color:#fff;border-bottom:1px solid gray}.et-qd-sub-header{background-color:#00b371;padding:12px;display:flex;gap:12px;flex-wrap:wrap}.et-qd-sub-header__divider{width:1px;background-color:#25292e}.et-qd-btn{background-color:#00ffa1;color:#25292e;border:none;padding:12px;cursor:pointer;font-size:14px;font-weight:700;text-align:center;text-decoration:none;display:inline-block;width:100%;transition:all .3s ease-in-out;font-family:monospace;border-radius:10px}.et-qd-btn:hover{background-color:#00cc81}.et-qd-btn.et-qd-btn-secondary{background-color:#25292e;color:#00ffa1}.et-qd-btn.et-qd-btn-secondary:hover{background-color:#3c424a}.et-qd-chip{background-color:#00ffa1;color:#25292e;border:none;padding:4px 9px;cursor:pointer;font-size:12px;font-weight:700;text-align:center;text-decoration:none;display:inline-block;transition:all .3s ease-in-out;font-family:monospace;border-radius:10px}.et-qd-chip:hover{background-color:#00cc81}.et-qd-chip.et-qd-chip-secondary{background-color:#25292e;color:#00ffa1}.et-qd-chip.et-qd-chip-secondary:hover{background-color:#3c424a}.et-qd-chip.et-qd-chip-bordered{border:1px solid rgb(0,255,161)}.et-qd-translucent-clickable{pointer-events:all}.et-qd-client{border-bottom:1px solid rgb(59.734939759,66.1927710843,74.265060241);padding:12px}.et-qd-client__title{margin:0;font-size:14px;color:#fff;font-weight:700}.et-qd-client__actions{display:flex;gap:12px;margin-top:12px}.et-qd-queries{padding:12px;display:grid;grid-template-rows:auto auto minmax(0,1fr)}.et-qd-queries__actions{display:flex;gap:12px;margin-top:12px;margin-bottom:16px}.et-qd-queries__title{margin:0;font-size:14px;color:#fff;font-weight:700}.et-qd-queries__divider{width:1px;background-color:#3c424a}.et-qd-queries__browser{display:grid;grid-template-columns:1fr minmax(0,3fr);margin-left:-12px;margin-right:-12px;border-top:1px solid rgb(59.734939759,66.1927710843,74.265060241);margin-bottom:-12px}.et-qd-queries__browser-list{border-right:1px solid rgb(59.734939759,66.1927710843,74.265060241);list-style:none;padding:0;margin:0;display:grid;grid-auto-flow:row;grid-auto-rows:55px;overflow-y:auto;overflow-x:hidden}.et-qd-queries__browser-list li{margin:0}.et-qd-queries__browser-list li button{all:unset;font-family:monospace;box-sizing:border-box;width:100%;border:none;border-bottom:1px solid rgb(59.734939759,66.1927710843,74.265060241);background-color:#25292e;color:#fff;text-align:left;padding:12px;height:100%;transition:all .3s ease-in-out;cursor:pointer;display:grid;grid-template-columns:auto minmax(0,1fr);gap:2px;display:block}.et-qd-queries__browser-list li button span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.et-qd-queries__browser-list li button span:first-of-type{font-weight:700}.et-qd-queries__browser-list li button:hover,.et-qd-queries__browser-list li button.et-qd-query--active{background-color:#30363c}.et-qd-queries__browser-detail{padding:12px;overflow-y:auto;overflow-x:hidden}.et-qd-queries__browser-detail__title{margin:0;font-size:14px;color:#fff;font-weight:700}.et-qd-auth-provider__viewer{border-top:1px solid rgb(59.734939759,66.1927710843,74.265060241);margin-left:-12px;margin-right:-12px;margin-bottom:-12px;padding:12px;overflow-y:auto;overflow-x:hidden}.et-qd-list{display:grid;gap:12px}.et-qd-list-item{display:grid}.et-qd-list-item p{font-weight:700;margin:0;padding-bottom:8px}.et-qd-list-item p+p{margin-top:-8px}.et-qd-list-item div+pre{margin-top:8px}.et-qd-list-item pre{margin:0;padding:4px;background-color:#0e1012;border-radius:4px;max-height:450px;overflow:auto}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: QueryShortNamePipe, name: "queryShortName" }, { kind: "directive", type: QueryDirective, selector: "[etQuery]", inputs: ["etQuery", "etQueryCache"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom }); }
2676
2658
  }
2677
2659
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: QueryDevtoolsComponent, decorators: [{
2678
2660
  type: Component,
@@ -2682,7 +2664,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImpor
2682
2664
  }], ctorParameters: () => [] });
2683
2665
 
2684
2666
  class EntityStoreError extends Error {
2685
- detail;
2686
2667
  constructor(message, detail) {
2687
2668
  super(message);
2688
2669
  this.detail = detail;
@@ -2693,17 +2674,16 @@ function flatten(arr) {
2693
2674
  return arr.reduce((acc, val) => acc.concat(val), []);
2694
2675
  }
2695
2676
  class EntityStore {
2696
- _config;
2697
- /**
2698
- * @internal
2699
- */
2700
- _dictionary = new Map();
2701
- /**
2702
- * @internal
2703
- */
2704
- _change$ = new Subject();
2705
2677
  constructor(_config) {
2706
2678
  this._config = _config;
2679
+ /**
2680
+ * @internal
2681
+ */
2682
+ this._dictionary = new Map();
2683
+ /**
2684
+ * @internal
2685
+ */
2686
+ this._change$ = new Subject();
2707
2687
  }
2708
2688
  select(keyOrKeys) {
2709
2689
  if (Array.isArray(keyOrKeys)) {
@@ -2907,6 +2887,9 @@ const pagedQueryStackPreviousPageCalledButAlreadyAtFirstPage = () => {
2907
2887
  const queryStackWithArgsUsed = () => {
2908
2888
  return new RuntimeError(500 /* QueryRuntimeErrorCode.QUERY_STACK_WITH_ARGS_USED */, `withArgs() has been used in a query stack or a paged query stack. This is not supported.`);
2909
2889
  };
2890
+ const queryStackWithResponseUpdateUsed = () => {
2891
+ return new RuntimeError(501 /* QueryRuntimeErrorCode.QUERY_STACK_WITH_RESPONSE_UPDATE_USED */, `withResponseUpdate() has been used in a query stack or a paged query stack. This is not supported.`);
2892
+ };
2910
2893
 
2911
2894
  const defaultResponseTransformer = (response) => {
2912
2895
  if (!isObject(response)) {
@@ -2963,6 +2946,7 @@ const createAuthProviderQuery = (config, authProviderConfig) => {
2963
2946
  };
2964
2947
  };
2965
2948
  const createBearerAuthProvider = (options) => {
2949
+ const route = injectRoute();
2966
2950
  const cookieEnabled = signal(options.cookie === undefined ? false : (options.cookie.enabled ?? true));
2967
2951
  const cookieOptions = {
2968
2952
  expiresInDays: 30,
@@ -2971,6 +2955,7 @@ const createBearerAuthProvider = (options) => {
2971
2955
  sameSite: 'lax',
2972
2956
  domain: getDomain() ?? 'localhost',
2973
2957
  refreshArgsTransformer: (token) => ({ body: { token } }),
2958
+ autoLoginExcludeRoutes: [],
2974
2959
  ...(options.cookie ?? {}),
2975
2960
  };
2976
2961
  const loginQuery = options.login ? createAuthProviderQuery(options.login, options) : null;
@@ -3135,7 +3120,9 @@ const createBearerAuthProvider = (options) => {
3135
3120
  tokens,
3136
3121
  };
3137
3122
  if (cookieEnabled()) {
3138
- tryLoginWithCookie();
3123
+ if (!cookieOptions.autoLoginExcludeRoutes.some((r) => route().startsWith(r))) {
3124
+ tryLoginWithCookie();
3125
+ }
3139
3126
  }
3140
3127
  return bearerAuthProvider;
3141
3128
  };
@@ -3171,6 +3158,7 @@ const setupQueryState = (options) => {
3171
3158
  const error = signal(null);
3172
3159
  const loading = signal(null);
3173
3160
  const lastTimeExecutedAt = signal(null);
3161
+ const request = signal(null);
3174
3162
  const state = {
3175
3163
  response,
3176
3164
  args,
@@ -3178,6 +3166,9 @@ const setupQueryState = (options) => {
3178
3166
  loading,
3179
3167
  error,
3180
3168
  lastTimeExecutedAt,
3169
+ subtle: {
3170
+ request,
3171
+ },
3181
3172
  };
3182
3173
  return state;
3183
3174
  };
@@ -3389,6 +3380,7 @@ const maybeExecute = (options) => {
3389
3380
  const createQueryObject = (options) => {
3390
3381
  const { state, execute, deps } = options;
3391
3382
  const destroy = () => deps.injector.destroy();
3383
+ const setResponse = (response) => state.response.set(response);
3392
3384
  const createSnapshot = createQuerySnapshotFn({ state, deps, execute });
3393
3385
  const query = {
3394
3386
  execute,
@@ -3403,6 +3395,7 @@ const createQueryObject = (options) => {
3403
3395
  reset: execute.reset,
3404
3396
  subtle: {
3405
3397
  destroy,
3398
+ setResponse,
3406
3399
  },
3407
3400
  };
3408
3401
  return query;
@@ -3734,6 +3727,22 @@ const withAutoRefresh = (options) => {
3734
3727
  },
3735
3728
  });
3736
3729
  };
3730
+ const withResponseUpdate = (options) => {
3731
+ return createQueryFeature({
3732
+ type: "withResponseUpdate" /* QueryFeatureType.WithResponseUpdate */,
3733
+ fn: (context) => {
3734
+ queryEffect(() => {
3735
+ const currentResponse = untracked(() => context.state.response());
3736
+ const response = options.updater({ currentResponse });
3737
+ if (response === null)
3738
+ return;
3739
+ untracked(() => {
3740
+ context.state.response.set(response);
3741
+ });
3742
+ }, QUERY_EFFECT_ERROR_MESSAGE, { injector: context.deps.injector });
3743
+ },
3744
+ });
3745
+ };
3737
3746
 
3738
3747
  /** Transforms an array of arrays into a single array and filters out `null` values. */
3739
3748
  const transformArrayResponse = (responses) => responses.filter((r) => !!r).flatMap((r) => r);
@@ -3749,9 +3758,13 @@ const createQueryStack = (options) => {
3749
3758
  const queries = signal([]);
3750
3759
  const lastQuery = signal(null);
3751
3760
  const hasWithArgsFeature = features.some((f) => f.type == "withArgs" /* QueryFeatureType.WithArgs */);
3761
+ const hasWithOptimisticUpdateFeature = features.some((f) => f.type == "withResponseUpdate" /* QueryFeatureType.WithResponseUpdate */);
3752
3762
  if (hasWithArgsFeature) {
3753
3763
  throw queryStackWithArgsUsed();
3754
3764
  }
3765
+ if (hasWithOptimisticUpdateFeature) {
3766
+ throw queryStackWithResponseUpdateUsed();
3767
+ }
3755
3768
  effect(() => {
3756
3769
  // Clear the stack if dependencies change
3757
3770
  dependencies?.();
@@ -4105,6 +4118,7 @@ const queryExecute = (options) => {
4105
4118
  executeState.effectRefs.push(responseRef, loadingRef, errorRef, latestHttpEventRef);
4106
4119
  });
4107
4120
  state.lastTimeExecutedAt.set(Date.now());
4121
+ state.subtle.request.set(request);
4108
4122
  };
4109
4123
  const cleanupPreviousExecute = (options) => {
4110
4124
  const { executeState } = options;
@@ -4555,70 +4569,77 @@ const createGqlMutationViaPost = (client) => {
4555
4569
  return (creatorOptions) => createGqlQueryCreator(creatorOptions, { method: 'MUTATE', client, transport: 'POST' });
4556
4570
  };
4557
4571
 
4558
- const roomAlreadyJoined = (room) => {
4559
- return new RuntimeError(1000 /* QueryRuntimeErrorCode.ROOM_ALREADY_JOINED */, `Tried joining the room "${room}" but it has already been joined.`);
4560
- };
4561
4572
  const roomNotJoined = (room) => {
4562
- return new RuntimeError(1001 /* QueryRuntimeErrorCode.ROOM_NOT_JOINED */, `Tried leaving the room "${room}" but it has not been joined.`);
4573
+ return new RuntimeError(1000 /* WebSocketRuntimeErrorCode.ROOM_NOT_JOINED */, `Tried leaving the room "${room}" but it has not been joined.`);
4563
4574
  };
4564
4575
  const messageMalformed = () => {
4565
- return new RuntimeError(1002 /* QueryRuntimeErrorCode.MESSAGE_MALFORMED */, 'A message has been received but it is malformed (cannot be parsed as JSON).');
4576
+ return new RuntimeError(1001 /* WebSocketRuntimeErrorCode.MESSAGE_MALFORMED */, 'A message has been received but it is malformed (cannot be parsed as JSON).');
4566
4577
  };
4567
4578
 
4568
4579
  const createWebSocketClient = (config) => {
4569
- const joinedRooms = new Set();
4570
4580
  const socket = io(config.url, {
4571
4581
  withCredentials: true,
4572
4582
  autoConnect: false,
4573
4583
  });
4574
- const currentEvent = signal(null);
4584
+ const rooms = new Map();
4575
4585
  const isConnected = signal(false);
4576
4586
  const joinRoom = (room) => {
4577
- if (joinedRooms.has(room)) {
4578
- if (isDevMode())
4579
- throw roomAlreadyJoined(room);
4580
- return;
4581
- }
4582
- socket.emit('join-room', room);
4583
- joinedRooms.add(room);
4584
- };
4585
- const joinComputedRoom = (room) => {
4586
- const pre = previousSignalValue(computed(() => room()));
4587
+ const roomFn = typeof room === 'function' ? room : () => room;
4588
+ const join = (name) => {
4589
+ socket.emit('join-room', name);
4590
+ const existingRoom = rooms.get(name);
4591
+ if (existingRoom)
4592
+ return existingRoom;
4593
+ const message = signal(null);
4594
+ const newRoom = {
4595
+ latestMessage: message,
4596
+ };
4597
+ rooms.set(name, newRoom);
4598
+ return newRoom;
4599
+ };
4600
+ const pre = previousSignalValue(computed(() => roomFn()));
4601
+ const roomData = signal(null);
4587
4602
  effect(() => {
4588
- const current = room();
4603
+ const current = roomFn();
4589
4604
  untracked(() => {
4590
4605
  const previous = pre();
4591
4606
  if (previous === current)
4592
4607
  return;
4593
4608
  if (previous)
4594
4609
  leaveRoom(previous);
4595
- if (current)
4596
- joinRoom(current);
4610
+ if (current) {
4611
+ const joinedRoom = join(current);
4612
+ if (joinedRoom)
4613
+ roomData.set(joinedRoom);
4614
+ }
4615
+ else {
4616
+ roomData.set(null);
4617
+ }
4597
4618
  });
4598
4619
  });
4599
4620
  inject(DestroyRef).onDestroy(() => {
4600
- const current = room();
4601
- if (current)
4621
+ const current = roomFn();
4622
+ if (current) {
4602
4623
  leaveRoom(current);
4624
+ roomData.set(null);
4625
+ }
4603
4626
  });
4627
+ return roomData.asReadonly();
4604
4628
  };
4605
4629
  const leaveRoom = (room) => {
4606
- if (!joinedRooms.has(room)) {
4630
+ if (!rooms.has(room)) {
4607
4631
  if (isDevMode())
4608
4632
  throw roomNotJoined(room);
4609
- return;
4610
4633
  }
4611
4634
  socket.emit('leave-room', room);
4612
- joinedRooms.delete(room);
4613
- };
4614
- const leaveAllRooms = () => {
4615
- joinedRooms.forEach((room) => leaveRoom(room));
4616
- joinedRooms.clear();
4635
+ rooms.delete(room);
4617
4636
  };
4618
4637
  const setupWebSocketConnectionListener = () => {
4619
4638
  socket.on('connect', () => {
4620
4639
  isConnected.set(true);
4621
- joinedRooms.forEach((room) => joinRoom(room));
4640
+ for (const room of rooms.keys()) {
4641
+ joinRoom(room);
4642
+ }
4622
4643
  });
4623
4644
  socket.on('disconnect', () => isConnected.set(false));
4624
4645
  };
@@ -4626,7 +4647,9 @@ const createWebSocketClient = (config) => {
4626
4647
  socket.onAny((data) => {
4627
4648
  try {
4628
4649
  const json = JSON.parse(data);
4629
- currentEvent.set(json);
4650
+ const room = rooms.get(json.room);
4651
+ if (room)
4652
+ room.latestMessage.set(json);
4630
4653
  }
4631
4654
  catch (error) {
4632
4655
  console.error(error);
@@ -4641,11 +4664,10 @@ const createWebSocketClient = (config) => {
4641
4664
  socket.connect();
4642
4665
  const client = {
4643
4666
  joinRoom,
4644
- joinComputedRoom,
4645
- leaveRoom,
4646
- leaveAllRooms,
4647
- currentEvent: currentEvent.asReadonly(),
4648
4667
  isConnected: isConnected.asReadonly(),
4668
+ subtle: {
4669
+ leaveRoom,
4670
+ },
4649
4671
  };
4650
4672
  return client;
4651
4673
  };
@@ -4738,6 +4760,7 @@ var index = /*#__PURE__*/Object.freeze({
4738
4760
  queryExecute: queryExecute,
4739
4761
  queryFeatureUsedMultipleTimes: queryFeatureUsedMultipleTimes,
4740
4762
  queryStackWithArgsUsed: queryStackWithArgsUsed,
4763
+ queryStackWithResponseUpdateUsed: queryStackWithResponseUpdateUsed,
4741
4764
  refreshTokenCalledWithoutConfig: refreshTokenCalledWithoutConfig,
4742
4765
  resetExecuteState: resetExecuteState,
4743
4766
  selectRoleCalledWithoutConfig: selectRoleCalledWithoutConfig,
@@ -4763,6 +4786,7 @@ var index = /*#__PURE__*/Object.freeze({
4763
4786
  withLogging: withLogging,
4764
4787
  withPolling: withPolling,
4765
4788
  withPollingUsedOnUnsupportedHttpMethod: withPollingUsedOnUnsupportedHttpMethod,
4789
+ withResponseUpdate: withResponseUpdate,
4766
4790
  withSuccessHandling: withSuccessHandling
4767
4791
  });
4768
4792
 
@@ -4865,7 +4889,6 @@ const transformToSortQueryParam = (value) => {
4865
4889
 
4866
4890
  const ET_ARR_PREFIX = 'ET_ARR__';
4867
4891
  class QueryField {
4868
- data;
4869
4892
  get control() {
4870
4893
  return this.data.control;
4871
4894
  }
@@ -4876,70 +4899,12 @@ class QueryField {
4876
4899
  const IGNORED_FILTER_COUNT_FIELDS = ['page', 'skip', 'take', 'limit', 'sort', 'sortBy', 'sortOrder', 'query', 'search'];
4877
4900
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
4878
4901
  class QueryForm {
4879
- _fields;
4880
- _options;
4881
- _destroy$ = createDestroy();
4882
- _unobserveTrigger$ = new Subject();
4883
- _router = inject(Router);
4884
- _activatedRoute = inject(ActivatedRoute);
4885
- _defaultValues = this._extractDefaultValues();
4886
- _zone = inject(NgZone);
4887
- _didValueChanges$ = new Subject();
4888
- _isObserving = false;
4889
- _skipNextResets = false;
4890
- _queryParamChanges$ = toObservable(injectQueryParamChanges());
4891
- _queryParams = injectQueryParams();
4892
- /**
4893
- * The angular form group that contains all the fields.
4894
- *
4895
- * **Do not** use any of the following methods on this form group:
4896
- * - `setValue`: Use `QueryForm.setValue` instead.
4897
- * - `patchValue`: Use `QueryForm.patchValue` instead.
4898
- * - `valueChanges`: Use `QueryForm.changes$` instead.
4899
- * - `value`: Use `QueryForm.value` instead.
4900
- * - `controls`: Use `QueryForm.controls` instead.
4901
- */
4902
- form = this._setupFormGroup();
4903
- _lastFormValue$ = new BehaviorSubject(null);
4904
- _currentFormValue$ = new BehaviorSubject(this._formValue);
4905
4902
  get _formValue() {
4906
4903
  return this.form.getRawValue();
4907
4904
  }
4908
4905
  get _form() {
4909
4906
  return this.form;
4910
4907
  }
4911
- _changes$ = new BehaviorSubject({
4912
- previousValue: null,
4913
- currentValue: this.form.getRawValue(),
4914
- });
4915
- changes$ = this._changes$.asObservable();
4916
- currentValue$ = this._changes$.pipe(map(({ currentValue }) => currentValue));
4917
- previousValue$ = this._changes$.pipe(map(({ previousValue }) => previousValue));
4918
- changes = toSignal(this.changes$);
4919
- currentValue = toSignal(this.currentValue$);
4920
- previousValue = toSignal(this.previousValue$);
4921
- /**
4922
- * The number of active filters.
4923
- *
4924
- * Excludes the following fields by default:
4925
- * - `page`
4926
- * - `skip`
4927
- * - `take`
4928
- * - `limit`
4929
- * - `sort`
4930
- * - `sortBy`
4931
- * - `sortOrder`
4932
- * - `query`
4933
- * - `search`
4934
- */
4935
- activeFilterCount$ = this.changes$.pipe(map(({ currentValue }) => Object.entries(currentValue)
4936
- .map(([key, value]) => {
4937
- if (IGNORED_FILTER_COUNT_FIELDS.includes(key) || this._fields[key]?.data.skipInFilterCount) {
4938
- return true;
4939
- }
4940
- return this._isDefaultValue(key, value);
4941
- })
4942
- .filter((v) => v === false).length));
4943
4908
  get controls() {
4944
4909
  return this.form.controls;
4945
4910
  }
@@ -4956,6 +4921,62 @@ class QueryForm {
4956
4921
  constructor(_fields, _options) {
4957
4922
  this._fields = _fields;
4958
4923
  this._options = _options;
4924
+ this._destroy$ = createDestroy();
4925
+ this._unobserveTrigger$ = new Subject();
4926
+ this._router = inject(Router);
4927
+ this._activatedRoute = inject(ActivatedRoute);
4928
+ this._defaultValues = this._extractDefaultValues();
4929
+ this._zone = inject(NgZone);
4930
+ this._didValueChanges$ = new Subject();
4931
+ this._isObserving = false;
4932
+ this._skipNextResets = false;
4933
+ this._queryParamChanges$ = toObservable(injectQueryParamChanges());
4934
+ this._queryParams = injectQueryParams();
4935
+ /**
4936
+ * The angular form group that contains all the fields.
4937
+ *
4938
+ * **Do not** use any of the following methods on this form group:
4939
+ * - `setValue`: Use `QueryForm.setValue` instead.
4940
+ * - `patchValue`: Use `QueryForm.patchValue` instead.
4941
+ * - `valueChanges`: Use `QueryForm.changes$` instead.
4942
+ * - `value`: Use `QueryForm.value` instead.
4943
+ * - `controls`: Use `QueryForm.controls` instead.
4944
+ */
4945
+ this.form = this._setupFormGroup();
4946
+ this._lastFormValue$ = new BehaviorSubject(null);
4947
+ this._currentFormValue$ = new BehaviorSubject(this._formValue);
4948
+ this._changes$ = new BehaviorSubject({
4949
+ previousValue: null,
4950
+ currentValue: this.form.getRawValue(),
4951
+ });
4952
+ this.changes$ = this._changes$.asObservable();
4953
+ this.currentValue$ = this._changes$.pipe(map(({ currentValue }) => currentValue));
4954
+ this.previousValue$ = this._changes$.pipe(map(({ previousValue }) => previousValue));
4955
+ this.changes = toSignal(this.changes$);
4956
+ this.currentValue = toSignal(this.currentValue$);
4957
+ this.previousValue = toSignal(this.previousValue$);
4958
+ /**
4959
+ * The number of active filters.
4960
+ *
4961
+ * Excludes the following fields by default:
4962
+ * - `page`
4963
+ * - `skip`
4964
+ * - `take`
4965
+ * - `limit`
4966
+ * - `sort`
4967
+ * - `sortBy`
4968
+ * - `sortOrder`
4969
+ * - `query`
4970
+ * - `search`
4971
+ */
4972
+ this.activeFilterCount$ = this.changes$.pipe(map(({ currentValue }) => Object.entries(currentValue)
4973
+ .map(([key, value]) => {
4974
+ if (IGNORED_FILTER_COUNT_FIELDS.includes(key) || this._fields[key]?.data.skipInFilterCount) {
4975
+ return true;
4976
+ }
4977
+ return this._isDefaultValue(key, value);
4978
+ })
4979
+ .filter((v) => v === false).length));
4959
4980
  assertInInjectionContext(QueryForm);
4960
4981
  inject(DestroyRef).onDestroy(() => this._cleanup());
4961
4982
  }