@ethlete/query 5.43.0 → 5.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @ethlete/query
2
2
 
3
+ ## 5.44.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`8d2efef`](https://github.com/ethlete-io/ethdk/commit/8d2efef2a367db82d44977a3fdfe56396bb46515) Thanks [@TomTomB](https://github.com/TomTomB)! - Minor bump only
8
+
9
+ ## 5.43.2
10
+
11
+ ### Patch Changes
12
+
13
+ - [`830b987`](https://github.com/ethlete-io/ethdk/commit/830b987eba43a51252c3c55eee5590ceef8bf1cb) Thanks [@TomTomB](https://github.com/TomTomB)! - Fix query v3 features not reacting to 204 responses due to null checks
14
+
15
+ ## 5.43.1
16
+
17
+ ### Patch Changes
18
+
19
+ - [`f40e8a2`](https://github.com/ethlete-io/ethdk/commit/f40e8a224a6f0c527f4204e696966a1416da0f43) Thanks [@TomTomB](https://github.com/TomTomB)! - Fix query state observable not getting properly memorized
20
+
21
+ - [`f40e8a2`](https://github.com/ethlete-io/ethdk/commit/f40e8a224a6f0c527f4204e696966a1416da0f43) Thanks [@TomTomB](https://github.com/TomTomB)! - Fix bearer auth provider causing maximum callstack exceeded errors in certain edge cases
22
+
3
23
  ## 5.43.0
4
24
 
5
25
  ### Minor Changes
@@ -1,6 +1,6 @@
1
1
  import * as i1 from '@ethlete/core';
2
2
  import { createDestroy, computedTillTruthy, syncSignal, RuntimeError, isObject, injectRoute, getDomain, getCookie, setCookie, deleteCookie, clamp, previousSignalValue, DelayableDirective, nextFrame, injectQueryParamChanges, injectQueryParams, clone, equal, ET_PROPERTY_REMOVED } from '@ethlete/core';
3
- import { Observable, takeUntil, startWith, pairwise, tap, switchMap, of, BehaviorSubject, Subject, fromEvent, timer, take, Subscription, retry, throwError, catchError, ReplaySubject, map, shareReplay, interval, skip, takeWhile, filter, combineLatest, withLatestFrom, debounceTime, merge } from 'rxjs';
3
+ import { Observable, takeUntil, startWith, pairwise, tap, switchMap, of, BehaviorSubject, Subject, fromEvent, timer, take, Subscription, retry, throwError, catchError, ReplaySubject, map, shareReplay, interval, skip, takeWhile, filter, combineLatest, EMPTY, withLatestFrom, debounceTime, merge } from 'rxjs';
4
4
  import { HttpStatusCode, HttpErrorResponse, HttpEventType, HttpClient, HttpHeaders } from '@angular/common/http';
5
5
  import * as i0 from '@angular/core';
6
6
  import { assertInInjectionContext, inject, Injector, runInInjectionContext, signal, effect, untracked, computed, isDevMode, InjectionToken, EnvironmentInjector, createEnvironmentInjector, DestroyRef, ɵEffectScheduler as _EffectScheduler, ErrorHandler, Pipe, ChangeDetectorRef, input, ViewContainerRef, TemplateRef, Directive, Input, ElementRef, ViewEncapsulation, ChangeDetectionStrategy, Component, NgZone } from '@angular/core';
@@ -1547,11 +1547,11 @@ const withSuccessHandling = (options) => {
1547
1547
  type: QueryFeatureType.WITH_SUCCESS_HANDLING,
1548
1548
  fn: (context) => {
1549
1549
  nestedEffect(() => {
1550
- const response = context.state.response();
1551
- if (response === null)
1550
+ const event = context.state.latestHttpEvent();
1551
+ if (!event || event.type !== HttpEventType.Response)
1552
1552
  return;
1553
1553
  untracked(() => {
1554
- options.handler(response);
1554
+ options.handler(context.state.response());
1555
1555
  });
1556
1556
  }, { injector: context.deps.injector });
1557
1557
  },
@@ -1684,7 +1684,8 @@ const createQuerySnapshotFn = (options) => {
1684
1684
  snapshotState.response.set(currentResponse);
1685
1685
  if (currentLoading)
1686
1686
  return;
1687
- if (!currentResponse && !currentError)
1687
+ const hasCompletedResponse = currentLatestHttpEvent?.type === HttpEventType.Response;
1688
+ if (!hasCompletedResponse && !currentError)
1688
1689
  return;
1689
1690
  // kill the effect once loading is done and we either have a response or an error
1690
1691
  killEffectRef.destroy();
@@ -2084,7 +2085,6 @@ const createHttpRequest = (options) => {
2084
2085
  return true;
2085
2086
  };
2086
2087
  const updateState = (event) => {
2087
- currentEvent.set(event);
2088
2088
  switch (event.type) {
2089
2089
  case HttpEventType.Response:
2090
2090
  {
@@ -2111,6 +2111,7 @@ const createHttpRequest = (options) => {
2111
2111
  }
2112
2112
  break;
2113
2113
  }
2114
+ currentEvent.set(event);
2114
2115
  };
2115
2116
  const updateErrorState = (errorResponse) => {
2116
2117
  const errorRes = createQueryErrorResponse(errorResponse);
@@ -4342,13 +4343,16 @@ class Query {
4342
4343
  return ++this._currentLocalId;
4343
4344
  }
4344
4345
  get state$() {
4345
- return this._state$.pipe(tap((s) => {
4346
- if (!this._client.config.logging?.preparedQuerySubscriptions)
4347
- return;
4348
- if (isQueryStatePrepared(s)) {
4349
- console.warn(`Query ${this._routeWithParams} was subscribed to in the prepared state. Did you forget to call .execute()?`);
4350
- }
4351
- }), switchMap((s) => this._transformState(s)), shareReplay({ bufferSize: 1, refCount: true }));
4346
+ if (!this._memoizedState$) {
4347
+ this._memoizedState$ = this._state$.pipe(tap((s) => {
4348
+ if (!this._client.config.logging?.preparedQuerySubscriptions)
4349
+ return;
4350
+ if (isQueryStatePrepared(s)) {
4351
+ console.warn(`Query ${this._routeWithParams} was subscribed to in the prepared state. Did you forget to call .execute()?`);
4352
+ }
4353
+ }), switchMap((s) => this._transformState(s)), shareReplay({ bufferSize: 1, refCount: true }));
4354
+ }
4355
+ return this._memoizedState$;
4352
4356
  }
4353
4357
  /**
4354
4358
  * The current state of the query.
@@ -4452,6 +4456,7 @@ class Query {
4452
4456
  * @internal
4453
4457
  */
4454
4458
  this._isPollingPaused = false;
4459
+ this._memoizedState$ = null;
4455
4460
  this._state$ = new BehaviorSubject({
4456
4461
  type: "PREPARED" /* QueryStateType.Prepared */,
4457
4462
  meta: { id: this._currentLocalId, triggeredVia: 'program' },
@@ -4493,16 +4498,19 @@ class Query {
4493
4498
  // The tokens might get set without a refresh query being created (e.g.) directly after login.
4494
4499
  authProvider.currentRefreshQuery$.pipe(switchQueryState(), takeUntilResponse()),
4495
4500
  authProvider.tokens$.pipe(take(1)),
4496
- ]).pipe(takeUntil(this._onAbort$), filter(([state, tokens]) => {
4497
- if (state) {
4498
- return !isQueryStateLoading(state);
4501
+ ]).pipe(takeUntil(this._onAbort$), switchMap(([state, tokens]) => {
4502
+ if (state && isQueryStateLoading(state)) {
4503
+ return EMPTY;
4499
4504
  }
4500
- return !!tokens;
4501
- }), tap(([state]) => {
4502
4505
  if (isQueryStateFailure(state)) {
4503
4506
  this._updateEntityState({ type: 'failure', error: state.error, headers: {} }, meta, options);
4507
+ return EMPTY;
4508
+ }
4509
+ if (!state && !(tokens?.token || tokens?.refreshToken)) {
4510
+ return EMPTY;
4504
4511
  }
4505
- }), map(() => true), take(1));
4512
+ return of(true);
4513
+ }), take(1));
4506
4514
  }
4507
4515
  goSignal
4508
4516
  .pipe(switchMap(() => {
@@ -4915,7 +4923,9 @@ class BearerAuthProvider {
4915
4923
  }) ?? {
4916
4924
  body: { refreshToken: currentRefreshToken },
4917
4925
  };
4918
- const query = this._config.refreshConfig.queryCreator.prepare(args).execute({ skipCache: true });
4926
+ const query = this._config.refreshConfig.queryCreator
4927
+ .prepare(args)
4928
+ .execute({ skipCache: true, _isUnauthorizedRetry: true });
4919
4929
  this._currentRefreshQuery$.next(query);
4920
4930
  this._currentRefreshQuery$
4921
4931
  .pipe(switchQueryState(), tap((state) => {