@ethlete/query 6.0.0-next.1 → 6.0.0-next.11

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,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
- import { isDevMode, DestroyRef, InjectionToken, inject, Injector, EnvironmentInjector, ErrorHandler, ɵEffectScheduler as _EffectScheduler, createEnvironmentInjector, effect, computed, untracked, signal, linkedSignal, runInInjectionContext, assertInInjectionContext, ChangeDetectorRef, ViewContainerRef, TemplateRef, Input, Directive, ElementRef, input, Pipe, ViewEncapsulation, ChangeDetectionStrategy, Component, DOCUMENT, NgZone } from '@angular/core';
2
+ import { isDevMode, DestroyRef, InjectionToken, inject, Injector, EnvironmentInjector, ErrorHandler, createEnvironmentInjector, effect, untracked, signal, linkedSignal, computed, runInInjectionContext, assertInInjectionContext, ChangeDetectorRef, ViewContainerRef, TemplateRef, Input, Directive, ElementRef, input, Pipe, ViewEncapsulation, ChangeDetectionStrategy, Component, DOCUMENT, NgZone } from '@angular/core';
3
3
  import { createStaticProvider, RuntimeError, clamp, createDestroy, computedTillTruthy, getCookie, setCookie, deleteCookie, createProvider, nextFrame, createRootProvider, isObject, injectRoute, getDomain, injectQueryParamChanges, injectQueryParams, clone, equal, ET_PROPERTY_REMOVED, previousSignalValue } from '@ethlete/core';
4
- import { Observable, Subscription, tap, retry, throwError, timer, catchError, takeUntil, startWith, pairwise, switchMap, of, BehaviorSubject, Subject, fromEvent, take, filter, ReplaySubject, map, shareReplay, interval, skip, takeWhile, combineLatest, EMPTY, withLatestFrom, debounceTime, merge, throttleTime } from 'rxjs';
4
+ import { filter, Subject, Subscription, Observable, tap, retry, throwError, timer, catchError, takeUntil, startWith, pairwise, switchMap, of, BehaviorSubject, fromEvent, take, ReplaySubject, map, shareReplay, interval, skip, takeWhile, combineLatest, EMPTY, withLatestFrom, debounceTime, merge, throttleTime } from 'rxjs';
5
5
  import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
6
- import { HttpClient, HttpErrorResponse, HttpEventType, HttpHeaders, HttpStatusCode } from '@angular/common/http';
6
+ import { HttpClient, HttpEventType, HttpErrorResponse, HttpHeaders, HttpStatusCode } from '@angular/common/http';
7
7
  import { getActiveConsumer, setActiveConsumer } from '@angular/core/primitives/signals';
8
8
  import { NgClass, AsyncPipe, JsonPipe } from '@angular/common';
9
9
  import * as i1 from '@angular/forms';
@@ -46,9 +46,6 @@ const createGqlExecuteFn = (executeOptions) => {
46
46
  const reset = () => resetExecuteState({ executeState, executeOptions });
47
47
  const exec = (executeArgs) => {
48
48
  circularChecker.check();
49
- // Make sure all effects are flushed before reading the args.
50
- // A withArgs feature effect might still be pending otherwise resulting in the wrong args being read.
51
- executeOptions.deps.effectScheduler.flush();
52
49
  const { args = executeOptions.state.args(), options } = executeArgs ?? {};
53
50
  const query = transformGql(executeOptions.creatorInternals.query);
54
51
  let gqlParams = query(args?.variables);
@@ -133,7 +130,6 @@ const setupQueryDependencies = (options) => {
133
130
  scopeDestroyRef: hostInjector.get(DestroyRef),
134
131
  client: hostInjector.get(clientToken),
135
132
  injector: undefined, // Will be set after injector creation
136
- effectScheduler: hostInjector.get(_EffectScheduler),
137
133
  ngErrorHandler: hostInjector.get(ErrorHandler),
138
134
  httpClient: hostInjector.get(HttpClient),
139
135
  };
@@ -307,17 +303,27 @@ const withArgs = (args) => {
307
303
  return createQueryFeature({
308
304
  type: QueryFeatureType.WITH_ARGS,
309
305
  fn: (context) => {
310
- const currArgs = computed(() => args(), ...(ngDevMode ? [{ debugName: "currArgs" }] : []));
306
+ // `state.args` is reactively backed by this source, so every reader (exec, polling,
307
+ // auto-refresh) always sees the latest value with no pending-effect window. Sentinels are
308
+ // resolved here: CLEAR -> null, `null` ("don't change") -> keep the previous value.
309
+ let previous = null;
310
+ context.state.subtle.setArgsSource(() => {
311
+ const value = args();
312
+ if (value === CLEAR_QUERY_ARGS) {
313
+ previous = null;
314
+ return null;
315
+ }
316
+ if (value === null)
317
+ return previous;
318
+ previous = value;
319
+ return value;
320
+ });
321
+ // Trigger (auto-)execution whenever the resolved args change.
311
322
  nestedEffect(() => {
312
- const currArgsNow = currArgs();
323
+ const currArgsNow = context.state.args();
313
324
  if (currArgsNow === null)
314
325
  return;
315
326
  untracked(() => {
316
- if (currArgsNow === CLEAR_QUERY_ARGS) {
317
- context.state.args.set(null);
318
- return;
319
- }
320
- context.state.args.set(currArgsNow);
321
327
  if (context.flags.shouldAutoExecute)
322
328
  context.execute({ args: currArgsNow });
323
329
  });
@@ -366,14 +372,9 @@ const withLogging = (options) => {
366
372
  return createQueryFeature({
367
373
  type: QueryFeatureType.WITH_LOGGING,
368
374
  fn: (context) => {
369
- nestedEffect(() => {
370
- const event = context.state.latestHttpEvent();
371
- if (event === null)
372
- return;
373
- untracked(() => {
374
- options.logFn(event);
375
- });
376
- }, { injector: context.deps.injector });
375
+ context.state.events$.pipe(takeUntilDestroyed(context.deps.destroyRef)).subscribe((event) => {
376
+ options.logFn(event);
377
+ });
377
378
  },
378
379
  });
379
380
  };
@@ -382,14 +383,11 @@ const withErrorHandling = (options) => {
382
383
  return createQueryFeature({
383
384
  type: QueryFeatureType.WITH_ERROR_HANDLING,
384
385
  fn: (context) => {
385
- nestedEffect(() => {
386
- const error = context.state.error();
387
- if (error === null)
388
- return;
389
- untracked(() => {
390
- options.handler(error);
391
- });
392
- }, { injector: context.deps.injector });
386
+ context.state.events$
387
+ .pipe(filter((event) => event.type === 'error'), takeUntilDestroyed(context.deps.destroyRef))
388
+ .subscribe((event) => {
389
+ options.handler(event.error);
390
+ });
393
391
  },
394
392
  });
395
393
  };
@@ -398,14 +396,11 @@ const withSuccessHandling = (options) => {
398
396
  return createQueryFeature({
399
397
  type: QueryFeatureType.WITH_SUCCESS_HANDLING,
400
398
  fn: (context) => {
401
- nestedEffect(() => {
402
- const response = context.state.response();
403
- if (response === null)
404
- return;
405
- untracked(() => {
406
- options.handler(response);
407
- });
408
- }, { injector: context.deps.injector });
399
+ context.state.events$
400
+ .pipe(filter((event) => event.type === HttpEventType.Response), takeUntilDestroyed(context.deps.destroyRef))
401
+ .subscribe(() => {
402
+ options.handler(context.state.response());
403
+ });
409
404
  },
410
405
  });
411
406
  };
@@ -458,20 +453,32 @@ const withResponseUpdate = (options) => {
458
453
  };
459
454
 
460
455
  const setupQueryState = (options) => {
461
- const request = signal(null, ...(ngDevMode ? [{ debugName: "request" }] : []));
462
- const rawResponse = linkedSignal(() => request()?.response() ?? null, ...(ngDevMode ? [{ debugName: "rawResponse" }] : []));
456
+ const request = signal(null, ...(ngDevMode ? [{ debugName: "request" }] : /* istanbul ignore next */ []));
457
+ const rawResponse = linkedSignal(() => request()?.response() ?? null, ...(ngDevMode ? [{ debugName: "rawResponse" }] : /* istanbul ignore next */ []));
463
458
  const response = computed(() => {
464
459
  const raw = rawResponse();
465
460
  if (raw === null)
466
461
  return null;
467
462
  return options.transformResponse ? options.transformResponse(raw) : raw;
468
- }, ...(ngDevMode ? [{ debugName: "response" }] : []));
469
- const loading = linkedSignal(() => request()?.loading() ?? null, ...(ngDevMode ? [{ debugName: "loading" }] : []));
470
- const error = linkedSignal(() => request()?.error() ?? null, ...(ngDevMode ? [{ debugName: "error" }] : []));
471
- const latestHttpEvent = linkedSignal(() => request()?.currentEvent() ?? null, ...(ngDevMode ? [{ debugName: "latestHttpEvent" }] : []));
472
- const args = signal(null, ...(ngDevMode ? [{ debugName: "args" }] : []));
473
- const lastTimeExecutedAt = signal(null, ...(ngDevMode ? [{ debugName: "lastTimeExecutedAt" }] : []));
474
- const lastTriggeredBy = signal(null, ...(ngDevMode ? [{ debugName: "lastTriggeredBy" }] : []));
463
+ }, ...(ngDevMode ? [{ debugName: "response" }] : /* istanbul ignore next */ []));
464
+ const loading = linkedSignal(() => request()?.loading() ?? null, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
465
+ const error = linkedSignal(() => request()?.error() ?? null, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
466
+ const latestHttpEvent = linkedSignal(() => request()?.currentEvent() ?? null, ...(ngDevMode ? [{ debugName: "latestHttpEvent" }] : /* istanbul ignore next */ []));
467
+ // `args` is reactively sourced: reads always reflect the latest value from the installed source
468
+ // (e.g. the `withArgs` feature), so there is no stale window between a source change and an
469
+ // effect writing it. It stays writable (reset / auth-error clear it via `.set(null)`); a manual
470
+ // set is overridden again the next time the source's dependencies change.
471
+ const argsSource = signal(() => null, ...(ngDevMode ? [{ debugName: "argsSource" }] : /* istanbul ignore next */ []));
472
+ const args = linkedSignal(() => argsSource()(), ...(ngDevMode ? [{ debugName: "args" }] : /* istanbul ignore next */ []));
473
+ const setArgsSource = (source) => argsSource.set(source);
474
+ const lastTimeExecutedAt = signal(null, ...(ngDevMode ? [{ debugName: "lastTimeExecutedAt" }] : /* istanbul ignore next */ []));
475
+ const lastTriggeredBy = signal(null, ...(ngDevMode ? [{ debugName: "lastTriggeredBy" }] : /* istanbul ignore next */ []));
476
+ const requestEvents$ = new Subject();
477
+ let requestEventsSubscription = Subscription.EMPTY;
478
+ const bindRequestEvents = (request) => {
479
+ requestEventsSubscription.unsubscribe();
480
+ requestEventsSubscription = request.events$.subscribe((event) => requestEvents$.next(event));
481
+ };
475
482
  const executionState = computed(() => {
476
483
  const currentResponse = response();
477
484
  const currentError = error();
@@ -506,7 +513,7 @@ const setupQueryState = (options) => {
506
513
  else {
507
514
  return null;
508
515
  }
509
- }, ...(ngDevMode ? [{ debugName: "executionState" }] : []));
516
+ }, ...(ngDevMode ? [{ debugName: "executionState" }] : /* istanbul ignore next */ []));
510
517
  const state = {
511
518
  rawResponse,
512
519
  response,
@@ -517,9 +524,12 @@ const setupQueryState = (options) => {
517
524
  lastTimeExecutedAt,
518
525
  lastTriggeredBy,
519
526
  executionState,
527
+ events$: requestEvents$.asObservable(),
520
528
  subtle: {
521
529
  request,
522
530
  rawResponse,
531
+ bindRequestEvents,
532
+ setArgsSource,
523
533
  },
524
534
  };
525
535
  return state;
@@ -530,7 +540,7 @@ const createQuerySnapshotFn = (options) => {
530
540
  const context = injectQueryContext();
531
541
  const snapshotFn = () => {
532
542
  const snapshotState = setupQueryState({});
533
- const isAlive = signal(true, ...(ngDevMode ? [{ debugName: "isAlive" }] : []));
543
+ const isAlive = signal(true, ...(ngDevMode ? [{ debugName: "isAlive" }] : /* istanbul ignore next */ []));
534
544
  const killEffectRef = effect(() => {
535
545
  const currentLoading = state.loading();
536
546
  const currentError = state.error();
@@ -549,13 +559,14 @@ const createQuerySnapshotFn = (options) => {
549
559
  snapshotState.rawResponse.set(currentResponse);
550
560
  if (currentLoading)
551
561
  return;
552
- if (!currentResponse && !currentError)
562
+ const hasCompletedResponse = currentLatestHttpEvent?.type === HttpEventType.Response;
563
+ if (!hasCompletedResponse && !currentError)
553
564
  return;
554
565
  // kill the effect once loading is done and we either have a response or an error
555
566
  killEffectRef.destroy();
556
567
  isAlive.set(false);
557
568
  });
558
- }, { ...(ngDevMode ? { debugName: "killEffectRef" } : {}), injector: context.deps.injector });
569
+ }, { ...(ngDevMode ? { debugName: "killEffectRef" } : /* istanbul ignore next */ {}), injector: context.deps.injector });
559
570
  const snapshot = {
560
571
  args: wrapAsObservableSignal(snapshotState.args.asReadonly(), context.deps.injector),
561
572
  response: wrapAsObservableSignal(snapshotState.response, context.deps.injector),
@@ -745,6 +756,7 @@ const queryExecute = (options) => {
745
756
  state.lastTimeExecutedAt.set(Date.now());
746
757
  state.lastTriggeredBy.set(runQueryOptions?.triggeredBy ?? null);
747
758
  state.subtle.request.set(request);
759
+ state.subtle.bindRequestEvents(request);
748
760
  };
749
761
  const circularQueryDependencyChecker = () => {
750
762
  let lastTriggerTs = 0;
@@ -778,9 +790,6 @@ const createExecuteFn = (executeOptions) => {
778
790
  const reset = () => resetExecuteState({ executeState, executeOptions });
779
791
  const exec = (executeArgs) => {
780
792
  circularChecker.check();
781
- // Make sure all effects are flushed before reading the args.
782
- // A withArgs feature effect might still be pending otherwise resulting in the wrong args being read.
783
- executeOptions.deps.effectScheduler.flush();
784
793
  const { args = executeOptions.state.args(), options } = executeArgs ?? {};
785
794
  queryExecute({ executeOptions, executeState, args, options });
786
795
  };
@@ -1538,18 +1547,19 @@ const SPEED_BUFFER_TIME_IN_MS = 2000;
1538
1547
  const createHttpRequest = (options) => {
1539
1548
  let currentStreamSubscription = Subscription.EMPTY;
1540
1549
  const { args, clientOptions, dependencies } = options;
1541
- const currentEvent = signal(null, ...(ngDevMode ? [{ debugName: "currentEvent" }] : []));
1542
- const loading = signal(null, ...(ngDevMode ? [{ debugName: "loading" }] : []));
1543
- const error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
1544
- const response = signal(null, ...(ngDevMode ? [{ debugName: "response" }] : []));
1545
- const lastLoadEventTime = signal(0, ...(ngDevMode ? [{ debugName: "lastLoadEventTime" }] : []));
1546
- const lastLoadEventAmount = signal(0, ...(ngDevMode ? [{ debugName: "lastLoadEventAmount" }] : []));
1547
- const lastExecuteTime = signal(0, ...(ngDevMode ? [{ debugName: "lastExecuteTime" }] : []));
1548
- const expiresIn = signal(null, ...(ngDevMode ? [{ debugName: "expiresIn" }] : []));
1550
+ const currentEvent = signal(null, ...(ngDevMode ? [{ debugName: "currentEvent" }] : /* istanbul ignore next */ []));
1551
+ const event$ = new Subject();
1552
+ const loading = signal(null, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
1553
+ const error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
1554
+ const response = signal(null, ...(ngDevMode ? [{ debugName: "response" }] : /* istanbul ignore next */ []));
1555
+ const lastLoadEventTime = signal(0, ...(ngDevMode ? [{ debugName: "lastLoadEventTime" }] : /* istanbul ignore next */ []));
1556
+ const lastLoadEventAmount = signal(0, ...(ngDevMode ? [{ debugName: "lastLoadEventAmount" }] : /* istanbul ignore next */ []));
1557
+ const lastExecuteTime = signal(0, ...(ngDevMode ? [{ debugName: "lastExecuteTime" }] : /* istanbul ignore next */ []));
1558
+ const expiresIn = signal(null, ...(ngDevMode ? [{ debugName: "expiresIn" }] : /* istanbul ignore next */ []));
1549
1559
  const isStale = computed(() => {
1550
1560
  const expiresInTs = expiresIn();
1551
1561
  return expiresInTs === null || expiresInTs < Date.now();
1552
- }, ...(ngDevMode ? [{ debugName: "isStale" }] : []));
1562
+ }, ...(ngDevMode ? [{ debugName: "isStale" }] : /* istanbul ignore next */ []));
1553
1563
  const createStream = () => {
1554
1564
  const headers = typeof args?.headers === 'function' ? args.headers() : args?.headers;
1555
1565
  return dependencies.httpClient
@@ -1600,14 +1610,12 @@ const createHttpRequest = (options) => {
1600
1610
  return true;
1601
1611
  };
1602
1612
  const destroy = () => {
1603
- if (currentStreamSubscription.closed) {
1604
- return false;
1605
- }
1613
+ const wasActive = !currentStreamSubscription.closed;
1606
1614
  currentStreamSubscription.unsubscribe();
1607
- return true;
1615
+ event$.complete();
1616
+ return wasActive;
1608
1617
  };
1609
1618
  const updateState = (event) => {
1610
- currentEvent.set(event);
1611
1619
  switch (event.type) {
1612
1620
  case HttpEventType.Response:
1613
1621
  {
@@ -1634,12 +1642,16 @@ const createHttpRequest = (options) => {
1634
1642
  }
1635
1643
  break;
1636
1644
  }
1645
+ currentEvent.set(event);
1646
+ event$.next(event);
1637
1647
  };
1638
1648
  const updateErrorState = (errorResponse) => {
1639
1649
  const errorRes = createQueryErrorResponse(errorResponse);
1640
1650
  error.set(errorRes);
1641
1651
  loading.set(null);
1642
- currentEvent.set({ type: 'error', error: errorRes });
1652
+ const errorEvent = { type: 'error', error: errorRes };
1653
+ currentEvent.set(errorEvent);
1654
+ event$.next(errorEvent);
1643
1655
  options.dependencies.ngErrorHandler.handleError(errorRes.raw);
1644
1656
  };
1645
1657
  const updateLoadingState = (event) => {
@@ -1679,6 +1691,7 @@ const createHttpRequest = (options) => {
1679
1691
  error: error.asReadonly(),
1680
1692
  response: response.asReadonly(),
1681
1693
  currentEvent: currentEvent.asReadonly(),
1694
+ events$: event$.asObservable(),
1682
1695
  isStale,
1683
1696
  };
1684
1697
  return httpRequest;
@@ -1696,9 +1709,9 @@ const createQueryStack = (options) => {
1696
1709
  return { queries, lastQuery };
1697
1710
  }, transform, argsKeyFn, deduplicateArgs, maxQueries = Infinity, removeStrategy = 'oldest', } = options ?? {};
1698
1711
  const injector = inject(Injector);
1699
- const queries = signal([], ...(ngDevMode ? [{ debugName: "queries" }] : []));
1700
- const lastQuery = signal(null, ...(ngDevMode ? [{ debugName: "lastQuery" }] : []));
1701
- const firstQuery = computed(() => queries()[0] ?? null, ...(ngDevMode ? [{ debugName: "firstQuery" }] : []));
1712
+ const queries = signal([], ...(ngDevMode ? [{ debugName: "queries" }] : /* istanbul ignore next */ []));
1713
+ const lastQuery = signal(null, ...(ngDevMode ? [{ debugName: "lastQuery" }] : /* istanbul ignore next */ []));
1714
+ const firstQuery = computed(() => queries()[0] ?? null, ...(ngDevMode ? [{ debugName: "firstQuery" }] : /* istanbul ignore next */ []));
1702
1715
  const hasWithArgsFeature = features.some((f) => f.type == QueryFeatureType.WITH_ARGS);
1703
1716
  const hasWithOptimisticUpdateFeature = features.some((f) => f.type == QueryFeatureType.WITH_RESPONSE_UPDATE);
1704
1717
  if (hasWithArgsFeature) {
@@ -1780,23 +1793,23 @@ const createQueryStack = (options) => {
1780
1793
  untracked(() => clear());
1781
1794
  });
1782
1795
  effect(() => runWithArgs(args(dependencies?.())));
1783
- const anyLoading = computed(() => queries().some((q) => q.loading()), ...(ngDevMode ? [{ debugName: "anyLoading" }] : []));
1784
- const loadingCount = computed(() => queries().filter((q) => q.loading()).length, ...(ngDevMode ? [{ debugName: "loadingCount" }] : []));
1796
+ const anyLoading = computed(() => queries().some((q) => q.loading()), ...(ngDevMode ? [{ debugName: "anyLoading" }] : /* istanbul ignore next */ []));
1797
+ const loadingCount = computed(() => queries().filter((q) => q.loading()).length, ...(ngDevMode ? [{ debugName: "loadingCount" }] : /* istanbul ignore next */ []));
1785
1798
  const allLoading = computed(() => {
1786
1799
  const qs = queries();
1787
1800
  return qs.length > 0 && qs.every((q) => q.loading());
1788
- }, ...(ngDevMode ? [{ debugName: "allLoading" }] : []));
1801
+ }, ...(ngDevMode ? [{ debugName: "allLoading" }] : /* istanbul ignore next */ []));
1789
1802
  const loadingProgress = computed(() => {
1790
1803
  const total = queries().length;
1791
1804
  const loaded = queries().filter((q) => !q.loading()).length;
1792
1805
  return { loaded, total };
1793
- }, ...(ngDevMode ? [{ debugName: "loadingProgress" }] : []));
1806
+ }, ...(ngDevMode ? [{ debugName: "loadingProgress" }] : /* istanbul ignore next */ []));
1794
1807
  const anyError = computed(() => queries()
1795
1808
  .map((q) => q.error())
1796
- .find((e) => e !== null) ?? null, ...(ngDevMode ? [{ debugName: "anyError" }] : []));
1809
+ .find((e) => e !== null) ?? null, ...(ngDevMode ? [{ debugName: "anyError" }] : /* istanbul ignore next */ []));
1797
1810
  const errors = computed(() => queries()
1798
1811
  .map((q) => q.error())
1799
- .filter((e) => e !== null), ...(ngDevMode ? [{ debugName: "errors" }] : []));
1812
+ .filter((e) => e !== null), ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
1800
1813
  const response = computed(() => {
1801
1814
  const responses = queries().map((q) => q.response());
1802
1815
  return transform?.(responses) ?? responses;
@@ -1891,12 +1904,12 @@ const fakePaginationAdapter = (totalHits = 10) => {
1891
1904
  };
1892
1905
  const createPagedQueryStack = (options) => {
1893
1906
  const { responseNormalizer, queryCreator, features } = options;
1894
- const currentPageArgs = signal(null, ...(ngDevMode ? [{ debugName: "currentPageArgs" }] : []));
1895
- const initialPage = signal(options.initialPage ?? 1, ...(ngDevMode ? [{ debugName: "initialPage" }] : []));
1896
- const loadedMinPage = signal(initialPage(), ...(ngDevMode ? [{ debugName: "loadedMinPage" }] : []));
1897
- const loadedMaxPage = signal(initialPage(), ...(ngDevMode ? [{ debugName: "loadedMaxPage" }] : []));
1898
- const lastResetTimestamp = signal(Date.now(), ...(ngDevMode ? [{ debugName: "lastResetTimestamp" }] : []));
1899
- const pageDirection = signal('next', ...(ngDevMode ? [{ debugName: "pageDirection" }] : []));
1907
+ const currentPageArgs = signal(null, ...(ngDevMode ? [{ debugName: "currentPageArgs" }] : /* istanbul ignore next */ []));
1908
+ const initialPage = signal(options.initialPage ?? 1, ...(ngDevMode ? [{ debugName: "initialPage" }] : /* istanbul ignore next */ []));
1909
+ const loadedMinPage = signal(initialPage(), ...(ngDevMode ? [{ debugName: "loadedMinPage" }] : /* istanbul ignore next */ []));
1910
+ const loadedMaxPage = signal(initialPage(), ...(ngDevMode ? [{ debugName: "loadedMaxPage" }] : /* istanbul ignore next */ []));
1911
+ const resetTrigger = signal(0, ...(ngDevMode ? [{ debugName: "resetTrigger" }] : /* istanbul ignore next */ []));
1912
+ const pageDirection = signal('next', ...(ngDevMode ? [{ debugName: "pageDirection" }] : /* istanbul ignore next */ []));
1900
1913
  const stack = createQueryStack({
1901
1914
  args: () => null,
1902
1915
  queryCreator,
@@ -1919,7 +1932,7 @@ const createPagedQueryStack = (options) => {
1919
1932
  transform: transformArrayResponse,
1920
1933
  });
1921
1934
  effect(() => {
1922
- lastResetTimestamp();
1935
+ resetTrigger();
1923
1936
  const args = options.args(initialPage(), []);
1924
1937
  untracked(() => {
1925
1938
  stack.clear();
@@ -1935,22 +1948,22 @@ const createPagedQueryStack = (options) => {
1935
1948
  if (!res)
1936
1949
  return null;
1937
1950
  return responseNormalizer(res, all);
1938
- }, ...(ngDevMode ? [{ debugName: "maxPagination" }] : []));
1951
+ }, ...(ngDevMode ? [{ debugName: "maxPagination" }] : /* istanbul ignore next */ []));
1939
1952
  const minPagination = computed(() => {
1940
1953
  const res = stack.firstQuery()?.response();
1941
1954
  const all = stack.response();
1942
1955
  if (!res)
1943
1956
  return null;
1944
1957
  return responseNormalizer(res, all);
1945
- }, ...(ngDevMode ? [{ debugName: "minPagination" }] : []));
1958
+ }, ...(ngDevMode ? [{ debugName: "minPagination" }] : /* istanbul ignore next */ []));
1946
1959
  const isFirstPageLoaded = computed(() => {
1947
1960
  const min = minPagination();
1948
1961
  return min ? loadedMinPage() === min.currentPage : false;
1949
- }, ...(ngDevMode ? [{ debugName: "isFirstPageLoaded" }] : []));
1962
+ }, ...(ngDevMode ? [{ debugName: "isFirstPageLoaded" }] : /* istanbul ignore next */ []));
1950
1963
  const isLastPageLoaded = computed(() => {
1951
1964
  const max = maxPagination();
1952
1965
  return max ? loadedMaxPage() === max.totalPages : false;
1953
- }, ...(ngDevMode ? [{ debugName: "isLastPageLoaded" }] : []));
1966
+ }, ...(ngDevMode ? [{ debugName: "isLastPageLoaded" }] : /* istanbul ignore next */ []));
1954
1967
  const fetchPreviousPage = () => {
1955
1968
  const page = loadedMinPage() - 1;
1956
1969
  const allResponses = stack.response();
@@ -2019,25 +2032,25 @@ const createPagedQueryStack = (options) => {
2019
2032
  const page = resetOptions?.initialPage ?? initialPage();
2020
2033
  initialPage.set(page);
2021
2034
  pageDirection.set('next');
2022
- lastResetTimestamp.set(Date.now());
2035
+ resetTrigger.update((v) => v + 1);
2023
2036
  };
2024
2037
  const canFetchPreviousPage = computed(() => {
2025
2038
  const currentMinPagination = minPagination();
2026
2039
  if (!currentMinPagination)
2027
2040
  return false;
2028
2041
  return loadedMinPage() > 1;
2029
- }, ...(ngDevMode ? [{ debugName: "canFetchPreviousPage" }] : []));
2042
+ }, ...(ngDevMode ? [{ debugName: "canFetchPreviousPage" }] : /* istanbul ignore next */ []));
2030
2043
  const canFetchNextPage = computed(() => {
2031
2044
  const currentMaxPagination = maxPagination();
2032
2045
  return currentMaxPagination ? loadedMaxPage() < currentMaxPagination.totalPages : false;
2033
- }, ...(ngDevMode ? [{ debugName: "canFetchNextPage" }] : []));
2046
+ }, ...(ngDevMode ? [{ debugName: "canFetchNextPage" }] : /* istanbul ignore next */ []));
2034
2047
  const items = computed(() => {
2035
2048
  const res = stack.response();
2036
2049
  return res.map((r) => responseNormalizer(r, res).items).flat();
2037
- }, ...(ngDevMode ? [{ debugName: "items" }] : []));
2050
+ }, ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
2038
2051
  const isFirstLoad = computed(() => {
2039
2052
  return stack.queries().length === 1 && !!stack.lastQuery()?.loading();
2040
- }, ...(ngDevMode ? [{ debugName: "isFirstLoad" }] : []));
2053
+ }, ...(ngDevMode ? [{ debugName: "isFirstLoad" }] : /* istanbul ignore next */ []));
2041
2054
  const execute = (options) => {
2042
2055
  const whereFn = options?.where;
2043
2056
  if (whereFn) {
@@ -2210,7 +2223,7 @@ function effectComputed(computation, injector) {
2210
2223
  // Ignore errors in the initial computation
2211
2224
  // Angular might throw an error if required inputs are read but not available yet
2212
2225
  }
2213
- const lastResult = signal(initialData, ...(ngDevMode ? [{ debugName: "lastResult" }] : []));
2226
+ const lastResult = signal(initialData, ...(ngDevMode ? [{ debugName: "lastResult" }] : /* istanbul ignore next */ []));
2214
2227
  effect(() => {
2215
2228
  const data = runInInjectionContext(injector, () => computation());
2216
2229
  untracked(() => {
@@ -2261,7 +2274,7 @@ function queryStateSignal(source, options) {
2261
2274
  })), {
2262
2275
  initialValue: null,
2263
2276
  });
2264
- const rwSignal = linkedSignal(roSignal, ...(ngDevMode ? [{ debugName: "rwSignal" }] : []));
2277
+ const rwSignal = linkedSignal(roSignal, ...(ngDevMode ? [{ debugName: "rwSignal" }] : /* istanbul ignore next */ []));
2265
2278
  return rwSignal;
2266
2279
  }
2267
2280
  function queryStateResponseSignal(source, options) {
@@ -2269,7 +2282,7 @@ function queryStateResponseSignal(source, options) {
2269
2282
  const dataSignal = computed(() => {
2270
2283
  const state = s();
2271
2284
  return isQueryStateSuccess(state) ? state.response : null;
2272
- }, ...(ngDevMode ? [{ debugName: "dataSignal" }] : []));
2285
+ }, ...(ngDevMode ? [{ debugName: "dataSignal" }] : /* istanbul ignore next */ []));
2273
2286
  dataSignal['reset'] = () => {
2274
2287
  s.set(null);
2275
2288
  };
@@ -2352,7 +2365,7 @@ class V2QueryCreator {
2352
2365
  };
2353
2366
  this.createSignal = (initialValue, config) => {
2354
2367
  assertInInjectionContext(this.createSignal);
2355
- const _signal = signal(initialValue ?? null, ...(ngDevMode ? [{ debugName: "_signal" }] : []));
2368
+ const _signal = signal(initialValue ?? null, ...(ngDevMode ? [{ debugName: "_signal" }] : /* istanbul ignore next */ []));
2356
2369
  addQueryContainerHandling(toObservable(_signal), () => _signal(), config);
2357
2370
  return _signal;
2358
2371
  };
@@ -2622,11 +2635,14 @@ const createSecureExecuteFactory = (options) => {
2622
2635
  const circularChecker = circularQueryDependencyChecker();
2623
2636
  let authQuerySubscription = Subscription.EMPTY;
2624
2637
  let tokenRefreshSubscription = Subscription.EMPTY;
2638
+ let tokenWaitSubscription = Subscription.EMPTY;
2625
2639
  const reset = () => {
2626
2640
  authQuerySubscription.unsubscribe();
2627
2641
  authQuerySubscription = Subscription.EMPTY;
2628
2642
  tokenRefreshSubscription.unsubscribe();
2629
2643
  tokenRefreshSubscription = Subscription.EMPTY;
2644
+ tokenWaitSubscription.unsubscribe();
2645
+ tokenWaitSubscription = Subscription.EMPTY;
2630
2646
  resetExecuteState({
2631
2647
  executeState,
2632
2648
  executeOptions: { deps: options.deps, state: options.state },
@@ -2667,11 +2683,27 @@ const createSecureExecuteFactory = (options) => {
2667
2683
  },
2668
2684
  }, tokens, headers, executeState);
2669
2685
  };
2686
+ // The auth query completing and the access token being populated happen on two
2687
+ // different reactive timelines: the token is set by a separate token-extraction
2688
+ // effect (see `setupBearerQueryRegistry`), and for cross-client / secure auth
2689
+ // queries the completion is delivered through several nested `toObservable` hops.
2690
+ // Calling `authAndExec` purely because the auth query is "done" therefore races
2691
+ // the token and can run while it is still null. Gate on the token signal instead:
2692
+ // execute immediately if it is already available, otherwise wait for it.
2693
+ const authAndExecWhenTokenReady = (executeArgs) => {
2694
+ if (options.authProvider.accessToken()) {
2695
+ authAndExec(executeArgs);
2696
+ return;
2697
+ }
2698
+ tokenWaitSubscription.unsubscribe();
2699
+ tokenWaitSubscription = toObservable(options.authProvider.accessToken, {
2700
+ injector: options.deps.injector,
2701
+ })
2702
+ .pipe(filter(Boolean), take(1), tap(() => authAndExec(executeArgs)))
2703
+ .subscribe();
2704
+ };
2670
2705
  const exec = (executeArgs) => {
2671
2706
  circularChecker.check();
2672
- // Make sure all effects are flushed before reading the args.
2673
- // A withArgs feature effect might still be pending otherwise resulting in the wrong args being read.
2674
- options.deps.effectScheduler.flush();
2675
2707
  const execArgsWithDefaults = {
2676
2708
  args: executeArgs?.args ?? options.state.args(),
2677
2709
  options: executeArgs?.options,
@@ -2680,6 +2712,8 @@ const createSecureExecuteFactory = (options) => {
2680
2712
  authQuerySubscription = Subscription.EMPTY;
2681
2713
  tokenRefreshSubscription.unsubscribe();
2682
2714
  tokenRefreshSubscription = Subscription.EMPTY;
2715
+ tokenWaitSubscription.unsubscribe();
2716
+ tokenWaitSubscription = Subscription.EMPTY;
2683
2717
  tokenRefreshSubscription = options.authProvider.afterTokenRefresh$
2684
2718
  .pipe(filter(() => {
2685
2719
  const currentError = options.state.error();
@@ -2707,14 +2741,14 @@ const createSecureExecuteFactory = (options) => {
2707
2741
  error(query);
2708
2742
  }
2709
2743
  else if (query.response()) {
2710
- authAndExec(execArgsWithDefaults);
2744
+ authAndExecWhenTokenReady(execArgsWithDefaults);
2711
2745
  }
2712
2746
  }));
2713
2747
  }))
2714
2748
  .subscribe();
2715
2749
  }
2716
2750
  else if (authQuery.response()) {
2717
- authAndExec(execArgsWithDefaults);
2751
+ authAndExecWhenTokenReady(execArgsWithDefaults);
2718
2752
  }
2719
2753
  else if (authQuery.error()) {
2720
2754
  error(authQuery);
@@ -2959,7 +2993,7 @@ class LegacyQuery {
2959
2993
  });
2960
2994
  }
2961
2995
  });
2962
- }, ...(ngDevMode ? [{ debugName: "storeSyncEffect" }] : []));
2996
+ }, ...(ngDevMode ? [{ debugName: "storeSyncEffect" }] : /* istanbul ignore next */ []));
2963
2997
  /**
2964
2998
  * @internal
2965
2999
  */
@@ -3112,7 +3146,7 @@ class LegacyQueryCreator {
3112
3146
  legacyQuery.destroy();
3113
3147
  destroyEffect.destroy();
3114
3148
  }
3115
- }, ...(ngDevMode ? [{ debugName: "destroyEffect" }] : []));
3149
+ }, ...(ngDevMode ? [{ debugName: "destroyEffect" }] : /* istanbul ignore next */ []));
3116
3150
  }
3117
3151
  return legacyQuery;
3118
3152
  });
@@ -3124,7 +3158,7 @@ class LegacyQueryCreator {
3124
3158
  return subject;
3125
3159
  };
3126
3160
  this.createSignal = (initialValue, config) => {
3127
- const _signal = signal(initialValue ?? null, ...(ngDevMode ? [{ debugName: "_signal" }] : []));
3161
+ const _signal = signal(initialValue ?? null, ...(ngDevMode ? [{ debugName: "_signal" }] : /* istanbul ignore next */ []));
3128
3162
  addQueryContainerHandling(toObservable(_signal), () => _signal(), config);
3129
3163
  return _signal;
3130
3164
  };
@@ -3271,7 +3305,7 @@ const createQueryCollectionSubject = (queryMap, config) => {
3271
3305
  };
3272
3306
  const createQueryCollectionSignal = (queryMap, config) => {
3273
3307
  assertInInjectionContext(createQueryCollectionSignal);
3274
- const _signal = signal(null, ...(ngDevMode ? [{ debugName: "_signal" }] : []));
3308
+ const _signal = signal(null, ...(ngDevMode ? [{ debugName: "_signal" }] : /* istanbul ignore next */ []));
3275
3309
  addQueryContainerHandling(toObservable(_signal).pipe(map((s) => s?.query ?? null)), () => _signal()?.query ?? null, config);
3276
3310
  return _signal;
3277
3311
  };
@@ -4005,7 +4039,7 @@ class V2BearerAuthProvider {
4005
4039
  }
4006
4040
 
4007
4041
  const [provideInfinityQueryResponseDelay, injectInfinityQueryResponseDelay] = createProvider(() => {
4008
- const enabled = signal(false, ...(ngDevMode ? [{ debugName: "enabled" }] : []));
4042
+ const enabled = signal(false, ...(ngDevMode ? [{ debugName: "enabled" }] : /* istanbul ignore next */ []));
4009
4043
  const enabled$ = toObservable(enabled);
4010
4044
  return {
4011
4045
  enabled,
@@ -4316,13 +4350,13 @@ class InfinityQueryDirective {
4316
4350
  this._viewContext.currentQuery = null;
4317
4351
  this._data$.next([]);
4318
4352
  }
4319
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InfinityQueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4320
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.1", type: InfinityQueryDirective, isStandalone: true, selector: "[etInfinityQuery]", inputs: { infinityQuery: ["etInfinityQuery", "infinityQuery"] }, providers: [
4353
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: InfinityQueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4354
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.13", type: InfinityQueryDirective, isStandalone: true, selector: "[etInfinityQuery]", inputs: { infinityQuery: ["etInfinityQuery", "infinityQuery"] }, providers: [
4321
4355
  { provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective },
4322
4356
  provideInfinityQueryResponseDelay(),
4323
4357
  ], exportAs: ["etInfinityQuery"], ngImport: i0 }); }
4324
4358
  }
4325
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InfinityQueryDirective, decorators: [{
4359
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: InfinityQueryDirective, decorators: [{
4326
4360
  type: Directive,
4327
4361
  args: [{
4328
4362
  selector: '[etInfinityQuery]',
@@ -4344,10 +4378,10 @@ class InfinityQueryTriggerDirective {
4344
4378
  this._destroy = new Subject();
4345
4379
  this._observer = null;
4346
4380
  this.click$ = fromEvent(this._elementRef.nativeElement, 'click');
4347
- this.scrollContainerSelector = input(null, ...(ngDevMode ? [{ debugName: "scrollContainerSelector" }] : []));
4381
+ this.scrollContainerSelector = input(null, ...(ngDevMode ? [{ debugName: "scrollContainerSelector" }] : /* istanbul ignore next */ []));
4348
4382
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
4349
- this.infinityQueryOverride = input(null, ...(ngDevMode ? [{ debugName: "infinityQueryOverride" }] : []));
4350
- this.infinityQuery = computed(() => this.infinityQueryOverride() ?? this._infinityQuery, ...(ngDevMode ? [{ debugName: "infinityQuery" }] : []));
4383
+ this.infinityQueryOverride = input(null, ...(ngDevMode ? [{ debugName: "infinityQueryOverride" }] : /* istanbul ignore next */ []));
4384
+ this.infinityQuery = computed(() => this.infinityQueryOverride() ?? this._infinityQuery, ...(ngDevMode ? [{ debugName: "infinityQuery" }] : /* istanbul ignore next */ []));
4351
4385
  }
4352
4386
  ngOnInit() {
4353
4387
  const isInteractive = this._elementRef.nativeElement.tagName === 'BUTTON';
@@ -4379,10 +4413,10 @@ class InfinityQueryTriggerDirective {
4379
4413
  });
4380
4414
  this._observer.observe(this._elementRef.nativeElement);
4381
4415
  }
4382
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InfinityQueryTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4383
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.1", type: InfinityQueryTriggerDirective, isStandalone: true, selector: "[etInfinityQueryTrigger], et-infinity-query-trigger", inputs: { scrollContainerSelector: { classPropertyName: "scrollContainerSelector", publicName: "scrollContainerSelector", isSignal: true, isRequired: false, transformFunction: null }, infinityQueryOverride: { classPropertyName: "infinityQueryOverride", publicName: "infinityQueryOverride", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
4416
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: InfinityQueryTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4417
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.13", type: InfinityQueryTriggerDirective, isStandalone: true, selector: "[etInfinityQueryTrigger], et-infinity-query-trigger", inputs: { scrollContainerSelector: { classPropertyName: "scrollContainerSelector", publicName: "scrollContainerSelector", isSignal: true, isRequired: false, transformFunction: null }, infinityQueryOverride: { classPropertyName: "infinityQueryOverride", publicName: "infinityQueryOverride", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
4384
4418
  }
4385
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: InfinityQueryTriggerDirective, decorators: [{
4419
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: InfinityQueryTriggerDirective, decorators: [{
4386
4420
  type: Directive,
4387
4421
  args: [{
4388
4422
  selector: '[etInfinityQueryTrigger], et-infinity-query-trigger',
@@ -4406,8 +4440,8 @@ class QueryDirective {
4406
4440
  scope: null,
4407
4441
  query: null,
4408
4442
  };
4409
- this.query = input.required({ ...(ngDevMode ? { debugName: "query" } : {}), alias: 'etQuery' });
4410
- this.cache = input(false, { ...(ngDevMode ? { debugName: "cache" } : {}), alias: 'etQueryCache' });
4443
+ this.query = input.required({ ...(ngDevMode ? { debugName: "query" } : /* istanbul ignore next */ {}), alias: 'etQuery' });
4444
+ this.cache = input(false, { ...(ngDevMode ? { debugName: "cache" } : /* istanbul ignore next */ {}), alias: 'etQueryCache' });
4411
4445
  this.queryState = queryStateSignal(this.query);
4412
4446
  inject(ViewContainerRef).createEmbeddedView(inject(TemplateRef), this._viewContext);
4413
4447
  effect(() => {
@@ -4468,10 +4502,10 @@ class QueryDirective {
4468
4502
  });
4469
4503
  });
4470
4504
  }
4471
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: QueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4472
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.1", type: QueryDirective, isStandalone: true, selector: "[etQuery]", inputs: { query: { classPropertyName: "query", publicName: "etQuery", isSignal: true, isRequired: true, transformFunction: null }, cache: { classPropertyName: "cache", publicName: "etQueryCache", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
4505
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: QueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4506
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.13", type: QueryDirective, isStandalone: true, selector: "[etQuery]", inputs: { query: { classPropertyName: "query", publicName: "etQuery", isSignal: true, isRequired: true, transformFunction: null }, cache: { classPropertyName: "cache", publicName: "etQueryCache", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
4473
4507
  }
4474
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: QueryDirective, decorators: [{
4508
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: QueryDirective, decorators: [{
4475
4509
  type: Directive,
4476
4510
  args: [{
4477
4511
  selector: '[etQuery]',
@@ -4492,10 +4526,10 @@ class QueryShortNamePipe {
4492
4526
  }
4493
4527
  return route;
4494
4528
  }
4495
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: QueryShortNamePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
4496
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.1", ngImport: i0, type: QueryShortNamePipe, isStandalone: true, name: "queryShortName" }); }
4529
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: QueryShortNamePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
4530
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.13", ngImport: i0, type: QueryShortNamePipe, isStandalone: true, name: "queryShortName" }); }
4497
4531
  }
4498
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: QueryShortNamePipe, decorators: [{
4532
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: QueryShortNamePipe, decorators: [{
4499
4533
  type: Pipe,
4500
4534
  args: [{ name: 'queryShortName' }]
4501
4535
  }] });
@@ -4517,19 +4551,19 @@ class QueryDevtoolsComponent {
4517
4551
  this._cdr = inject(ChangeDetectorRef);
4518
4552
  this._destroy$ = createDestroy();
4519
4553
  this.queryClientConfigs = inject(QUERY_CLIENT_DEVTOOLS_TOKEN);
4520
- this.isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
4521
- this.isTranslucent = signal(false, ...(ngDevMode ? [{ debugName: "isTranslucent" }] : []));
4522
- this.snapLayout = signal('full', ...(ngDevMode ? [{ debugName: "snapLayout" }] : []));
4523
- this.queryListMode = signal('live', ...(ngDevMode ? [{ debugName: "queryListMode" }] : []));
4524
- this.viewMode = signal('query', ...(ngDevMode ? [{ debugName: "viewMode" }] : []));
4525
- this.showResponse = signal(false, ...(ngDevMode ? [{ debugName: "showResponse" }] : []));
4526
- this.showRawResponse = signal(false, ...(ngDevMode ? [{ debugName: "showRawResponse" }] : []));
4527
- this.showQueryConfig = signal(false, ...(ngDevMode ? [{ debugName: "showQueryConfig" }] : []));
4528
- this.showEntityStoreValue = signal(false, ...(ngDevMode ? [{ debugName: "showEntityStoreValue" }] : []));
4529
- this.showArguments = signal(false, ...(ngDevMode ? [{ debugName: "showArguments" }] : []));
4554
+ this.isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
4555
+ this.isTranslucent = signal(false, ...(ngDevMode ? [{ debugName: "isTranslucent" }] : /* istanbul ignore next */ []));
4556
+ this.snapLayout = signal('full', ...(ngDevMode ? [{ debugName: "snapLayout" }] : /* istanbul ignore next */ []));
4557
+ this.queryListMode = signal('live', ...(ngDevMode ? [{ debugName: "queryListMode" }] : /* istanbul ignore next */ []));
4558
+ this.viewMode = signal('query', ...(ngDevMode ? [{ debugName: "viewMode" }] : /* istanbul ignore next */ []));
4559
+ this.showResponse = signal(false, ...(ngDevMode ? [{ debugName: "showResponse" }] : /* istanbul ignore next */ []));
4560
+ this.showRawResponse = signal(false, ...(ngDevMode ? [{ debugName: "showRawResponse" }] : /* istanbul ignore next */ []));
4561
+ this.showQueryConfig = signal(false, ...(ngDevMode ? [{ debugName: "showQueryConfig" }] : /* istanbul ignore next */ []));
4562
+ this.showEntityStoreValue = signal(false, ...(ngDevMode ? [{ debugName: "showEntityStoreValue" }] : /* istanbul ignore next */ []));
4563
+ this.showArguments = signal(false, ...(ngDevMode ? [{ debugName: "showArguments" }] : /* istanbul ignore next */ []));
4530
4564
  this.selectedClientIdCtrl = new FormControl(0);
4531
4565
  this.selectedClientId = toSignal(this.selectedClientIdCtrl.valueChanges.pipe(startWith(this.selectedClientIdCtrl.value)));
4532
- this.selectedQueryId = signal(null, ...(ngDevMode ? [{ debugName: "selectedQueryId" }] : []));
4566
+ this.selectedQueryId = signal(null, ...(ngDevMode ? [{ debugName: "selectedQueryId" }] : /* istanbul ignore next */ []));
4533
4567
  this.selectedClientConfig = computed(() => {
4534
4568
  if (this.queryClientConfigs.length === 1) {
4535
4569
  return this.queryClientConfigs[0];
@@ -4540,11 +4574,11 @@ class QueryDevtoolsComponent {
4540
4574
  return this.queryClientConfigs[0];
4541
4575
  }
4542
4576
  return cfg;
4543
- }, ...(ngDevMode ? [{ debugName: "selectedClientConfig" }] : []));
4577
+ }, ...(ngDevMode ? [{ debugName: "selectedClientConfig" }] : /* istanbul ignore next */ []));
4544
4578
  this.queryStore = computed(() => {
4545
4579
  const config = this.selectedClientConfig();
4546
4580
  return config.client._store;
4547
- }, ...(ngDevMode ? [{ debugName: "queryStore" }] : []));
4581
+ }, ...(ngDevMode ? [{ debugName: "queryStore" }] : /* istanbul ignore next */ []));
4548
4582
  this.queryStore$ = toObservable(this.queryStore);
4549
4583
  this._queries$ = new BehaviorSubject([]);
4550
4584
  this.queries = toSignal(this._queries$);
@@ -4558,14 +4592,14 @@ class QueryDevtoolsComponent {
4558
4592
  return this.queries()?.find((q) => q._id === id) ?? null;
4559
4593
  }
4560
4594
  return this.queryHistory$.getValue()?.find((q) => q._id === id) ?? null;
4561
- }, ...(ngDevMode ? [{ debugName: "selectedQuery" }] : []));
4595
+ }, ...(ngDevMode ? [{ debugName: "selectedQuery" }] : /* istanbul ignore next */ []));
4562
4596
  this.selectedQuery$ = toObservable(this.selectedQuery);
4563
4597
  this.selectedQueryEntityStore = computed(() => {
4564
4598
  const query = this.selectedQuery();
4565
4599
  if (!query)
4566
4600
  return null;
4567
4601
  return query.store;
4568
- }, ...(ngDevMode ? [{ debugName: "selectedQueryEntityStore" }] : []));
4602
+ }, ...(ngDevMode ? [{ debugName: "selectedQueryEntityStore" }] : /* istanbul ignore next */ []));
4569
4603
  this.selectedQueryEntityStore$ = toObservable(this.selectedQueryEntityStore);
4570
4604
  this.selectedQueryEntityStoreValue$ = this.selectedQueryEntityStore$.pipe(switchMap((s) => s?._change$.pipe(startWith(''), map(() => {
4571
4605
  if (!s._dictionary)
@@ -4603,7 +4637,7 @@ class QueryDevtoolsComponent {
4603
4637
  return {
4604
4638
  ...sharedCfg,
4605
4639
  };
4606
- }, ...(ngDevMode ? [{ debugName: "stringifiedQueryConfig" }] : []));
4640
+ }, ...(ngDevMode ? [{ debugName: "stringifiedQueryConfig" }] : /* istanbul ignore next */ []));
4607
4641
  this.authProvider = toSignal(toObservable(this.selectedClientConfig).pipe(switchMap((c) => c.client.authProvider$)));
4608
4642
  this.authProviderDetails = computed(() => {
4609
4643
  const provider = this.authProvider();
@@ -4665,7 +4699,7 @@ class QueryDevtoolsComponent {
4665
4699
  config: {},
4666
4700
  };
4667
4701
  }
4668
- }, ...(ngDevMode ? [{ debugName: "authProviderDetails" }] : []));
4702
+ }, ...(ngDevMode ? [{ debugName: "authProviderDetails" }] : /* istanbul ignore next */ []));
4669
4703
  this.trackByClient = (_, { client }) => client.config.baseRoute;
4670
4704
  this.trackByQuery = (_, { _id }) => _id;
4671
4705
  this.selectedClientIdCtrl.valueChanges
@@ -4786,10 +4820,10 @@ class QueryDevtoolsComponent {
4786
4820
  clearQueryHistory() {
4787
4821
  this.queryHistory$.next([]);
4788
4822
  }
4789
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: QueryDevtoolsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4790
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", 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: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: QueryDirective, selector: "[etQuery]", inputs: ["etQuery", "etQueryCache"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: QueryShortNamePipe, name: "queryShortName" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom }); }
4823
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: QueryDevtoolsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4824
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", 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: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: QueryDirective, selector: "[etQuery]", inputs: ["etQuery", "etQueryCache"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: QueryShortNamePipe, name: "queryShortName" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom }); }
4791
4825
  }
4792
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: QueryDevtoolsComponent, decorators: [{
4826
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: QueryDevtoolsComponent, decorators: [{
4793
4827
  type: Component,
4794
4828
  args: [{ selector: 'et-query-devtools', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.ShadowDom, host: {
4795
4829
  class: 'et-query-devtools',
@@ -5040,26 +5074,17 @@ const createQueryRepository = (config) => {
5040
5074
  else {
5041
5075
  const consumers = new Map([]);
5042
5076
  consumers.set(consumerDestroyRef, destroyListener);
5043
- const eventSubscription = combineLatest([
5044
- toObservable(request.error, { injector: config.dependencies.injector }),
5045
- toObservable(request.response, { injector: config.dependencies.injector }),
5046
- ]).subscribe(([errorValue, responseValue]) => {
5047
- if (errorValue?.raw instanceof HttpErrorResponse) {
5048
- eventsSubject.next({
5049
- type: 'request-error',
5050
- error: errorValue.raw,
5051
- key,
5052
- isSecure,
5053
- request,
5054
- });
5077
+ // Drive repository events off the request's discrete, terminal event stream rather than
5078
+ // recombining the `error` + `response` signals via combineLatest (which could observe stale
5079
+ // pairings). Each settle emits exactly one terminal event.
5080
+ const eventSubscription = request.events$.subscribe((event) => {
5081
+ if (event.type === 'error') {
5082
+ if (event.error.raw instanceof HttpErrorResponse) {
5083
+ eventsSubject.next({ type: 'request-error', error: event.error.raw, key, isSecure, request });
5084
+ }
5055
5085
  }
5056
- else if (responseValue !== null && !errorValue) {
5057
- eventsSubject.next({
5058
- type: 'request-success',
5059
- key,
5060
- isSecure,
5061
- request,
5062
- });
5086
+ else if (event.type === HttpEventType.Response) {
5087
+ eventsSubject.next({ type: 'request-success', key, isSecure, request });
5063
5088
  }
5064
5089
  });
5065
5090
  cache.set(key, {
@@ -5164,7 +5189,10 @@ const setupLeaderElection = () => {
5164
5189
  const leaderTimeout = 3000;
5165
5190
  const storageKey = 'ethlete-auth-leader-heartbeat';
5166
5191
  const tabId = `tab-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
5167
- const isLeader = signal(false, ...(ngDevMode ? [{ debugName: "isLeader" }] : []));
5192
+ const isLeader = signal(false, ...(ngDevMode ? [{ debugName: "isLeader" }] : /* istanbul ignore next */ []));
5193
+ const instanceCount = signal(1, ...(ngDevMode ? [{ debugName: "instanceCount" }] : /* istanbul ignore next */ []));
5194
+ const knownTabs = new Map();
5195
+ knownTabs.set(tabId, Date.now());
5168
5196
  let channel = null;
5169
5197
  let heartbeatIntervalId = null;
5170
5198
  let leaderCheckIntervalId = null;
@@ -5172,6 +5200,7 @@ const setupLeaderElection = () => {
5172
5200
  isLeader.set(true);
5173
5201
  return {
5174
5202
  isLeader: isLeader.asReadonly(),
5203
+ instanceCount: instanceCount.asReadonly(),
5175
5204
  becomeLeader: () => {
5176
5205
  /* no-op */
5177
5206
  },
@@ -5181,6 +5210,7 @@ const setupLeaderElection = () => {
5181
5210
  };
5182
5211
  }
5183
5212
  channel = new BroadcastChannel(channelName);
5213
+ channel.postMessage({ type: 'instance-register', tabId });
5184
5214
  const updateLeaderHeartbeat = (newTabId = tabId) => {
5185
5215
  try {
5186
5216
  localStorage.setItem(storageKey, JSON.stringify({ tabId: newTabId, timestamp: Date.now() }));
@@ -5227,48 +5257,60 @@ const setupLeaderElection = () => {
5227
5257
  const heartbeat = getLeaderHeartbeat();
5228
5258
  const now = Date.now();
5229
5259
  if (!heartbeat || now - heartbeat.timestamp > leaderTimeout) {
5230
- // No leader or leader is dead
5231
5260
  if (!isLeader()) {
5232
5261
  becomeLeader();
5233
5262
  }
5234
5263
  }
5235
5264
  else if (heartbeat.tabId === tabId) {
5236
- // We are the leader, update heartbeat
5237
5265
  if (!isLeader()) {
5238
5266
  isLeader.set(true);
5239
5267
  }
5240
5268
  updateLeaderHeartbeat();
5241
5269
  }
5242
5270
  else {
5243
- // Another tab is leader
5244
5271
  if (isLeader()) {
5245
5272
  isLeader.set(false);
5246
5273
  }
5247
5274
  }
5248
5275
  };
5249
- // Handle messages from other tabs
5250
5276
  channel.onmessage = (event) => {
5251
5277
  const message = event.data;
5252
5278
  if (message.type === 'heartbeat') {
5279
+ if (message.tabId !== tabId) {
5280
+ knownTabs.set(message.tabId, Date.now());
5281
+ }
5253
5282
  if (message.tabId !== tabId && isLeader()) {
5254
- // Another tab claims to be leader, resolve conflict
5255
5283
  const heartbeat = getLeaderHeartbeat();
5256
5284
  if (heartbeat && heartbeat.tabId === message.tabId) {
5257
- // Other tab is legitimate leader
5258
5285
  releaseLeadership();
5259
5286
  }
5260
5287
  }
5261
5288
  }
5289
+ else if (message.type === 'tab-heartbeat') {
5290
+ if (message.tabId !== tabId) {
5291
+ knownTabs.set(message.tabId, Date.now());
5292
+ }
5293
+ }
5294
+ else if (message.type === 'instance-register') {
5295
+ if (message.tabId !== tabId) {
5296
+ knownTabs.set(message.tabId, Date.now());
5297
+ instanceCount.set(knownTabs.size);
5298
+ channel?.postMessage({ type: 'tab-heartbeat', tabId });
5299
+ }
5300
+ }
5301
+ else if (message.type === 'instance-unregister') {
5302
+ if (message.tabId !== tabId) {
5303
+ knownTabs.delete(message.tabId);
5304
+ instanceCount.set(knownTabs.size);
5305
+ }
5306
+ }
5262
5307
  else if (message.type === 'leader-claim') {
5263
5308
  if (message.tabId !== tabId && isLeader()) {
5264
- // Conflict: both tabs think they're leader
5265
- // Let the tab with earlier heartbeat win
5266
5309
  const heartbeat = getLeaderHeartbeat();
5267
5310
  if (heartbeat && heartbeat.tabId === message.tabId) {
5268
5311
  releaseLeadership();
5269
5312
  }
5270
5313
  else {
5271
- // We were leader first, send heartbeat to assert dominance
5272
5314
  const assertMessage = {
5273
5315
  type: 'heartbeat',
5274
5316
  tabId,
@@ -5279,35 +5321,40 @@ const setupLeaderElection = () => {
5279
5321
  }
5280
5322
  else if (message.type === 'leader-release') {
5281
5323
  if (message.tabId !== tabId) {
5282
- // Leader released, try to become new leader
5283
5324
  setTimeout(() => checkLeaderStatus(), 100);
5284
5325
  }
5285
5326
  }
5286
5327
  };
5287
- // Try to become leader on startup
5288
5328
  checkLeaderStatus();
5289
- // Send heartbeat periodically if we're the leader
5290
5329
  heartbeatIntervalId = setInterval(() => {
5330
+ knownTabs.set(tabId, Date.now());
5291
5331
  if (isLeader()) {
5292
5332
  updateLeaderHeartbeat();
5293
- const message = {
5294
- type: 'heartbeat',
5295
- tabId,
5296
- };
5297
- channel?.postMessage(message);
5333
+ channel?.postMessage({ type: 'heartbeat', tabId });
5334
+ }
5335
+ else {
5336
+ channel?.postMessage({ type: 'tab-heartbeat', tabId });
5337
+ }
5338
+ const now = Date.now();
5339
+ let changed = false;
5340
+ for (const [id, lastSeen] of knownTabs) {
5341
+ if (id !== tabId && now - lastSeen > leaderTimeout) {
5342
+ knownTabs.delete(id);
5343
+ changed = true;
5344
+ }
5345
+ }
5346
+ if (changed) {
5347
+ instanceCount.set(knownTabs.size);
5298
5348
  }
5299
5349
  }, heartbeatInterval);
5300
- // Check leader status periodically
5301
5350
  leaderCheckIntervalId = setInterval(() => {
5302
5351
  checkLeaderStatus();
5303
5352
  }, heartbeatInterval);
5304
- // Handle tab visibility changes
5305
5353
  const handleVisibilityChange = () => {
5306
5354
  if (document.hidden && isLeader()) {
5307
5355
  // Tab is hidden but we're leader - keep leadership but other tabs will take over if we die
5308
5356
  }
5309
5357
  else if (!document.hidden && !isLeader()) {
5310
- // Tab became visible and we're not leader - check if we should become leader
5311
5358
  checkLeaderStatus();
5312
5359
  }
5313
5360
  };
@@ -5319,10 +5366,10 @@ const setupLeaderElection = () => {
5319
5366
  if (leaderCheckIntervalId) {
5320
5367
  clearInterval(leaderCheckIntervalId);
5321
5368
  }
5369
+ channel?.postMessage({ type: 'instance-unregister', tabId });
5322
5370
  releaseLeadership();
5323
5371
  document.removeEventListener('visibilitychange', handleVisibilityChange);
5324
5372
  channel?.close();
5325
- // Clean up storage if we were the leader
5326
5373
  const heartbeat = getLeaderHeartbeat();
5327
5374
  if (heartbeat?.tabId === tabId) {
5328
5375
  try {
@@ -5336,6 +5383,7 @@ const setupLeaderElection = () => {
5336
5383
  destroyRef.onDestroy(cleanup);
5337
5384
  return {
5338
5385
  isLeader: isLeader.asReadonly(),
5386
+ instanceCount: instanceCount.asReadonly(),
5339
5387
  becomeLeader,
5340
5388
  cleanup,
5341
5389
  };
@@ -5516,11 +5564,20 @@ const defaultExtractTokens = (response) => {
5516
5564
  }
5517
5565
  return { accessToken: response['accessToken'], refreshToken: response['refreshToken'] };
5518
5566
  };
5519
- const setupBearerQueryRegistry = (builders, injector, latestExecutedQuery, latestNonInternalQuery, setTokens) => {
5567
+ const deriveExecutionStateType = (builder, triggeredBy) => {
5568
+ if (triggeredBy === 'persistent-auth')
5569
+ return 'autoLogin';
5570
+ if (builder._type === 'tokenRefreshQuery')
5571
+ return 'tokenRefresh';
5572
+ if (triggeredBy === 'token-revocation')
5573
+ return 'revocation';
5574
+ return builder.key;
5575
+ };
5576
+ const setupBearerQueryRegistry = (builders, injector, latestExecutedQuery, latestNonInternalQuery, setTokens, executionState) => {
5520
5577
  const queries = {};
5521
5578
  const querySnapshots = new Map();
5522
5579
  for (const builder of builders) {
5523
- const querySnapshot = signal(null, ...(ngDevMode ? [{ debugName: "querySnapshot" }] : []));
5580
+ const querySnapshot = signal(null, ...(ngDevMode ? [{ debugName: "querySnapshot" }] : /* istanbul ignore next */ []));
5524
5581
  querySnapshots.set(builder.key, querySnapshot);
5525
5582
  const extractTokens = builder.config.extractTokens ?? defaultExtractTokens;
5526
5583
  effect(() => {
@@ -5549,10 +5606,27 @@ const setupBearerQueryRegistry = (builders, injector, latestExecutedQuery, lates
5549
5606
  });
5550
5607
  query.execute({ args, options });
5551
5608
  const snapshot = query.createSnapshot();
5552
- latestExecutedQuery.set({ key: builder.key, snapshot });
5553
- if (!snapshot.triggeredBy()) {
5554
- latestNonInternalQuery.set({ key: builder.key, snapshot });
5609
+ const stateType = deriveExecutionStateType(builder, options?.triggeredBy);
5610
+ if (stateType !== 'revocation') {
5611
+ latestExecutedQuery.set({ key: builder.key, snapshot });
5612
+ if (!snapshot.triggeredBy()) {
5613
+ latestNonInternalQuery.set({ key: builder.key, snapshot });
5614
+ }
5555
5615
  }
5616
+ executionState.set({ type: stateType, state: 'loading' });
5617
+ effect(() => {
5618
+ const response = snapshot.response();
5619
+ const loading = snapshot.loading();
5620
+ const error = snapshot.error();
5621
+ if (loading)
5622
+ return;
5623
+ if (error) {
5624
+ executionState.set({ type: stateType, state: 'error', error });
5625
+ }
5626
+ else if (response) {
5627
+ executionState.set({ type: stateType, state: 'success', response });
5628
+ }
5629
+ }, { injector });
5556
5630
  querySnapshot.set(snapshot);
5557
5631
  return snapshot;
5558
5632
  };
@@ -5602,13 +5676,18 @@ const createLeaderElection = (config) => {
5602
5676
  const leaderElectionEnabled = multiTabSyncEnabled &&
5603
5677
  (typeof multiTabSyncConfig === 'object' ? (multiTabSyncConfig?.leaderElection ?? true) : true);
5604
5678
  const leaderElection = leaderElectionEnabled ? setupLeaderElection() : null;
5605
- return () => (leaderElectionEnabled ? (leaderElection?.isLeader() ?? true) : true);
5679
+ const isLeaderFn = () => (leaderElectionEnabled ? (leaderElection?.isLeader() ?? true) : true);
5680
+ const leaderElectionContext = leaderElection
5681
+ ? { isLeader: leaderElection.isLeader, instanceCount: leaderElection.instanceCount }
5682
+ : undefined;
5683
+ return { isLeaderFn, leaderElectionContext };
5606
5684
  };
5607
5685
  const createBearerAuthProviderImpl = (config) => {
5608
5686
  const injector = inject(Injector);
5687
+ const destroyRef = inject(DestroyRef);
5609
5688
  const queryClient = config.queryClientRef[1]();
5610
- const accessToken = signal(null, ...(ngDevMode ? [{ debugName: "accessToken" }] : []));
5611
- const refreshToken = signal(null, ...(ngDevMode ? [{ debugName: "refreshToken" }] : []));
5689
+ const accessToken = signal(null, ...(ngDevMode ? [{ debugName: "accessToken" }] : /* istanbul ignore next */ []));
5690
+ const refreshToken = signal(null, ...(ngDevMode ? [{ debugName: "refreshToken" }] : /* istanbul ignore next */ []));
5612
5691
  const afterTokenRefresh$ = new Subject();
5613
5692
  const bearerData = computed(() => {
5614
5693
  const token = accessToken();
@@ -5623,20 +5702,24 @@ const createBearerAuthProviderImpl = (config) => {
5623
5702
  }
5624
5703
  return null;
5625
5704
  }
5626
- }, ...(ngDevMode ? [{ debugName: "bearerData" }] : []));
5627
- const isAuthenticated = computed(() => !!accessToken(), ...(ngDevMode ? [{ debugName: "isAuthenticated" }] : []));
5628
- const latestExecutedQuery = signal(null, ...(ngDevMode ? [{ debugName: "latestExecutedQuery" }] : []));
5629
- const latestNonInternalQuery = signal(null, ...(ngDevMode ? [{ debugName: "latestNonInternalQuery" }] : []));
5705
+ }, ...(ngDevMode ? [{ debugName: "bearerData" }] : /* istanbul ignore next */ []));
5706
+ const isAuthenticated = computed(() => !!accessToken(), ...(ngDevMode ? [{ debugName: "isAuthenticated" }] : /* istanbul ignore next */ []));
5707
+ const latestExecutedQuery = signal(null, ...(ngDevMode ? [{ debugName: "latestExecutedQuery" }] : /* istanbul ignore next */ []));
5708
+ const latestNonInternalQuery = signal(null, ...(ngDevMode ? [{ debugName: "latestNonInternalQuery" }] : /* istanbul ignore next */ []));
5709
+ const executionState = signal(null, ...(ngDevMode ? [{ debugName: "executionState" }] : /* istanbul ignore next */ []));
5630
5710
  const setTokens = (access, refresh) => {
5631
5711
  accessToken.set(access);
5632
5712
  refreshToken.set(refresh);
5633
5713
  afterTokenRefresh$.next();
5634
5714
  };
5635
- const { queries } = setupBearerQueryRegistry(config.queries, injector, latestExecutedQuery, latestNonInternalQuery, setTokens);
5715
+ const { queries } = setupBearerQueryRegistry(config.queries, injector, latestExecutedQuery, latestNonInternalQuery, setTokens, executionState);
5636
5716
  const logout = () => {
5637
5717
  accessToken.set(null);
5638
5718
  refreshToken.set(null);
5639
5719
  queryClient.repository.unbindAllSecure();
5720
+ latestExecutedQuery.set(null);
5721
+ latestNonInternalQuery.set(null);
5722
+ executionState.set({ type: 'logout', state: 'success' });
5640
5723
  };
5641
5724
  const isLeader = createLeaderElection(config);
5642
5725
  const querySetupContext = {
@@ -5645,7 +5728,7 @@ const createBearerAuthProviderImpl = (config) => {
5645
5728
  bearerDecryptFn: config.bearerDecryptFn,
5646
5729
  queryClient,
5647
5730
  repository: queryClient.repository,
5648
- isLeader,
5731
+ isLeader: isLeader.isLeaderFn,
5649
5732
  afterTokenRefresh$,
5650
5733
  queries: queries,
5651
5734
  };
@@ -5658,10 +5741,13 @@ const createBearerAuthProviderImpl = (config) => {
5658
5741
  bearerData,
5659
5742
  logout,
5660
5743
  injector,
5744
+ destroyRef,
5661
5745
  setTokens,
5662
- isLeader,
5746
+ isLeader: isLeader.isLeaderFn,
5747
+ leaderElection: isLeader.leaderElectionContext,
5663
5748
  afterTokenRefresh$,
5664
5749
  queries: queries,
5750
+ executionState,
5665
5751
  };
5666
5752
  const features = setupFeatures(config.features, featureSetupContext);
5667
5753
  setupMultiTabSyncIfEnabled(config, accessToken, refreshToken, queryClient);
@@ -5674,6 +5760,7 @@ const createBearerAuthProviderImpl = (config) => {
5674
5760
  isAuthenticated,
5675
5761
  latestExecutedQuery: latestExecutedQuery.asReadonly(),
5676
5762
  latestNonInternalQuery: latestNonInternalQuery.asReadonly(),
5763
+ executionState: executionState.asReadonly(),
5677
5764
  logout,
5678
5765
  afterTokenRefresh$,
5679
5766
  };
@@ -5823,8 +5910,8 @@ const withInactivityLogout = (config = {}) => {
5823
5910
  const activityEvents = config.activityEvents ?? ['mousedown', 'keydown', 'scroll', 'touchstart'];
5824
5911
  const destroyRef = inject(DestroyRef);
5825
5912
  const document = inject(DOCUMENT);
5826
- const enabled = signal(true, ...(ngDevMode ? [{ debugName: "enabled" }] : []));
5827
- const lastActivityTime = signal(Date.now(), ...(ngDevMode ? [{ debugName: "lastActivityTime" }] : []));
5913
+ const enabled = signal(true, ...(ngDevMode ? [{ debugName: "enabled" }] : /* istanbul ignore next */ []));
5914
+ const lastActivityTime = signal(Date.now(), ...(ngDevMode ? [{ debugName: "lastActivityTime" }] : /* istanbul ignore next */ []));
5828
5915
  const resetTimer = () => {
5829
5916
  lastActivityTime.set(Date.now());
5830
5917
  };
@@ -5907,7 +5994,7 @@ const createPersistentAuthFeature = (config, context) => {
5907
5994
  }
5908
5995
  return config.defaultRememberMe ?? false;
5909
5996
  };
5910
- const rememberMeSignal = signal(initializeRememberMe(), ...(ngDevMode ? [{ debugName: "rememberMeSignal" }] : []));
5997
+ const rememberMeSignal = signal(initializeRememberMe(), ...(ngDevMode ? [{ debugName: "rememberMeSignal" }] : /* istanbul ignore next */ []));
5911
5998
  effect(() => {
5912
5999
  const token = refreshToken();
5913
6000
  const rememberMe = rememberMeSignal();
@@ -5968,7 +6055,7 @@ const withTokenExpirationWarning = (config = {}) => {
5968
6055
  if (typeof exp !== 'number')
5969
6056
  return null;
5970
6057
  return new Date(exp * 1000);
5971
- }, ...(ngDevMode ? [{ debugName: "expiresAt" }] : []));
6058
+ }, ...(ngDevMode ? [{ debugName: "expiresAt" }] : /* istanbul ignore next */ []));
5972
6059
  const expiresIn$ = combineLatest([interval(checkInterval), toObservable(context.bearerData)]).pipe(map(() => {
5973
6060
  const expiry = expiresAt();
5974
6061
  if (!expiry)
@@ -5999,23 +6086,26 @@ const withTokenExpirationWarning = (config = {}) => {
5999
6086
  const withTokenRevocation = (config) => {
6000
6087
  return (context) => {
6001
6088
  const revokeOnLogout = config.revokeOnLogout ?? true;
6002
- const enabled = signal(true, ...(ngDevMode ? [{ debugName: "enabled" }] : []));
6089
+ const enabled = signal(true, ...(ngDevMode ? [{ debugName: "enabled" }] : /* istanbul ignore next */ []));
6003
6090
  let previousAccessToken = null;
6091
+ let previousRefreshToken = null;
6004
6092
  let currentRevocationSnapshot = null;
6005
- const revoke = () => {
6093
+ const revokeWithTokens = (accessToken, refreshToken) => {
6006
6094
  if (currentRevocationSnapshot?.isAlive())
6007
6095
  return currentRevocationSnapshot;
6008
- const accessToken = context.accessToken();
6009
- const refreshToken = context.refreshToken();
6010
6096
  if (!accessToken && !refreshToken) {
6011
6097
  return null;
6012
6098
  }
6013
6099
  const args = config.buildArgs({ accessToken, refreshToken });
6100
+ context.executionState.set({ type: 'revocation', state: 'loading' });
6014
6101
  currentRevocationSnapshot = context.queries[config.queryKey].execute(args, {
6015
6102
  triggeredBy: 'token-revocation',
6016
6103
  });
6017
6104
  return currentRevocationSnapshot;
6018
6105
  };
6106
+ const revoke = () => {
6107
+ return revokeWithTokens(context.accessToken(), context.refreshToken());
6108
+ };
6019
6109
  const enable = () => {
6020
6110
  enabled.set(true);
6021
6111
  };
@@ -6025,10 +6115,12 @@ const withTokenRevocation = (config) => {
6025
6115
  if (revokeOnLogout) {
6026
6116
  effect(() => {
6027
6117
  const currentToken = context.accessToken();
6118
+ const currentRefreshToken = context.refreshToken();
6028
6119
  if (previousAccessToken && !currentToken && enabled()) {
6029
- untracked(() => revoke());
6120
+ untracked(() => revokeWithTokens(previousAccessToken, previousRefreshToken));
6030
6121
  }
6031
6122
  previousAccessToken = currentToken;
6123
+ previousRefreshToken = currentRefreshToken;
6032
6124
  }, { injector: context.injector });
6033
6125
  }
6034
6126
  const instance = {
@@ -6074,7 +6166,7 @@ const createTrackingFeature = (context, config) => {
6074
6166
  }
6075
6167
  }
6076
6168
  };
6077
- const emit = (event, data) => {
6169
+ const fireHandlers = (event, data) => {
6078
6170
  const eventHandlers = handlers.get(event);
6079
6171
  if (eventHandlers) {
6080
6172
  eventHandlers.forEach((handler) => {
@@ -6087,6 +6179,27 @@ const createTrackingFeature = (context, config) => {
6087
6179
  });
6088
6180
  }
6089
6181
  };
6182
+ const forwardingChannel = context.leaderElection && typeof BroadcastChannel !== 'undefined'
6183
+ ? new BroadcastChannel('ethlete-auth-tracking')
6184
+ : null;
6185
+ if (forwardingChannel) {
6186
+ forwardingChannel.onmessage = (messageEvent) => {
6187
+ if (context.isLeader()) {
6188
+ fireHandlers(messageEvent.data.event, messageEvent.data.data);
6189
+ }
6190
+ };
6191
+ context.destroyRef.onDestroy(() => forwardingChannel.close());
6192
+ }
6193
+ const emit = (event, data) => {
6194
+ if (forwardingChannel && !context.isLeader()) {
6195
+ forwardingChannel.postMessage({ event, data });
6196
+ return;
6197
+ }
6198
+ fireHandlers(event, data);
6199
+ };
6200
+ const emitDirect = (event, data) => {
6201
+ fireHandlers(event, data);
6202
+ };
6090
6203
  const trackedQueries = new Map();
6091
6204
  Object.entries(context.queries).forEach(([key, queryEntry]) => {
6092
6205
  const query = queryEntry; // eslint-disable-line @typescript-eslint/no-explicit-any
@@ -6103,17 +6216,11 @@ const createTrackingFeature = (context, config) => {
6103
6216
  const prevState = trackedQueries.get(key);
6104
6217
  if (response && !loading && !error && prevState?.lastResult !== 'success') {
6105
6218
  trackedQueries.set(key, { loading: false, lastResult: 'success' });
6106
- emit(`${key}Success`, {
6107
- queryKey: key,
6108
- snapshot,
6109
- });
6219
+ emit(`${key}Success`, { snapshot });
6110
6220
  }
6111
6221
  if (error && !loading && prevState?.lastResult !== 'error') {
6112
6222
  trackedQueries.set(key, { loading: false, lastResult: 'error' });
6113
- emit(`${key}Failure`, {
6114
- queryKey: key,
6115
- error,
6116
- });
6223
+ emit(`${key}Failure`, { error });
6117
6224
  }
6118
6225
  if (loading) {
6119
6226
  trackedQueries.set(key, { loading: true, lastResult: null });
@@ -6143,6 +6250,17 @@ const createTrackingFeature = (context, config) => {
6143
6250
  }
6144
6251
  });
6145
6252
  }
6253
+ if (context.leaderElection) {
6254
+ const { isLeader: isLeaderSignal, instanceCount: instanceCountSignal } = context.leaderElection;
6255
+ effect(() => {
6256
+ emitDirect('leaderStatusChange', { isLeader: isLeaderSignal() });
6257
+ });
6258
+ effect(() => {
6259
+ emitDirect('leaderInstanceCountChange', {
6260
+ count: instanceCountSignal(),
6261
+ });
6262
+ });
6263
+ }
6146
6264
  return {
6147
6265
  on,
6148
6266
  off,
@@ -6326,10 +6444,10 @@ class ParseHttpErrorCodeToTitleDePipe {
6326
6444
  constructor() {
6327
6445
  this.transform = parseHttpErrorCodeToTitleDe;
6328
6446
  }
6329
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ParseHttpErrorCodeToTitleDePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
6330
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.1", ngImport: i0, type: ParseHttpErrorCodeToTitleDePipe, isStandalone: true, name: "parseHttpErrorCodeToTitleDe" }); }
6447
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ParseHttpErrorCodeToTitleDePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
6448
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.13", ngImport: i0, type: ParseHttpErrorCodeToTitleDePipe, isStandalone: true, name: "parseHttpErrorCodeToTitleDe" }); }
6331
6449
  }
6332
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ParseHttpErrorCodeToTitleDePipe, decorators: [{
6450
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ParseHttpErrorCodeToTitleDePipe, decorators: [{
6333
6451
  type: Pipe,
6334
6452
  args: [{
6335
6453
  name: 'parseHttpErrorCodeToTitleDe',
@@ -6339,10 +6457,10 @@ class ParseHttpErrorCodeToMessageDePipe {
6339
6457
  constructor() {
6340
6458
  this.transform = parseHttpErrorCodeToMessageDe;
6341
6459
  }
6342
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ParseHttpErrorCodeToMessageDePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
6343
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.1", ngImport: i0, type: ParseHttpErrorCodeToMessageDePipe, isStandalone: true, name: "parseHttpErrorCodeToMessageDe" }); }
6460
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ParseHttpErrorCodeToMessageDePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
6461
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.13", ngImport: i0, type: ParseHttpErrorCodeToMessageDePipe, isStandalone: true, name: "parseHttpErrorCodeToMessageDe" }); }
6344
6462
  }
6345
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ParseHttpErrorCodeToMessageDePipe, decorators: [{
6463
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ParseHttpErrorCodeToMessageDePipe, decorators: [{
6346
6464
  type: Pipe,
6347
6465
  args: [{
6348
6466
  name: 'parseHttpErrorCodeToMessageDe',
@@ -6526,10 +6644,10 @@ class ParseHttpErrorCodeToTitleEnPipe {
6526
6644
  constructor() {
6527
6645
  this.transform = parseHttpErrorCodeToTitleEn;
6528
6646
  }
6529
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ParseHttpErrorCodeToTitleEnPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
6530
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.1", ngImport: i0, type: ParseHttpErrorCodeToTitleEnPipe, isStandalone: true, name: "parseHttpErrorCodeToTitleEn" }); }
6647
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ParseHttpErrorCodeToTitleEnPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
6648
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.13", ngImport: i0, type: ParseHttpErrorCodeToTitleEnPipe, isStandalone: true, name: "parseHttpErrorCodeToTitleEn" }); }
6531
6649
  }
6532
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ParseHttpErrorCodeToTitleEnPipe, decorators: [{
6650
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ParseHttpErrorCodeToTitleEnPipe, decorators: [{
6533
6651
  type: Pipe,
6534
6652
  args: [{
6535
6653
  name: 'parseHttpErrorCodeToTitleEn',
@@ -6539,10 +6657,10 @@ class ParseHttpErrorCodeToMessageEnPipe {
6539
6657
  constructor() {
6540
6658
  this.transform = parseHttpErrorCodeToMessageEn;
6541
6659
  }
6542
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ParseHttpErrorCodeToMessageEnPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
6543
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.1", ngImport: i0, type: ParseHttpErrorCodeToMessageEnPipe, isStandalone: true, name: "parseHttpErrorCodeToMessageEn" }); }
6660
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ParseHttpErrorCodeToMessageEnPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
6661
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.13", ngImport: i0, type: ParseHttpErrorCodeToMessageEnPipe, isStandalone: true, name: "parseHttpErrorCodeToMessageEn" }); }
6544
6662
  }
6545
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ParseHttpErrorCodeToMessageEnPipe, decorators: [{
6663
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ParseHttpErrorCodeToMessageEnPipe, decorators: [{
6546
6664
  type: Pipe,
6547
6665
  args: [{
6548
6666
  name: 'parseHttpErrorCodeToMessageEn',
@@ -6966,8 +7084,11 @@ class QueryForm {
6966
7084
  continue;
6967
7085
  const valueGotRemoved = value === ET_PROPERTY_REMOVED;
6968
7086
  if (valueGotRemoved) {
6969
- field.control.setValue(this._getDefaultValue(key), { emitEvent: false });
6970
- didValueChanges = true;
7087
+ const defaultValue = this._getDefaultValue(key);
7088
+ if (!equal(field.control.value, defaultValue)) {
7089
+ field.control.setValue(defaultValue, { emitEvent: false });
7090
+ didValueChanges = true;
7091
+ }
6971
7092
  continue;
6972
7093
  }
6973
7094
  let deserializedValue = value;
@@ -7139,6 +7260,21 @@ class QueryForm {
7139
7260
  });
7140
7261
  }
7141
7262
  _handleFormChange(forceOverwrite = false) {
7263
+ // Normalize values that have a valueToQueryParamTransformFn returning null/undefined to their
7264
+ // field default before capturing the new value. This prevents intermediate "empty object" states
7265
+ // (e.g. Sort emitting { active: '', direction: '' } when cleared) from being
7266
+ // emitted as distinct form values.
7267
+ for (const [key, field] of Object.entries(this._fields)) {
7268
+ if (!field.data.valueToQueryParamTransformFn)
7269
+ continue;
7270
+ const rawValue = this._formValue[key];
7271
+ if (this._isDefaultValue(key, rawValue))
7272
+ continue;
7273
+ const serialized = field.data.valueToQueryParamTransformFn(rawValue);
7274
+ if (serialized !== null && serialized !== undefined)
7275
+ continue;
7276
+ this.form.controls[key]?.setValue(this._getDefaultValue(key), { emitEvent: false });
7277
+ }
7142
7278
  const currentVal = clone(this._currentFormValue$.value);
7143
7279
  const newVal = clone(this._formValue);
7144
7280
  if (equal(currentVal, newVal)) {
@@ -7194,17 +7330,17 @@ const createWebSocketClient = (options) => {
7194
7330
  transports: options.transports,
7195
7331
  });
7196
7332
  const rooms = new Map();
7197
- const isConnected = signal(false, ...(ngDevMode ? [{ debugName: "isConnected" }] : []));
7333
+ const isConnected = signal(false, ...(ngDevMode ? [{ debugName: "isConnected" }] : /* istanbul ignore next */ []));
7198
7334
  const joinRoom = (room) => {
7199
7335
  const roomFn = typeof room === 'function' ? room : () => room;
7200
7336
  const pre = previousSignalValue(computed(() => roomFn()));
7201
- const roomData = signal(null, ...(ngDevMode ? [{ debugName: "roomData" }] : []));
7337
+ const roomData = signal(null, ...(ngDevMode ? [{ debugName: "roomData" }] : /* istanbul ignore next */ []));
7202
7338
  const join = (name) => {
7203
7339
  socket.emit('join-room', name);
7204
7340
  const existingRoom = rooms.get(name);
7205
7341
  if (existingRoom)
7206
7342
  return existingRoom;
7207
- const message = signal(null, ...(ngDevMode ? [{ debugName: "message" }] : []));
7343
+ const message = signal(null, ...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
7208
7344
  const newRoom = {
7209
7345
  latestMessage: message,
7210
7346
  };