@ethlete/query 5.16.2 → 5.18.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 +16 -0
- package/esm2022/index.mjs +2 -1
- package/esm2022/lib/devtools/components/query-devtools/query-devtools.component.mjs +3 -3
- package/esm2022/lib/devtools/pipes/query-short-name.pipe.mjs +3 -3
- package/esm2022/lib/directives/infinity-query-trigger.directive.mjs +3 -3
- package/esm2022/lib/directives/infinity-query.directive.mjs +3 -3
- package/esm2022/lib/directives/query.directive.mjs +3 -3
- package/esm2022/lib/experimental/bearer-auth-provider-config.mjs +19 -0
- package/esm2022/lib/experimental/bearer-auth-provider.mjs +245 -0
- package/esm2022/lib/experimental/http-request.mjs +153 -0
- package/esm2022/lib/experimental/index.mjs +21 -0
- package/esm2022/lib/experimental/query-client-config.mjs +13 -0
- package/esm2022/lib/experimental/query-client.mjs +16 -0
- package/esm2022/lib/experimental/query-creator-templates.mjs +33 -0
- package/esm2022/lib/experimental/query-creator.mjs +28 -0
- package/esm2022/lib/experimental/query-dependencies.mjs +14 -0
- package/esm2022/lib/experimental/query-errors.mjs +55 -0
- package/esm2022/lib/experimental/query-execute-utils.mjs +57 -0
- package/esm2022/lib/experimental/query-execute.mjs +12 -0
- package/esm2022/lib/experimental/query-features.mjs +126 -0
- package/esm2022/lib/experimental/query-repository.mjs +91 -0
- package/esm2022/lib/experimental/query-snapshot.mjs +44 -0
- package/esm2022/lib/experimental/query-state.mjs +20 -0
- package/esm2022/lib/experimental/query-utils.mjs +148 -0
- package/esm2022/lib/experimental/query.mjs +37 -0
- package/esm2022/lib/experimental/secure-query-creator.mjs +15 -0
- package/esm2022/lib/experimental/secure-query-execute.mjs +77 -0
- package/esm2022/lib/experimental/secure-query.mjs +41 -0
- package/esm2022/lib/query/query.mjs +3 -2
- package/esm2022/lib/query/query.types.mjs +1 -1
- package/esm2022/lib/query-form/query-form.mjs +32 -11
- package/fesm2022/ethlete-query.mjs +1313 -31
- package/fesm2022/ethlete-query.mjs.map +1 -1
- package/index.d.ts +1 -0
- package/lib/experimental/bearer-auth-provider-config.d.ts +111 -0
- package/lib/experimental/bearer-auth-provider.d.ts +63 -0
- package/lib/experimental/http-request.d.ts +55 -0
- package/lib/experimental/index.d.ts +20 -0
- package/lib/experimental/query-client-config.d.ts +18 -0
- package/lib/experimental/query-client.d.ts +10 -0
- package/lib/experimental/query-creator-templates.d.ts +14 -0
- package/lib/experimental/query-creator.d.ts +39 -0
- package/lib/experimental/query-dependencies.d.ts +12 -0
- package/lib/experimental/query-errors.d.ts +39 -0
- package/lib/experimental/query-execute-utils.d.ts +20 -0
- package/lib/experimental/query-execute.d.ts +16 -0
- package/lib/experimental/query-features.d.ts +45 -0
- package/lib/experimental/query-repository.d.ts +31 -0
- package/lib/experimental/query-snapshot.d.ts +8 -0
- package/lib/experimental/query-state.d.ts +14 -0
- package/lib/experimental/query-utils.d.ts +41 -0
- package/lib/experimental/query.d.ts +41 -0
- package/lib/experimental/secure-query-creator.d.ts +7 -0
- package/lib/experimental/secure-query-execute.d.ts +7 -0
- package/lib/experimental/secure-query.d.ts +6 -0
- package/lib/query/query.types.d.ts +2 -1
- package/lib/query-form/query-form.d.ts +3 -1
- package/package.json +1 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import * as i1 from '@ethlete/core';
|
|
2
|
-
import { createDestroy, computedTillTruthy, getCookie, setCookie, deleteCookie, DelayableDirective, nextFrame,
|
|
3
|
-
import { Observable, takeUntil, startWith, pairwise, tap, switchMap, of, BehaviorSubject, Subject, fromEvent, timer, take, filter, takeWhile, map, shareReplay, ReplaySubject, combineLatest, interval, skip, withLatestFrom, debounceTime, merge } from 'rxjs';
|
|
2
|
+
import { createDestroy, computedTillTruthy, getCookie, setCookie, deleteCookie, DelayableDirective, nextFrame, RuntimeError, isObject, getDomain, syncSignal, injectQueryParamChanges, injectQueryParams, clone, equal, ET_PROPERTY_REMOVED } from '@ethlete/core';
|
|
3
|
+
import { Observable, takeUntil, startWith, pairwise, tap, switchMap, of, BehaviorSubject, Subject, fromEvent, timer, take, filter, takeWhile, map, shareReplay, ReplaySubject, combineLatest, interval, skip, withLatestFrom, debounceTime, Subscription, retry, throwError, catchError, merge } from 'rxjs';
|
|
4
4
|
import * as i0 from '@angular/core';
|
|
5
|
-
import { assertInInjectionContext, inject, Injector, computed, signal, isDevMode, untracked, TemplateRef, ViewContainerRef, ErrorHandler, ChangeDetectorRef, Directive, Input, InjectionToken, ElementRef, Pipe, effect, Component, ChangeDetectionStrategy, ViewEncapsulation, NgZone } from '@angular/core';
|
|
5
|
+
import { assertInInjectionContext, inject, Injector, computed, signal, isDevMode, untracked, TemplateRef, ViewContainerRef, ErrorHandler, ChangeDetectorRef, Directive, Input, InjectionToken, ElementRef, Pipe, effect, Component, ChangeDetectionStrategy, ViewEncapsulation, DestroyRef, runInInjectionContext, NgZone } from '@angular/core';
|
|
6
6
|
import { toSignal, toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
7
7
|
import { AsyncPipe, JsonPipe, NgClass } from '@angular/common';
|
|
8
8
|
import * as i1$1 from '@angular/forms';
|
|
9
9
|
import { FormControl, ReactiveFormsModule, FormGroup } from '@angular/forms';
|
|
10
|
+
import { HttpErrorResponse, HttpStatusCode, HttpEventType, HttpClient, HttpHeaders } from '@angular/common/http';
|
|
10
11
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
11
12
|
|
|
12
13
|
class CustomHeaderAuthProvider {
|
|
@@ -154,7 +155,7 @@ const buildQueryString = (params, config) => {
|
|
|
154
155
|
}
|
|
155
156
|
return queryParams.length ? queryParams.join('&') : null;
|
|
156
157
|
};
|
|
157
|
-
const extractExpiresInSeconds = (headers) => {
|
|
158
|
+
const extractExpiresInSeconds$1 = (headers) => {
|
|
158
159
|
const cacheControl = headers['cache-control'];
|
|
159
160
|
const age = headers['age'];
|
|
160
161
|
const expires = headers['expires'];
|
|
@@ -292,7 +293,7 @@ const getResponseUrl = (xhr) => {
|
|
|
292
293
|
}
|
|
293
294
|
return null;
|
|
294
295
|
};
|
|
295
|
-
const shouldRetryRequest = (config) => {
|
|
296
|
+
const shouldRetryRequest$1 = (config) => {
|
|
296
297
|
const defaultRetryDelay = 1000 + 1000 * config.currentRetryCount;
|
|
297
298
|
if (config.currentRetryCount > 3) {
|
|
298
299
|
return { retry: false };
|
|
@@ -339,7 +340,7 @@ const request = (config) => {
|
|
|
339
340
|
const responseType = config.responseType || 'json';
|
|
340
341
|
const body = config.body || null;
|
|
341
342
|
const url = config.urlWithParams.split('?')[0] || '';
|
|
342
|
-
const retryFn = config.retryFn || shouldRetryRequest;
|
|
343
|
+
const retryFn = config.retryFn || shouldRetryRequest$1;
|
|
343
344
|
let currentRetryCount = 0;
|
|
344
345
|
let retryTimeout = null;
|
|
345
346
|
return new Observable((observer) => {
|
|
@@ -432,7 +433,7 @@ const request = (config) => {
|
|
|
432
433
|
headers,
|
|
433
434
|
response: body,
|
|
434
435
|
};
|
|
435
|
-
const expiresInSeconds = config.cacheAdapter?.(headers) ?? extractExpiresInSeconds(headers);
|
|
436
|
+
const expiresInSeconds = config.cacheAdapter?.(headers) ?? extractExpiresInSeconds$1(headers);
|
|
436
437
|
const expiresInTimestamp = buildTimestampFromSeconds(expiresInSeconds);
|
|
437
438
|
if (expiresInTimestamp) {
|
|
438
439
|
successEvent.expiresInTimestamp = expiresInTimestamp;
|
|
@@ -1512,7 +1513,7 @@ class Query {
|
|
|
1512
1513
|
break;
|
|
1513
1514
|
}
|
|
1514
1515
|
case 'success': {
|
|
1515
|
-
const { response, expiresInTimestamp } = requestEvent;
|
|
1516
|
+
const { response, expiresInTimestamp, headers } = requestEvent;
|
|
1516
1517
|
const isGql = isGqlQueryConfig(this._queryConfig);
|
|
1517
1518
|
const responseData = isGql && typeof response === 'object' && !!response && 'data' in response
|
|
1518
1519
|
? response['data']
|
|
@@ -1529,6 +1530,7 @@ class Query {
|
|
|
1529
1530
|
this._updateState({
|
|
1530
1531
|
type: "SUCCESS" /* QueryStateType.Success */,
|
|
1531
1532
|
response: responseData,
|
|
1533
|
+
headers: headers,
|
|
1532
1534
|
meta: { ...meta, expiresAt: expiresInTimestamp },
|
|
1533
1535
|
});
|
|
1534
1536
|
break;
|
|
@@ -1957,10 +1959,10 @@ class QueryDirective {
|
|
|
1957
1959
|
this._viewContainerRef.createEmbeddedView(this._mainTemplateRef, this._viewContext);
|
|
1958
1960
|
}
|
|
1959
1961
|
}
|
|
1960
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.
|
|
1961
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.1.
|
|
1962
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: QueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1963
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.1.4", type: QueryDirective, isStandalone: true, selector: "[etQuery]", inputs: { query: ["etQuery", "query"], cache: ["etQueryCache", "cache"] }, ngImport: i0 }); }
|
|
1962
1964
|
}
|
|
1963
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.
|
|
1965
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: QueryDirective, decorators: [{
|
|
1964
1966
|
type: Directive,
|
|
1965
1967
|
args: [{
|
|
1966
1968
|
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
@@ -2268,10 +2270,10 @@ class InfinityQueryDirective {
|
|
|
2268
2270
|
this._viewContext.currentQuery = null;
|
|
2269
2271
|
this._data$.next([]);
|
|
2270
2272
|
}
|
|
2271
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.
|
|
2272
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.1.
|
|
2273
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: InfinityQueryDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2274
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.1.4", type: InfinityQueryDirective, isStandalone: true, selector: "[etInfinityQuery]", inputs: { infinityQuery: ["etInfinityQuery", "infinityQuery"] }, providers: [{ provide: INFINITY_QUERY_TOKEN, useExisting: InfinityQueryDirective }], exportAs: ["etInfinityQuery"], hostDirectives: [{ directive: i1.DelayableDirective }], ngImport: i0 }); }
|
|
2273
2275
|
}
|
|
2274
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.
|
|
2276
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: InfinityQueryDirective, decorators: [{
|
|
2275
2277
|
type: Directive,
|
|
2276
2278
|
args: [{
|
|
2277
2279
|
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
@@ -2324,10 +2326,10 @@ class InfinityQueryTriggerDirective {
|
|
|
2324
2326
|
});
|
|
2325
2327
|
this._observer.observe(this._elementRef.nativeElement);
|
|
2326
2328
|
}
|
|
2327
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.
|
|
2328
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.1.
|
|
2329
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: InfinityQueryTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2330
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.1.4", type: InfinityQueryTriggerDirective, isStandalone: true, selector: "[etInfinityQueryTrigger], et-infinity-query-trigger", inputs: { scrollContainerSelector: "scrollContainerSelector" }, ngImport: i0 }); }
|
|
2329
2331
|
}
|
|
2330
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.
|
|
2332
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: InfinityQueryTriggerDirective, decorators: [{
|
|
2331
2333
|
type: Directive,
|
|
2332
2334
|
args: [{
|
|
2333
2335
|
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
@@ -2352,10 +2354,10 @@ class QueryShortNamePipe {
|
|
|
2352
2354
|
}
|
|
2353
2355
|
return route;
|
|
2354
2356
|
}
|
|
2355
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.
|
|
2356
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.1.
|
|
2357
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: QueryShortNamePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
2358
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.1.4", ngImport: i0, type: QueryShortNamePipe, isStandalone: true, name: "queryShortName" }); }
|
|
2357
2359
|
}
|
|
2358
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.
|
|
2360
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: QueryShortNamePipe, decorators: [{
|
|
2359
2361
|
type: Pipe,
|
|
2360
2362
|
args: [{ name: 'queryShortName', standalone: true }]
|
|
2361
2363
|
}] });
|
|
@@ -2646,10 +2648,10 @@ class QueryDevtoolsComponent {
|
|
|
2646
2648
|
clearQueryHistory() {
|
|
2647
2649
|
this.queryHistory$.next([]);
|
|
2648
2650
|
}
|
|
2649
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.
|
|
2650
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.1.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 #3c424a;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 #3c424a;margin-bottom:-12px}.et-qd-queries__browser-list{border-right:1px solid #3c424a;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 #3c424a;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 #3c424a;margin-left:-12px;margin-right:-12px;margin-bottom:-12px;padding:12px;overflow-y:auto;overflow-x:hidden}.et-qd-list{display:grid;gap:12px}.et-qd-list-item{display:grid}.et-qd-list-item p{font-weight:700;margin:0;padding-bottom:8px}.et-qd-list-item p+p{margin-top:-8px}.et-qd-list-item div+pre{margin-top:8px}.et-qd-list-item pre{margin:0;padding:4px;background-color:#0e1012;border-radius:4px;max-height:450px;overflow:auto}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: QueryShortNamePipe, name: "queryShortName" }, { kind: "directive", type: QueryDirective, selector: "[etQuery]", inputs: ["etQuery", "etQueryCache"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom }); }
|
|
2651
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: QueryDevtoolsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2652
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.1.4", type: QueryDevtoolsComponent, isStandalone: true, selector: "et-query-devtools", host: { classAttribute: "et-query-devtools" }, ngImport: i0, template: "@if (!isOpen()) {\n <button (click)=\"toggleOpen()\" class=\"et-query-devtools-open-btn et-qd-chip\">Query Devtools</button>\n}\n\n@if (isOpen()) {\n <div\n [class.et-query-devtools-container--transparent]=\"isTranslucent()\"\n class=\"et-query-devtools-container et-query-devtools-container--snap-{{ snapLayout() }}\"\n >\n <header class=\"et-qd-header\">\n <h3 class=\"et-qd-header__title\">Query Devtools</h3>\n\n <div class=\"et-qd-header__select\">\n <label for=\"et-query-client-instance\">Client instance</label>\n <select [formControl]=\"selectedClientIdCtrl\" id=\"et-query-client-instance\">\n @for (clientConfig of queryClientConfigs; track trackByClient(i, clientConfig); let i = $index) {\n <option [value]=\"i\">\n {{ clientConfig.displayName ?? clientConfig.client.config.baseRoute }}\n </option>\n }\n </select>\n </div>\n\n <button (click)=\"toggleOpen()\" class=\"et-qd-btn et-qd-btn-secondary\">Close</button>\n </header>\n\n <div class=\"et-qd-sub-header\">\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !isTranslucent() }\"\n (click)=\"toggleTranslucent()\"\n class=\"et-qd-chip et-qd-translucent-clickable\"\n >\n Translucent\n </button>\n <div class=\"et-qd-sub-header__divider\"></div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'full' }\"\n (click)=\"selectSnapLayout('full')\"\n class=\"et-qd-chip\"\n >\n Fullscreen\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'top' }\"\n (click)=\"selectSnapLayout('top')\"\n class=\"et-qd-chip\"\n >\n Top\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'bottom' }\"\n (click)=\"selectSnapLayout('bottom')\"\n class=\"et-qd-chip\"\n >\n Bottom\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'left' }\"\n (click)=\"selectSnapLayout('left')\"\n class=\"et-qd-chip\"\n >\n Left\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': snapLayout() !== 'right' }\"\n (click)=\"selectSnapLayout('right')\"\n class=\"et-qd-chip\"\n >\n Right\n </button>\n </div>\n\n @if (selectedClientConfig(); as cfg) {\n <div class=\"et-qd-client\">\n <p class=\"et-qd-client__title\">{{ cfg.displayName ?? cfg.client.config.baseRoute }}</p>\n\n <div class=\"et-qd-client__actions\">\n <button (click)=\"cfg.client._store.refreshQueriesInUse()\" class=\"et-qd-chip\">Refresh all</button>\n <button (click)=\"cfg.client._store.refreshQueriesInUse({ ignoreCacheValidity: true })\" class=\"et-qd-chip\">\n Refresh all (ignore caches)\n </button>\n <button\n (click)=\"cfg.client._store.refreshQueriesInUse({ ignoreCacheValidity: true, purgeUnused: true })\"\n class=\"et-qd-chip\"\n >\n Refresh all (ignore caches & purge unused)\n </button>\n </div>\n </div>\n }\n\n @if (selectedClientConfig(); as cfg) {\n <div class=\"et-qd-queries\">\n <p class=\"et-qd-queries__title\">Inspector</p>\n <div class=\"et-qd-queries__actions\">\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': queryListMode() !== 'live' || viewMode() !== 'query' }\"\n (click)=\"selectQueryListMode('live'); selectViewMode('query')\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Live Queries ({{ queries()?.length ?? 0 }})\n </button>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': queryListMode() !== 'history' || viewMode() !== 'query' }\"\n (click)=\"selectQueryListMode('history'); selectViewMode('query')\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Query History ({{ (queryHistory$ | async)?.length ?? 0 }}/50)\n </button>\n @if (queryListMode() === 'history' && viewMode() === 'query') {\n <div class=\"et-qd-queries__divider\"></div>\n <button (click)=\"clearQueryHistory()\" class=\"et-qd-chip et-qd-chip-bordered\">Clear history</button>\n }\n\n <div class=\"et-qd-queries__divider\"></div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': viewMode() !== 'authProvider' }\"\n (click)=\"selectViewMode('authProvider')\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Auth Provider\n </button>\n </div>\n\n @if (viewMode() === 'query') {\n <div class=\"et-qd-queries__browser\">\n @if (queryListMode() === 'live') {\n <ul class=\"et-qd-queries__browser-list\">\n @for (query of queries(); track trackByQuery($index, query)) {\n <li>\n <button\n [class.et-qd-query--active]=\"selectedQuery()?._id === query._id\"\n (click)=\"selectQuery(query)\"\n >\n <span> {{ query._queryConfig.method }}</span>\n <span> {{ query | queryShortName }}</span>\n </button>\n </li>\n }\n </ul>\n }\n @if (queryListMode() === 'history') {\n <ul class=\"et-qd-queries__browser-list\">\n @for (query of queryHistory$ | async; track trackByQuery($index, query)) {\n <li>\n <button\n [class.et-qd-query--active]=\"selectedQuery()?._id === query._id\"\n (click)=\"selectQuery(query)\"\n >\n <span> {{ query._queryConfig.method }}</span>\n <span> {{ query | queryShortName }}</span>\n </button>\n </li>\n }\n </ul>\n }\n <div class=\"et-qd-queries__browser-detail\">\n @if (selectedQuery(); as query) {\n <p class=\"et-qd-queries__browser-detail__title\">\n {{ query._queryConfig.method }} {{ query._routeWithParams }}\n </p>\n\n <div class=\"et-qd-queries__actions\">\n <button (click)=\"query.execute()\" class=\"et-qd-chip et-qd-chip-bordered\">Execute</button>\n <button (click)=\"query.execute({ skipCache: true })\" class=\"et-qd-chip et-qd-chip-bordered\">\n Execute (ignore cache)\n </button>\n\n <button (click)=\"query.abort()\" class=\"et-qd-chip et-qd-chip-bordered\">Abort</button>\n <div class=\"et-qd-queries__divider\"></div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !query.isPolling }\"\n (click)=\"query.poll({ interval: 5000, takeUntil: _destroy$ })\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Poll\n </button>\n\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': query.isPolling }\"\n (click)=\"query.stopPolling()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Stop polling\n </button>\n @if (query.isPolling || query._isPollingPaused) {\n <button (click)=\"query.pausePolling()\" class=\"et-qd-chip et-qd-chip-secondary et-qd-chip-bordered\">\n Pause polling\n </button>\n <button (click)=\"query.resumePolling()\" class=\"et-qd-chip et-qd-chip-secondary et-qd-chip-bordered\">\n Resume polling\n </button>\n }\n </div>\n\n <div class=\"et-qd-list\">\n <div class=\"et-qd-list-item\">\n <p>State type</p>\n <pre>{{ query.rawState.type }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Dependents</p>\n <pre>{{ query._dependents | json }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Is expired</p>\n <pre>{{ query.isExpired }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Is in use</p>\n <pre>{{ query.isInUse }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Subscriber count</p>\n <pre>{{ query._subscriberCount }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Is polling</p>\n <pre>{{ query.isPolling }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Is polling paused</p>\n <pre>{{ query._isPollingPaused }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Enable smart polling</p>\n <pre>{{ query._enableSmartPolling }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Query store key</p>\n <pre>{{ query._queryStoreKey }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Arguments</p>\n\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showArguments() }\"\n (click)=\"toggleShowArguments()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showArguments()) {\n <pre>{{ query._arguments | json }}</pre>\n }\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>State</p>\n <p><i> Warning, this will cause a subscription if shown!</i></p>\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showResponse() }\"\n (click)=\"toggleShowResponse()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showResponse()) {\n <pre>{{ query.state$ | async | json }}</pre>\n }\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Raw state</p>\n <p><i> The query state unaffected by entity stores</i></p>\n\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showRawResponse() }\"\n (click)=\"toggleShowRawResponse()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showRawResponse()) {\n <pre>{{ query.rawState | json }}</pre>\n }\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Query config</p>\n\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showQueryConfig() }\"\n (click)=\"toggleShowQueryConfig()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showQueryConfig()) {\n <pre>{{ stringifiedQueryConfig() | json }}</pre>\n }\n </div>\n\n @if (!!query._queryConfig.entity) {\n <div class=\"et-qd-list-item\">\n <p>Entity store value</p>\n\n <div>\n <button\n [ngClass]=\"{ 'et-qd-chip-secondary': !showEntityStoreValue() }\"\n (click)=\"toggleShowEntityStoreValue()\"\n class=\"et-qd-chip et-qd-chip-bordered\"\n >\n Toggle\n </button>\n </div>\n @if (showEntityStoreValue()) {\n <pre>{{ selectedQueryEntityStoreValue$ | async | json }}</pre>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n } @else if (viewMode() === 'authProvider') {\n <div class=\"et-qd-auth-provider__viewer\">\n @if (authProviderDetails(); as details) {\n <div class=\"et-qd-list\">\n <div class=\"et-qd-list-item\">\n <p>Type</p>\n <pre>{{ details.type }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>Header value</p>\n <pre>{{ details.header() | json }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>Config</p>\n <pre>{{ details.config | json }}</pre>\n </div>\n\n @if (details.type === 'BearerAuthProvider') {\n <div class=\"et-qd-list-item\">\n <p>Tokens</p>\n <pre>{{ details.provider.tokens$ | async | json }}</pre>\n </div>\n\n <div class=\"et-qd-list-item\">\n <p>Should refresh on unauthorized response</p>\n <pre>{{ details.provider.shouldRefreshOnUnauthorizedResponse }}</pre>\n </div>\n\n <ng-container\n *etQuery=\"\n details.provider.currentRefreshQuery$ | async as response;\n loading as loading;\n error as error;\n query as query\n \"\n >\n <div class=\"et-qd-list-item\">\n <p>Refresh query response</p>\n\n <div>\n <button (click)=\"details.provider._refreshQuery()\" class=\"et-qd-chip et-qd-chip-bordered\">\n Refresh\n </button>\n </div>\n <pre>{{ response | json }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>Refresh query loading</p>\n <pre>{{ loading }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>Refresh query error</p>\n <pre>{{ error ?? 'null' }}</pre>\n </div>\n <div class=\"et-qd-list-item\">\n <p>State</p>\n <pre>{{ query?.state$ | async | json }}</pre>\n </div>\n </ng-container>\n }\n </div>\n } @else {\n <p>No auth provider set</p>\n }\n </div>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{position:fixed;top:0;z-index:1000000;font-size:14px;color:#fff}.et-query-devtools-container{position:fixed;inset:0;background-color:#25292e;z-index:10000;overflow:auto;font-family:monospace;display:grid;grid-template-rows:auto auto auto minmax(0,1fr)}.et-query-devtools-container.et-query-devtools-container--transparent{opacity:.25;pointer-events:none}.et-query-devtools-container.et-query-devtools-container--transparent .et-query-devtools-translucent-btn{pointer-events:all}.et-query-devtools-container.et-query-devtools-container--snap-left{inset-inline-start:0;inset-block-start:0;inset-block-end:0;width:50%;border-right:1px solid rgb(37,41,46)}.et-query-devtools-container.et-query-devtools-container--snap-right{inset-inline-start:unset;inset-inline-end:0;inset-block-start:0;inset-block-end:0;width:50%;border-left:1px solid rgb(37,41,46)}.et-query-devtools-container.et-query-devtools-container--snap-top{inset-inline-start:0;inset-block-start:0;inset-inline-end:0;height:50%;border-bottom:1px solid rgb(37,41,46)}.et-query-devtools-container.et-query-devtools-container--snap-bottom{inset-inline-start:0;inset-block-start:unset;inset-block-end:0;inset-inline-end:0;height:50%;border-top:1px solid rgb(37,41,46)}button.et-query-devtools-open-btn{position:fixed;inset-inline-end:20px;inset-block-end:0;z-index:9999;font-family:monospace;border-radius:3px 3px 0 0;line-height:14px;font-size:12px}.et-qd-header{background-color:#00ffa1;padding:12px;display:grid;grid-template-columns:1fr auto auto;gap:12px;align-items:center}.et-qd-header__title{color:#25292e;margin:0;font-size:22px}.et-qd-header__select{display:grid;background-color:#25292e;border-radius:10px;overflow:hidden}.et-qd-header__select select{width:250px;color:#fff;padding:3px 10px 2px;border:none;background-color:#25292e;font-family:monospace}.et-qd-header__select label{padding:3px 10px;color:#25292e;font-size:12px;font-weight:700;color:#fff;border-bottom:1px solid gray}.et-qd-sub-header{background-color:#00b371;padding:12px;display:flex;gap:12px;flex-wrap:wrap}.et-qd-sub-header__divider{width:1px;background-color:#25292e}.et-qd-btn{background-color:#00ffa1;color:#25292e;border:none;padding:12px;cursor:pointer;font-size:14px;font-weight:700;text-align:center;text-decoration:none;display:inline-block;width:100%;transition:all .3s ease-in-out;font-family:monospace;border-radius:10px}.et-qd-btn:hover{background-color:#00cc81}.et-qd-btn.et-qd-btn-secondary{background-color:#25292e;color:#00ffa1}.et-qd-btn.et-qd-btn-secondary:hover{background-color:#3c424a}.et-qd-chip{background-color:#00ffa1;color:#25292e;border:none;padding:4px 9px;cursor:pointer;font-size:12px;font-weight:700;text-align:center;text-decoration:none;display:inline-block;transition:all .3s ease-in-out;font-family:monospace;border-radius:10px}.et-qd-chip:hover{background-color:#00cc81}.et-qd-chip.et-qd-chip-secondary{background-color:#25292e;color:#00ffa1}.et-qd-chip.et-qd-chip-secondary:hover{background-color:#3c424a}.et-qd-chip.et-qd-chip-bordered{border:1px solid rgb(0,255,161)}.et-qd-translucent-clickable{pointer-events:all}.et-qd-client{border-bottom:1px solid #3c424a;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 #3c424a;margin-bottom:-12px}.et-qd-queries__browser-list{border-right:1px solid #3c424a;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 #3c424a;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 #3c424a;margin-left:-12px;margin-right:-12px;margin-bottom:-12px;padding:12px;overflow-y:auto;overflow-x:hidden}.et-qd-list{display:grid;gap:12px}.et-qd-list-item{display:grid}.et-qd-list-item p{font-weight:700;margin:0;padding-bottom:8px}.et-qd-list-item p+p{margin-top:-8px}.et-qd-list-item div+pre{margin-top:8px}.et-qd-list-item pre{margin:0;padding:4px;background-color:#0e1012;border-radius:4px;max-height:450px;overflow:auto}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: QueryShortNamePipe, name: "queryShortName" }, { kind: "directive", type: QueryDirective, selector: "[etQuery]", inputs: ["etQuery", "etQueryCache"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom }); }
|
|
2651
2653
|
}
|
|
2652
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.
|
|
2654
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.4", ngImport: i0, type: QueryDevtoolsComponent, decorators: [{
|
|
2653
2655
|
type: Component,
|
|
2654
2656
|
args: [{ selector: 'et-query-devtools', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.ShadowDom, host: {
|
|
2655
2657
|
class: 'et-query-devtools',
|
|
@@ -2810,6 +2812,1265 @@ const removeFrom = (store, { where, id }) => {
|
|
|
2810
2812
|
.subscribe();
|
|
2811
2813
|
};
|
|
2812
2814
|
|
|
2815
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
2816
|
+
const queryFeatureUsedMultipleTimes = (type) => {
|
|
2817
|
+
return new RuntimeError(0 /* RuntimeErrorCode.QUERY_FEATURE_USED_MULTIPLE_TIMES */, `The query feature "${type}()" was used multiple times.`);
|
|
2818
|
+
};
|
|
2819
|
+
const withArgsQueryFeatureMissingButRouteIsFunction = () => {
|
|
2820
|
+
return new RuntimeError(100 /* RuntimeErrorCode.WITH_ARGS_QUERY_FEATURE_MISSING_BUT_ROUTE_IS_FUNCTION */, `This queries route is a function, but a "withArgs()" feature is missing.`);
|
|
2821
|
+
};
|
|
2822
|
+
const withPollingUsedOnUnsupportedHttpMethod = (method) => {
|
|
2823
|
+
return new RuntimeError(101 /* RuntimeErrorCode.WITH_POLLING_USED_ON_UNSUPPORTED_HTTP_METHOD */, `This is a "${method}" request, "withPolling()" is only supported for GET, HEAD, OPTIONS requests and GQL queries.`);
|
|
2824
|
+
};
|
|
2825
|
+
const withAutoRefreshUsedOnUnsupportedHttpMethod = (method) => {
|
|
2826
|
+
return new RuntimeError(102 /* RuntimeErrorCode.WITH_AUTO_REFRESH_USED_ON_UNSUPPORTED_HTTP_METHOD */, `This is a "${method}" request, "withAutoRefresh()" is only supported for GET, HEAD, OPTIONS requests and GQL queries.`);
|
|
2827
|
+
};
|
|
2828
|
+
const withAutoRefreshUsedInManualQuery = () => {
|
|
2829
|
+
return new RuntimeError(103 /* RuntimeErrorCode.WITH_AUTO_REFRESH_USED_IN_MANUAL_QUERY */, `"withAutoRefresh()" has been used inside a query that has "onlyManualExecution" set to true.` +
|
|
2830
|
+
` If this is intentional, set "ignoreOnlyManualExecution" to true inside the auto refresh config.`);
|
|
2831
|
+
};
|
|
2832
|
+
const cookieLoginTriedButCookieDisabled = () => {
|
|
2833
|
+
return new RuntimeError(200 /* RuntimeErrorCode.COOKIE_LOGIN_TRIED_BUT_COOKIE_DISABLED */, `Cookie login has been tried, but the cookie is disabled.`);
|
|
2834
|
+
};
|
|
2835
|
+
const enableCookieCalledWithoutCookieConfig = () => {
|
|
2836
|
+
return new RuntimeError(201 /* RuntimeErrorCode.ENABLE_COOKIE_CALLED_WITHOUT_COOKIE_CONFIG */, `enableCookie() has been called but there is no cookie config. Please set it during the auth provider creation.`);
|
|
2837
|
+
};
|
|
2838
|
+
const disableCookieCalledWithoutCookieConfig = () => {
|
|
2839
|
+
return new RuntimeError(202 /* RuntimeErrorCode.DISABLE_COOKIE_CALLED_WITHOUT_COOKIE_CONFIG */, `disableCookie() has been called but there is no cookie config. Please set it during the auth provider creation.`);
|
|
2840
|
+
};
|
|
2841
|
+
const loginCalledWithoutConfig = () => {
|
|
2842
|
+
return new RuntimeError(203 /* RuntimeErrorCode.LOGIN_CALLED_WITHOUT_CONFIG */, `login() has been called without a config. Please set it during the auth provider creation.`);
|
|
2843
|
+
};
|
|
2844
|
+
const loginWithTokenCalledWithoutConfig = () => {
|
|
2845
|
+
return new RuntimeError(204 /* RuntimeErrorCode.LOGIN_WITH_TOKEN_CALLED_WITHOUT_CONFIG */, `loginWithToken() has been called without a config. Please set it during the auth provider creation.`);
|
|
2846
|
+
};
|
|
2847
|
+
const refreshTokenCalledWithoutConfig = () => {
|
|
2848
|
+
return new RuntimeError(205 /* RuntimeErrorCode.REFRESH_TOKEN_CALLED_WITHOUT_CONFIG */, `refreshToken() has been called without a config. Please set it during the auth provider creation.`);
|
|
2849
|
+
};
|
|
2850
|
+
const selectRoleCalledWithoutConfig = () => {
|
|
2851
|
+
return new RuntimeError(206 /* RuntimeErrorCode.SELECT_ROLE_CALLED_WITHOUT_CONFIG */, `selectRole() has been called without a config. Please set it during the auth provider creation.`);
|
|
2852
|
+
};
|
|
2853
|
+
const defaultResponseTransformerResponseNotObject = (currentType) => {
|
|
2854
|
+
return new RuntimeError(207 /* RuntimeErrorCode.DEFAULT_RESPONSE_TRANSFORMER_RESPONSE_NOT_OBJECT */, `The default response transformer expects the response to be an object, but it is a "${currentType}".`);
|
|
2855
|
+
};
|
|
2856
|
+
const defaultResponseTransformerResponseNotContainingAccessToken = () => {
|
|
2857
|
+
return new RuntimeError(208 /* RuntimeErrorCode.DEFAULT_RESPONSE_TRANSFORMER_RESPONSE_NOT_CONTAINING_ACCESS_TOKEN */, `The default response transformer expects the response to contain an "accessToken" property.`);
|
|
2858
|
+
};
|
|
2859
|
+
const defaultResponseTransformerResponseNotContainingRefreshToken = () => {
|
|
2860
|
+
return new RuntimeError(209 /* RuntimeErrorCode.DEFAULT_RESPONSE_TRANSFORMER_RESPONSE_NOT_CONTAINING_REFRESH_TOKEN */, `The default response transformer expects the response to contain a "refreshToken" property.`);
|
|
2861
|
+
};
|
|
2862
|
+
const unableToDecryptBearerToken = (token) => {
|
|
2863
|
+
return new RuntimeError(210 /* RuntimeErrorCode.UNABLE_TO_DECRYPT_BEARER_TOKEN */, `The bearer token could not be decrypted: ${token}`);
|
|
2864
|
+
};
|
|
2865
|
+
const bearerExpiresInPropertyNotNumber = (expiresIn) => {
|
|
2866
|
+
return new RuntimeError(211 /* RuntimeErrorCode.BEARER_EXPIRES_IN_PROPERTY_NOT_NUMBER */, `The expires in property is not a number: ${expiresIn}`);
|
|
2867
|
+
};
|
|
2868
|
+
|
|
2869
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
2870
|
+
const defaultResponseTransformer = (response) => {
|
|
2871
|
+
if (!isObject(response)) {
|
|
2872
|
+
throw defaultResponseTransformerResponseNotObject(typeof response);
|
|
2873
|
+
}
|
|
2874
|
+
if (!('accessToken' in response)) {
|
|
2875
|
+
throw defaultResponseTransformerResponseNotContainingAccessToken();
|
|
2876
|
+
}
|
|
2877
|
+
if (!('refreshToken' in response)) {
|
|
2878
|
+
throw defaultResponseTransformerResponseNotContainingRefreshToken();
|
|
2879
|
+
}
|
|
2880
|
+
return response;
|
|
2881
|
+
};
|
|
2882
|
+
const FIVE_MINUTES = 5 * 60 * 1000;
|
|
2883
|
+
const createAuthProviderQuery = (config, authProviderConfig) => {
|
|
2884
|
+
const query = config.queryCreator();
|
|
2885
|
+
const triggeredInternally = signal(false);
|
|
2886
|
+
const tokens = computed(() => {
|
|
2887
|
+
const res = query.response();
|
|
2888
|
+
if (!res)
|
|
2889
|
+
return null;
|
|
2890
|
+
const transformed = config.responseTransformer?.(res) ?? defaultResponseTransformer(res);
|
|
2891
|
+
const bearerValue = decryptBearer(transformed.accessToken);
|
|
2892
|
+
if (!bearerValue)
|
|
2893
|
+
throw unableToDecryptBearerToken(transformed.accessToken);
|
|
2894
|
+
return {
|
|
2895
|
+
bearer: bearerValue,
|
|
2896
|
+
tokens: transformed,
|
|
2897
|
+
};
|
|
2898
|
+
});
|
|
2899
|
+
const expiresIn = computed(() => {
|
|
2900
|
+
const res = tokens();
|
|
2901
|
+
if (!res)
|
|
2902
|
+
return null;
|
|
2903
|
+
const expiresIn = res.bearer[authProviderConfig.expiresInPropertyName ?? 'exp'];
|
|
2904
|
+
const refreshBuffer = authProviderConfig.refreshBuffer ?? FIVE_MINUTES;
|
|
2905
|
+
if (typeof expiresIn !== 'number') {
|
|
2906
|
+
throw bearerExpiresInPropertyNotNumber(expiresIn);
|
|
2907
|
+
}
|
|
2908
|
+
// const dummyRemainingTime = (query.lastTimeExecutedAt() ?? 0) + 5000 - new Date().getTime();
|
|
2909
|
+
const remainingTime = new Date(expiresIn * 1000).getTime() - refreshBuffer - new Date().getTime();
|
|
2910
|
+
return remainingTime;
|
|
2911
|
+
});
|
|
2912
|
+
const execute = (newArgs, options) => {
|
|
2913
|
+
query.execute(newArgs);
|
|
2914
|
+
triggeredInternally.set(options?.triggeredInternally ?? false);
|
|
2915
|
+
};
|
|
2916
|
+
return {
|
|
2917
|
+
execute,
|
|
2918
|
+
query,
|
|
2919
|
+
tokens,
|
|
2920
|
+
expiresIn,
|
|
2921
|
+
triggeredInternally: triggeredInternally.asReadonly(),
|
|
2922
|
+
};
|
|
2923
|
+
};
|
|
2924
|
+
const createBearerAuthProvider = (options) => {
|
|
2925
|
+
const cookieEnabled = signal(options.cookie === undefined ? false : (options.cookie.enabled ?? true));
|
|
2926
|
+
const cookieOptions = {
|
|
2927
|
+
expiresInDays: 30,
|
|
2928
|
+
name: 'etAuth',
|
|
2929
|
+
path: '/',
|
|
2930
|
+
sameSite: 'lax',
|
|
2931
|
+
domain: getDomain() ?? 'localhost',
|
|
2932
|
+
refreshArgsTransformer: (token) => ({ body: { token } }),
|
|
2933
|
+
...(options.cookie ?? {}),
|
|
2934
|
+
};
|
|
2935
|
+
const loginQuery = options.login ? createAuthProviderQuery(options.login, options) : null;
|
|
2936
|
+
const tokenLoginQuery = options.tokenLogin ? createAuthProviderQuery(options.tokenLogin, options) : null;
|
|
2937
|
+
const tokenRefreshQuery = options.tokenRefresh ? createAuthProviderQuery(options.tokenRefresh, options) : null;
|
|
2938
|
+
const selectRoleQuery = options.selectRole ? createAuthProviderQuery(options.selectRole, options) : null;
|
|
2939
|
+
const queries = [
|
|
2940
|
+
{ type: 'login', query: loginQuery },
|
|
2941
|
+
{ type: 'tokenLogin', query: tokenLoginQuery },
|
|
2942
|
+
{ type: 'tokenRefresh', query: tokenRefreshQuery },
|
|
2943
|
+
{ type: 'selectRole', query: selectRoleQuery },
|
|
2944
|
+
];
|
|
2945
|
+
const latestExecutedQuery = computed(() => {
|
|
2946
|
+
const relevantQueries = queries.filter((q) => q.query && q.query.query.lastTimeExecutedAt() !== null);
|
|
2947
|
+
return findMostRecentQuery(relevantQueries);
|
|
2948
|
+
});
|
|
2949
|
+
const tokens = computed(() => {
|
|
2950
|
+
const query = latestExecutedQuery();
|
|
2951
|
+
return query?.query?.tokens()?.tokens ?? null;
|
|
2952
|
+
});
|
|
2953
|
+
toObservable(computed(() => {
|
|
2954
|
+
const query = latestExecutedQuery();
|
|
2955
|
+
const expiresIn = query?.query?.expiresIn() ?? null;
|
|
2956
|
+
const tokens = query?.query?.tokens() ?? null;
|
|
2957
|
+
return { expiresIn, tokens, query };
|
|
2958
|
+
}))
|
|
2959
|
+
.pipe(switchMap((res) => {
|
|
2960
|
+
if (!res.tokens || res.expiresIn === null || !options.tokenRefresh)
|
|
2961
|
+
return of(null);
|
|
2962
|
+
const expIn = res.expiresIn;
|
|
2963
|
+
const tokens = res.tokens;
|
|
2964
|
+
if (!expIn || !tokens)
|
|
2965
|
+
return of(null);
|
|
2966
|
+
return timer(expIn).pipe(tap(() => refreshToken({
|
|
2967
|
+
...cookieOptions.refreshArgsTransformer(tokens.tokens.refreshToken),
|
|
2968
|
+
}, { triggeredInternally: true })));
|
|
2969
|
+
}), takeUntilDestroyed())
|
|
2970
|
+
.subscribe();
|
|
2971
|
+
const latestNonInternalQuery = signal(null);
|
|
2972
|
+
effect(() => {
|
|
2973
|
+
const relevantQueries = queries.filter((q) => q.query && !q.query.triggeredInternally() && q.query.query.lastTimeExecutedAt() !== null);
|
|
2974
|
+
const lastQuery = findMostRecentQuery(relevantQueries);
|
|
2975
|
+
untracked(() => {
|
|
2976
|
+
if (!lastQuery || !lastQuery.query?.query)
|
|
2977
|
+
return;
|
|
2978
|
+
latestNonInternalQuery.set({
|
|
2979
|
+
type: lastQuery.type,
|
|
2980
|
+
...lastQuery.query.query.createSnapshot(),
|
|
2981
|
+
});
|
|
2982
|
+
});
|
|
2983
|
+
});
|
|
2984
|
+
// Cookie writing
|
|
2985
|
+
effect(() => {
|
|
2986
|
+
const isCookieEnabled = cookieEnabled();
|
|
2987
|
+
const res = latestExecutedQuery();
|
|
2988
|
+
const error = res?.query?.query.error();
|
|
2989
|
+
if (!isCookieEnabled || (error && error.status === 401)) {
|
|
2990
|
+
deleteCookie$1();
|
|
2991
|
+
return;
|
|
2992
|
+
}
|
|
2993
|
+
if (!res?.query)
|
|
2994
|
+
return;
|
|
2995
|
+
const { tokens } = res.query;
|
|
2996
|
+
const rt = tokens()?.tokens.refreshToken;
|
|
2997
|
+
if (!rt)
|
|
2998
|
+
return;
|
|
2999
|
+
writeCookie(rt);
|
|
3000
|
+
});
|
|
3001
|
+
const login = (args) => {
|
|
3002
|
+
if (!loginQuery) {
|
|
3003
|
+
throw loginCalledWithoutConfig();
|
|
3004
|
+
}
|
|
3005
|
+
loginQuery.execute(args);
|
|
3006
|
+
return loginQuery.query.createSnapshot();
|
|
3007
|
+
};
|
|
3008
|
+
const loginWithToken = (args) => {
|
|
3009
|
+
if (!tokenLoginQuery) {
|
|
3010
|
+
throw loginWithTokenCalledWithoutConfig();
|
|
3011
|
+
}
|
|
3012
|
+
tokenLoginQuery.execute(args);
|
|
3013
|
+
return tokenLoginQuery.query.createSnapshot();
|
|
3014
|
+
};
|
|
3015
|
+
const refreshToken = (args, options) => {
|
|
3016
|
+
if (!tokenRefreshQuery) {
|
|
3017
|
+
throw refreshTokenCalledWithoutConfig();
|
|
3018
|
+
}
|
|
3019
|
+
tokenRefreshQuery.execute(args, { triggeredInternally: options?.triggeredInternally });
|
|
3020
|
+
return tokenRefreshQuery.query.createSnapshot();
|
|
3021
|
+
};
|
|
3022
|
+
const selectRole = (args) => {
|
|
3023
|
+
if (!selectRoleQuery) {
|
|
3024
|
+
throw selectRoleCalledWithoutConfig();
|
|
3025
|
+
}
|
|
3026
|
+
selectRoleQuery.execute(args);
|
|
3027
|
+
return selectRoleQuery.query.createSnapshot();
|
|
3028
|
+
};
|
|
3029
|
+
const logout = () => {
|
|
3030
|
+
deleteCookie$1();
|
|
3031
|
+
loginQuery?.query.execute.reset();
|
|
3032
|
+
tokenLoginQuery?.query.execute.reset();
|
|
3033
|
+
tokenRefreshQuery?.query.execute.reset();
|
|
3034
|
+
selectRoleQuery?.query.execute.reset();
|
|
3035
|
+
latestNonInternalQuery.set(null);
|
|
3036
|
+
};
|
|
3037
|
+
const enableCookie = () => {
|
|
3038
|
+
if (isDevMode() && !options.cookie) {
|
|
3039
|
+
throw enableCookieCalledWithoutCookieConfig();
|
|
3040
|
+
}
|
|
3041
|
+
cookieEnabled.set(true);
|
|
3042
|
+
};
|
|
3043
|
+
const disableCookie = () => {
|
|
3044
|
+
if (isDevMode() && !options.cookie) {
|
|
3045
|
+
throw disableCookieCalledWithoutCookieConfig();
|
|
3046
|
+
}
|
|
3047
|
+
cookieEnabled.set(false);
|
|
3048
|
+
deleteCookie$1();
|
|
3049
|
+
};
|
|
3050
|
+
const tryLoginWithCookie = () => {
|
|
3051
|
+
const isCookieEnabled = cookieEnabled();
|
|
3052
|
+
if (!isCookieEnabled) {
|
|
3053
|
+
if (isDevMode()) {
|
|
3054
|
+
throw cookieLoginTriedButCookieDisabled();
|
|
3055
|
+
}
|
|
3056
|
+
return false;
|
|
3057
|
+
}
|
|
3058
|
+
const cookie = getCookie(cookieOptions.name);
|
|
3059
|
+
if (!cookie) {
|
|
3060
|
+
return false;
|
|
3061
|
+
}
|
|
3062
|
+
refreshToken(cookieOptions.refreshArgsTransformer(cookie));
|
|
3063
|
+
return true;
|
|
3064
|
+
};
|
|
3065
|
+
const writeCookie = (refreshToken) => {
|
|
3066
|
+
const { name, expiresInDays, domain, path, sameSite } = cookieOptions;
|
|
3067
|
+
setCookie(name, refreshToken, expiresInDays, domain, path, sameSite);
|
|
3068
|
+
};
|
|
3069
|
+
const deleteCookie$1 = () => {
|
|
3070
|
+
const { name, path, domain } = cookieOptions;
|
|
3071
|
+
deleteCookie(name, path, domain);
|
|
3072
|
+
};
|
|
3073
|
+
const findMostRecentQuery = (queriesToSearch) => {
|
|
3074
|
+
return queriesToSearch.reduce((acc, curr) => {
|
|
3075
|
+
if (!acc)
|
|
3076
|
+
return curr;
|
|
3077
|
+
const accExp = acc.query?.query.lastTimeExecutedAt() ?? null;
|
|
3078
|
+
const currExp = curr.query?.query.lastTimeExecutedAt() ?? null;
|
|
3079
|
+
if (currExp === null || accExp === null)
|
|
3080
|
+
return acc;
|
|
3081
|
+
return accExp > currExp ? acc : curr;
|
|
3082
|
+
}, null);
|
|
3083
|
+
};
|
|
3084
|
+
const bearerAuthProvider = {
|
|
3085
|
+
login,
|
|
3086
|
+
loginWithToken,
|
|
3087
|
+
refreshToken,
|
|
3088
|
+
selectRole,
|
|
3089
|
+
logout,
|
|
3090
|
+
enableCookie,
|
|
3091
|
+
disableCookie,
|
|
3092
|
+
tryLoginWithCookie,
|
|
3093
|
+
latestExecutedQuery: latestNonInternalQuery.asReadonly(),
|
|
3094
|
+
tokens,
|
|
3095
|
+
};
|
|
3096
|
+
if (cookieEnabled()) {
|
|
3097
|
+
tryLoginWithCookie();
|
|
3098
|
+
}
|
|
3099
|
+
return bearerAuthProvider;
|
|
3100
|
+
};
|
|
3101
|
+
const provideBearerAuthProvider = (config) => {
|
|
3102
|
+
return {
|
|
3103
|
+
provide: config.token,
|
|
3104
|
+
useFactory: () => createBearerAuthProvider(config),
|
|
3105
|
+
};
|
|
3106
|
+
};
|
|
3107
|
+
|
|
3108
|
+
const createBearerAuthProviderConfig = (options) => {
|
|
3109
|
+
const token = new InjectionToken(`BearerAuthProvider_${options.name}`);
|
|
3110
|
+
const bearerAuthProviderConfig = {
|
|
3111
|
+
name: options.name,
|
|
3112
|
+
queryClientRef: options.queryClientRef,
|
|
3113
|
+
token,
|
|
3114
|
+
cookie: options.cookie,
|
|
3115
|
+
expiresInPropertyName: options.expiresInPropertyName ?? 'exp',
|
|
3116
|
+
refreshBuffer: options.refreshBuffer ?? 300000,
|
|
3117
|
+
refreshOnUnauthorizedResponse: options.refreshOnUnauthorizedResponse ?? true,
|
|
3118
|
+
login: options.login,
|
|
3119
|
+
selectRole: options.selectRole,
|
|
3120
|
+
tokenLogin: options.tokenLogin,
|
|
3121
|
+
tokenRefresh: options.tokenRefresh,
|
|
3122
|
+
};
|
|
3123
|
+
return bearerAuthProviderConfig;
|
|
3124
|
+
};
|
|
3125
|
+
|
|
3126
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
3127
|
+
/**
|
|
3128
|
+
* Returning this inside e.g. a withComputedArgs feature will reset the query args to null.
|
|
3129
|
+
* This will also pause polling and auto refresh until new args are set.
|
|
3130
|
+
*/
|
|
3131
|
+
const QUERY_ARGS_RESET = Symbol('QUERY_ARGS_RESET');
|
|
3132
|
+
const QUERY_EFFECT_ERROR_MESSAGE = 'Effect triggered too often. This is probably due to a circular dependency inside the query.';
|
|
3133
|
+
/** A angular effect that will throw an error in dev mode if it is called too often. This indicates a circular dependency inside the effect. */
|
|
3134
|
+
const queryEffect = (fn, errorMessage, options) => {
|
|
3135
|
+
let lastTriggerTs = 0;
|
|
3136
|
+
let illegalWrites = 0;
|
|
3137
|
+
effect(() => {
|
|
3138
|
+
if (isDevMode()) {
|
|
3139
|
+
const now = performance.now();
|
|
3140
|
+
if (now - lastTriggerTs < 100) {
|
|
3141
|
+
illegalWrites++;
|
|
3142
|
+
if (illegalWrites > 5) {
|
|
3143
|
+
throw new Error(errorMessage);
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
lastTriggerTs = now;
|
|
3147
|
+
}
|
|
3148
|
+
fn();
|
|
3149
|
+
}, options);
|
|
3150
|
+
};
|
|
3151
|
+
const shouldAutoExecuteQuery = (method) => {
|
|
3152
|
+
return method === 'GET' || method === 'HEAD' || method === 'OPTIONS';
|
|
3153
|
+
};
|
|
3154
|
+
const extractExpiresInSeconds = (headers) => {
|
|
3155
|
+
const cacheControl = headers.get('cache-control');
|
|
3156
|
+
const age = headers.get('age');
|
|
3157
|
+
const expires = headers.get('expires');
|
|
3158
|
+
// In seconds
|
|
3159
|
+
let expiresIn = null;
|
|
3160
|
+
let maxAge = null;
|
|
3161
|
+
if (cacheControl?.includes('no-cache')) {
|
|
3162
|
+
return null;
|
|
3163
|
+
}
|
|
3164
|
+
if (cacheControl?.includes('max-age')) {
|
|
3165
|
+
const m = cacheControl.split('max-age=')[1];
|
|
3166
|
+
if (m) {
|
|
3167
|
+
maxAge = parseInt(m);
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
else if (cacheControl?.includes('s-maxage')) {
|
|
3171
|
+
const m = cacheControl.split('s-maxage=')[1];
|
|
3172
|
+
if (m) {
|
|
3173
|
+
maxAge = parseInt(m);
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
if (maxAge && age) {
|
|
3177
|
+
const ageSeconds = parseInt(age);
|
|
3178
|
+
expiresIn = maxAge - ageSeconds;
|
|
3179
|
+
}
|
|
3180
|
+
else if (maxAge) {
|
|
3181
|
+
expiresIn = maxAge / 2; // We assume the response is half way to its expiration
|
|
3182
|
+
}
|
|
3183
|
+
else if (expires) {
|
|
3184
|
+
// Used by some apis to tell the response will never expire
|
|
3185
|
+
// In this case we let the response expire after 1 hour
|
|
3186
|
+
if (expires === '-1') {
|
|
3187
|
+
expiresIn = 3600;
|
|
3188
|
+
}
|
|
3189
|
+
else {
|
|
3190
|
+
const expiresDate = new Date(expires);
|
|
3191
|
+
// check if the date is valid
|
|
3192
|
+
if (expiresDate.toString() !== 'Invalid Date') {
|
|
3193
|
+
expiresIn = Math.floor((expiresDate.getTime() - Date.now()) / 1000);
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
return expiresIn;
|
|
3198
|
+
};
|
|
3199
|
+
const shouldRetryRequest = (options) => {
|
|
3200
|
+
const { retryCount, error } = options;
|
|
3201
|
+
const defaultRetryDelay = 1000 + 1000 * retryCount;
|
|
3202
|
+
if (retryCount > 3) {
|
|
3203
|
+
return { retry: false };
|
|
3204
|
+
}
|
|
3205
|
+
if (!(error instanceof HttpErrorResponse)) {
|
|
3206
|
+
return { retry: false };
|
|
3207
|
+
}
|
|
3208
|
+
const { status, error: detail, headers } = error;
|
|
3209
|
+
// Retry on 5xx errors
|
|
3210
|
+
if (status >= 500) {
|
|
3211
|
+
// Don't retry if a requested page is out of range
|
|
3212
|
+
if (isSymfonyPagerfantaOutOfRangeError(detail)) {
|
|
3213
|
+
return { retry: false };
|
|
3214
|
+
}
|
|
3215
|
+
return { retry: true, delay: defaultRetryDelay };
|
|
3216
|
+
}
|
|
3217
|
+
// Retry on 408 or 425 errors
|
|
3218
|
+
if (status === HttpStatusCode.RequestTimeout || status === HttpStatusCode.TooEarly) {
|
|
3219
|
+
return { retry: true, delay: defaultRetryDelay };
|
|
3220
|
+
}
|
|
3221
|
+
// Retry on 429 errors
|
|
3222
|
+
if (status === HttpStatusCode.TooManyRequests) {
|
|
3223
|
+
const retryAfter = headers.get('retry-after') || headers.get('x-retry-after');
|
|
3224
|
+
if (retryAfter) {
|
|
3225
|
+
const delay = parseInt(retryAfter) * 1000;
|
|
3226
|
+
return { retry: true, delay: Number.isNaN(delay) ? defaultRetryDelay : delay };
|
|
3227
|
+
}
|
|
3228
|
+
return { retry: true, delay: defaultRetryDelay };
|
|
3229
|
+
}
|
|
3230
|
+
// Code 0 usually means the internet connection is down. We retry in this case.
|
|
3231
|
+
// It could also be a CORS issue but that should not be the case in production.
|
|
3232
|
+
if (status === 0) {
|
|
3233
|
+
return { retry: true, delay: defaultRetryDelay };
|
|
3234
|
+
}
|
|
3235
|
+
return { retry: false };
|
|
3236
|
+
};
|
|
3237
|
+
const getQueryFeatureUsage = (options) => {
|
|
3238
|
+
const { creator, creatorInternals, features, queryConfig } = options;
|
|
3239
|
+
const hasWithArgsFeature = features.some((f) => f.type == "withArgs" /* QueryFeatureType.WithArgs */);
|
|
3240
|
+
const shouldAutoExecuteMethod = shouldAutoExecuteQuery(creatorInternals.method);
|
|
3241
|
+
const shouldAutoExecute = shouldAutoExecuteMethod && !queryConfig.onlyManualExecution;
|
|
3242
|
+
const hasRouteFunction = typeof creator.route === 'function';
|
|
3243
|
+
if (hasRouteFunction && !hasWithArgsFeature) {
|
|
3244
|
+
throw withArgsQueryFeatureMissingButRouteIsFunction();
|
|
3245
|
+
}
|
|
3246
|
+
const featureFnContext = {
|
|
3247
|
+
hasWithArgsFeature,
|
|
3248
|
+
shouldAutoExecuteMethod,
|
|
3249
|
+
shouldAutoExecute,
|
|
3250
|
+
hasRouteFunction,
|
|
3251
|
+
};
|
|
3252
|
+
return featureFnContext;
|
|
3253
|
+
};
|
|
3254
|
+
const applyQueryFeatures = (options, context) => {
|
|
3255
|
+
const featureTypes = new Set();
|
|
3256
|
+
for (const feature of options.features) {
|
|
3257
|
+
if (featureTypes.has(feature.type)) {
|
|
3258
|
+
throw queryFeatureUsedMultipleTimes(feature.type);
|
|
3259
|
+
}
|
|
3260
|
+
featureTypes.add(feature.type);
|
|
3261
|
+
feature.fn(context);
|
|
3262
|
+
}
|
|
3263
|
+
};
|
|
3264
|
+
const maybeExecute = (options) => {
|
|
3265
|
+
if (options.flags.shouldAutoExecute && !options.flags.hasRouteFunction && !options.flags.hasWithArgsFeature) {
|
|
3266
|
+
options.execute();
|
|
3267
|
+
}
|
|
3268
|
+
};
|
|
3269
|
+
|
|
3270
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
3271
|
+
const SPEED_BUFFER_TIME_IN_MS = 2000;
|
|
3272
|
+
const createHttpRequest = (options) => {
|
|
3273
|
+
let currentStreamSubscription = Subscription.EMPTY;
|
|
3274
|
+
const currentEvent = signal(null);
|
|
3275
|
+
const loading = signal(null);
|
|
3276
|
+
const error = signal(null);
|
|
3277
|
+
const response = signal(null);
|
|
3278
|
+
const lastLoadEventTime = signal(0);
|
|
3279
|
+
const lastLoadEventAmount = signal(0);
|
|
3280
|
+
const lastExecuteTime = signal(0);
|
|
3281
|
+
const expiresIn = signal(null);
|
|
3282
|
+
const isStale = computed(() => {
|
|
3283
|
+
const expiresInTs = expiresIn();
|
|
3284
|
+
return expiresInTs === null || expiresInTs < Date.now();
|
|
3285
|
+
});
|
|
3286
|
+
const stream = options.httpClient
|
|
3287
|
+
.request(options.method, options.fullPath, {
|
|
3288
|
+
observe: 'events',
|
|
3289
|
+
body: options.body,
|
|
3290
|
+
reportProgress: options.reportProgress,
|
|
3291
|
+
withCredentials: options.withCredentials,
|
|
3292
|
+
transferCache: options.transferCache,
|
|
3293
|
+
responseType: options.responseType || 'json',
|
|
3294
|
+
context: options.context,
|
|
3295
|
+
headers: options.headers,
|
|
3296
|
+
})
|
|
3297
|
+
.pipe(tap((event) => updateState(event)), retry({
|
|
3298
|
+
delay: (error, retryCount) => {
|
|
3299
|
+
const retryOptions = { error, retryCount };
|
|
3300
|
+
const retryResult = options.retryFn?.(retryOptions) || shouldRetryRequest(retryOptions);
|
|
3301
|
+
if (!retryResult.retry) {
|
|
3302
|
+
return throwError(() => error);
|
|
3303
|
+
}
|
|
3304
|
+
return timer(retryResult.delay);
|
|
3305
|
+
},
|
|
3306
|
+
}), catchError((e) => {
|
|
3307
|
+
updateErrorState(e);
|
|
3308
|
+
return throwError(() => e);
|
|
3309
|
+
}));
|
|
3310
|
+
const execute = () => {
|
|
3311
|
+
if (loading() || !isStale()) {
|
|
3312
|
+
// Do not execute if there is already a request in progress or the request is not stale
|
|
3313
|
+
return false;
|
|
3314
|
+
}
|
|
3315
|
+
currentStreamSubscription.unsubscribe();
|
|
3316
|
+
lastExecuteTime.set(Date.now());
|
|
3317
|
+
lastLoadEventTime.set(lastExecuteTime());
|
|
3318
|
+
loading.set({
|
|
3319
|
+
executeTime: lastExecuteTime(),
|
|
3320
|
+
progress: null,
|
|
3321
|
+
});
|
|
3322
|
+
error.set(null);
|
|
3323
|
+
expiresIn.set(null);
|
|
3324
|
+
currentStreamSubscription = stream.subscribe();
|
|
3325
|
+
return true;
|
|
3326
|
+
};
|
|
3327
|
+
const destroy = () => {
|
|
3328
|
+
if (currentStreamSubscription.closed) {
|
|
3329
|
+
return false;
|
|
3330
|
+
}
|
|
3331
|
+
currentStreamSubscription.unsubscribe();
|
|
3332
|
+
return true;
|
|
3333
|
+
};
|
|
3334
|
+
const updateState = (event) => {
|
|
3335
|
+
currentEvent.set(event);
|
|
3336
|
+
switch (event.type) {
|
|
3337
|
+
case HttpEventType.Response:
|
|
3338
|
+
{
|
|
3339
|
+
loading.set(null);
|
|
3340
|
+
response.set(event.body);
|
|
3341
|
+
const expiresInSeconds = options.cacheAdapter
|
|
3342
|
+
? options.cacheAdapter(event.headers)
|
|
3343
|
+
: extractExpiresInSeconds(event.headers);
|
|
3344
|
+
const expiresInTimestamp = buildTimestampFromSeconds(expiresInSeconds);
|
|
3345
|
+
expiresIn.set(expiresInTimestamp);
|
|
3346
|
+
}
|
|
3347
|
+
break;
|
|
3348
|
+
case HttpEventType.UploadProgress:
|
|
3349
|
+
case HttpEventType.DownloadProgress:
|
|
3350
|
+
{
|
|
3351
|
+
updateLoadingState(event);
|
|
3352
|
+
}
|
|
3353
|
+
break;
|
|
3354
|
+
case HttpEventType.Sent:
|
|
3355
|
+
case HttpEventType.ResponseHeader:
|
|
3356
|
+
case HttpEventType.User:
|
|
3357
|
+
{
|
|
3358
|
+
// we don't care about these events
|
|
3359
|
+
}
|
|
3360
|
+
break;
|
|
3361
|
+
}
|
|
3362
|
+
};
|
|
3363
|
+
const updateErrorState = (errorResponse) => {
|
|
3364
|
+
let err = errorResponse instanceof HttpErrorResponse ? errorResponse : null;
|
|
3365
|
+
if (!err) {
|
|
3366
|
+
err = new HttpErrorResponse({
|
|
3367
|
+
error: errorResponse,
|
|
3368
|
+
status: 0,
|
|
3369
|
+
statusText: 'Unknown Error',
|
|
3370
|
+
});
|
|
3371
|
+
}
|
|
3372
|
+
error.set(err);
|
|
3373
|
+
loading.set(null);
|
|
3374
|
+
currentEvent.set({ type: 'error', error: err });
|
|
3375
|
+
};
|
|
3376
|
+
const updateLoadingState = (event) => {
|
|
3377
|
+
if (event.total === undefined) {
|
|
3378
|
+
return;
|
|
3379
|
+
}
|
|
3380
|
+
const progress = {
|
|
3381
|
+
total: event.total,
|
|
3382
|
+
loaded: event.loaded,
|
|
3383
|
+
percentage: (event.loaded / event.total) * 100,
|
|
3384
|
+
speed: null,
|
|
3385
|
+
remainingTime: null,
|
|
3386
|
+
};
|
|
3387
|
+
const state = {
|
|
3388
|
+
executeTime: lastExecuteTime(),
|
|
3389
|
+
progress,
|
|
3390
|
+
};
|
|
3391
|
+
const currentTime = Date.now();
|
|
3392
|
+
const elapsedTimeSinceLastEvent = currentTime - lastLoadEventTime();
|
|
3393
|
+
const elapsedTimeSinceLastExecute = currentTime - lastExecuteTime();
|
|
3394
|
+
const loadedAmount = event.loaded - lastLoadEventAmount();
|
|
3395
|
+
// We only want to calculate speed and remaining time after 2 seconds of the execution
|
|
3396
|
+
// This is to avoid showing incorrect speed and remaining time when the request is very fast
|
|
3397
|
+
if (elapsedTimeSinceLastExecute > SPEED_BUFFER_TIME_IN_MS) {
|
|
3398
|
+
const speed = (loadedAmount / elapsedTimeSinceLastEvent) * 1000;
|
|
3399
|
+
progress.speed = speed * 1000;
|
|
3400
|
+
progress.remainingTime = Math.round((event.total - event.loaded) / speed) * 1000;
|
|
3401
|
+
}
|
|
3402
|
+
lastLoadEventTime.set(currentTime);
|
|
3403
|
+
lastLoadEventAmount.set(event.loaded);
|
|
3404
|
+
loading.set(state);
|
|
3405
|
+
};
|
|
3406
|
+
const httpRequest = {
|
|
3407
|
+
execute,
|
|
3408
|
+
destroy,
|
|
3409
|
+
loading: loading.asReadonly(),
|
|
3410
|
+
error: error.asReadonly(),
|
|
3411
|
+
response: response.asReadonly(),
|
|
3412
|
+
currentEvent: currentEvent.asReadonly(),
|
|
3413
|
+
isStale,
|
|
3414
|
+
};
|
|
3415
|
+
return httpRequest;
|
|
3416
|
+
};
|
|
3417
|
+
|
|
3418
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
3419
|
+
const setupQueryDependencies = (options) => {
|
|
3420
|
+
const destroyRef = inject(DestroyRef);
|
|
3421
|
+
const client = inject(options.clientConfig.token);
|
|
3422
|
+
const injector = inject(Injector);
|
|
3423
|
+
const dependencies = {
|
|
3424
|
+
destroyRef,
|
|
3425
|
+
client,
|
|
3426
|
+
injector,
|
|
3427
|
+
};
|
|
3428
|
+
return dependencies;
|
|
3429
|
+
};
|
|
3430
|
+
|
|
3431
|
+
const resetExecuteState = (options) => {
|
|
3432
|
+
const { executeState, executeOptions: opts } = options;
|
|
3433
|
+
const { deps, state } = opts;
|
|
3434
|
+
const { effectRefs, previousKey } = executeState;
|
|
3435
|
+
deps.client.repository.unbind(previousKey, deps.destroyRef);
|
|
3436
|
+
effectRefs.forEach((ref) => ref.destroy());
|
|
3437
|
+
effectRefs.length = 0;
|
|
3438
|
+
state.args.set(null);
|
|
3439
|
+
state.error.set(null);
|
|
3440
|
+
state.latestHttpEvent.set(null);
|
|
3441
|
+
state.loading.set(null);
|
|
3442
|
+
state.response.set(null);
|
|
3443
|
+
state.lastTimeExecutedAt.set(null);
|
|
3444
|
+
};
|
|
3445
|
+
const setupQueryExecuteState = () => {
|
|
3446
|
+
return {
|
|
3447
|
+
effectRefs: [],
|
|
3448
|
+
previousKey: false,
|
|
3449
|
+
};
|
|
3450
|
+
};
|
|
3451
|
+
const queryExecute = (options) => {
|
|
3452
|
+
const { executeOptions, args, executeState } = options;
|
|
3453
|
+
const { deps, state, creator, creatorInternals, queryConfig } = executeOptions;
|
|
3454
|
+
const { key, request } = deps.client.repository.request({
|
|
3455
|
+
method: creatorInternals.method,
|
|
3456
|
+
route: creator.route,
|
|
3457
|
+
reportProgress: creator.reportProgress,
|
|
3458
|
+
withCredentials: creator.withCredentials,
|
|
3459
|
+
transferCache: creator.transferCache,
|
|
3460
|
+
responseType: creator.responseType || 'json',
|
|
3461
|
+
pathParams: args?.pathParams,
|
|
3462
|
+
queryParams: args?.queryParams,
|
|
3463
|
+
body: args?.body,
|
|
3464
|
+
destroyRef: deps.destroyRef,
|
|
3465
|
+
key: queryConfig.key,
|
|
3466
|
+
headers: args?.headers,
|
|
3467
|
+
});
|
|
3468
|
+
executeState.previousKey = key;
|
|
3469
|
+
runInInjectionContext(deps.injector, () => {
|
|
3470
|
+
const responseRef = syncSignal(request.response, state.response);
|
|
3471
|
+
const loadingRef = syncSignal(request.loading, state.loading);
|
|
3472
|
+
const errorRef = syncSignal(request.error, state.error);
|
|
3473
|
+
const latestHttpEventRef = syncSignal(request.currentEvent, state.latestHttpEvent);
|
|
3474
|
+
executeState.effectRefs.push(responseRef, loadingRef, errorRef, latestHttpEventRef);
|
|
3475
|
+
});
|
|
3476
|
+
state.lastTimeExecutedAt.set(Date.now());
|
|
3477
|
+
};
|
|
3478
|
+
const cleanupPreviousExecute = (options) => {
|
|
3479
|
+
const { executeOptions, executeState } = options;
|
|
3480
|
+
const { deps } = executeOptions;
|
|
3481
|
+
deps.client.repository.unbind(executeState.previousKey, deps.destroyRef);
|
|
3482
|
+
executeState.effectRefs.forEach((ref) => ref.destroy());
|
|
3483
|
+
executeState.effectRefs.length = 0;
|
|
3484
|
+
};
|
|
3485
|
+
|
|
3486
|
+
const createExecuteFn = (options) => {
|
|
3487
|
+
const executeState = setupQueryExecuteState();
|
|
3488
|
+
const reset = () => resetExecuteState({ executeState, executeOptions: options });
|
|
3489
|
+
const exec = (args = options.state.args()) => {
|
|
3490
|
+
cleanupPreviousExecute({ executeOptions: options, executeState, args });
|
|
3491
|
+
queryExecute({ executeOptions: options, executeState, args });
|
|
3492
|
+
};
|
|
3493
|
+
exec['reset'] = reset;
|
|
3494
|
+
return exec;
|
|
3495
|
+
};
|
|
3496
|
+
|
|
3497
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
3498
|
+
const setupQueryState = (options) => {
|
|
3499
|
+
const response = signal(null);
|
|
3500
|
+
const args = signal(null);
|
|
3501
|
+
const latestHttpEvent = signal(null);
|
|
3502
|
+
const error = signal(null);
|
|
3503
|
+
const loading = signal(null);
|
|
3504
|
+
const lastTimeExecutedAt = signal(null);
|
|
3505
|
+
const state = {
|
|
3506
|
+
response,
|
|
3507
|
+
args,
|
|
3508
|
+
latestHttpEvent,
|
|
3509
|
+
loading,
|
|
3510
|
+
error,
|
|
3511
|
+
lastTimeExecutedAt,
|
|
3512
|
+
};
|
|
3513
|
+
return state;
|
|
3514
|
+
};
|
|
3515
|
+
|
|
3516
|
+
const createQuerySnapshotFn = (options) => {
|
|
3517
|
+
const { state, deps } = options;
|
|
3518
|
+
const snapshotFn = () => {
|
|
3519
|
+
const snapshotState = setupQueryState({});
|
|
3520
|
+
const isAlive = signal(true);
|
|
3521
|
+
const killEffectRef = effect(() => {
|
|
3522
|
+
const currentLoading = state.loading();
|
|
3523
|
+
const currentError = state.error();
|
|
3524
|
+
const currentResponse = state.response();
|
|
3525
|
+
const currentArgs = state.args();
|
|
3526
|
+
const currentLatestHttpEvent = state.latestHttpEvent();
|
|
3527
|
+
const currentLastTimeExecutedAt = state.lastTimeExecutedAt();
|
|
3528
|
+
untracked(() => {
|
|
3529
|
+
snapshotState.args.set(currentArgs);
|
|
3530
|
+
snapshotState.error.set(currentError);
|
|
3531
|
+
snapshotState.lastTimeExecutedAt.set(currentLastTimeExecutedAt);
|
|
3532
|
+
snapshotState.latestHttpEvent.set(currentLatestHttpEvent);
|
|
3533
|
+
snapshotState.loading.set(currentLoading);
|
|
3534
|
+
snapshotState.response.set(currentResponse);
|
|
3535
|
+
if (currentLoading)
|
|
3536
|
+
return;
|
|
3537
|
+
if (!currentResponse && !currentError)
|
|
3538
|
+
return;
|
|
3539
|
+
// kill the effect once loading is done and we either have a response or an error
|
|
3540
|
+
killEffectRef.destroy();
|
|
3541
|
+
isAlive.set(false);
|
|
3542
|
+
});
|
|
3543
|
+
}, { injector: deps.injector });
|
|
3544
|
+
const snapshot = {
|
|
3545
|
+
args: snapshotState.args.asReadonly(),
|
|
3546
|
+
response: snapshotState.response.asReadonly(),
|
|
3547
|
+
latestHttpEvent: snapshotState.latestHttpEvent.asReadonly(),
|
|
3548
|
+
loading: snapshotState.loading.asReadonly(),
|
|
3549
|
+
error: snapshotState.error.asReadonly(),
|
|
3550
|
+
lastTimeExecutedAt: snapshotState.lastTimeExecutedAt.asReadonly(),
|
|
3551
|
+
isAlive: isAlive.asReadonly(),
|
|
3552
|
+
};
|
|
3553
|
+
return snapshot;
|
|
3554
|
+
};
|
|
3555
|
+
return snapshotFn;
|
|
3556
|
+
};
|
|
3557
|
+
|
|
3558
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3559
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
3560
|
+
const createQuery = (options) => {
|
|
3561
|
+
const deps = setupQueryDependencies({ clientConfig: options.creatorInternals.client });
|
|
3562
|
+
const state = setupQueryState({});
|
|
3563
|
+
const { creator, creatorInternals, queryConfig } = options;
|
|
3564
|
+
const flags = getQueryFeatureUsage(options);
|
|
3565
|
+
const execute = createExecuteFn({ deps, state, creator, creatorInternals, queryConfig: options.queryConfig });
|
|
3566
|
+
const createSnapshot = createQuerySnapshotFn({ state, deps });
|
|
3567
|
+
const featureFnContext = {
|
|
3568
|
+
state,
|
|
3569
|
+
queryConfig,
|
|
3570
|
+
creatorConfig: creator,
|
|
3571
|
+
creatorInternals,
|
|
3572
|
+
execute,
|
|
3573
|
+
flags,
|
|
3574
|
+
};
|
|
3575
|
+
applyQueryFeatures(options, featureFnContext);
|
|
3576
|
+
maybeExecute({ execute, flags });
|
|
3577
|
+
const query = {
|
|
3578
|
+
execute,
|
|
3579
|
+
args: state.args.asReadonly(),
|
|
3580
|
+
response: state.response.asReadonly(),
|
|
3581
|
+
latestHttpEvent: state.latestHttpEvent.asReadonly(),
|
|
3582
|
+
loading: state.loading.asReadonly(),
|
|
3583
|
+
error: state.error.asReadonly(),
|
|
3584
|
+
lastTimeExecutedAt: state.lastTimeExecutedAt.asReadonly(),
|
|
3585
|
+
createSnapshot,
|
|
3586
|
+
};
|
|
3587
|
+
return query;
|
|
3588
|
+
};
|
|
3589
|
+
|
|
3590
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3591
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
3592
|
+
const createQueryRepository = (config) => {
|
|
3593
|
+
const httpClient = inject(HttpClient);
|
|
3594
|
+
const cache = new Map();
|
|
3595
|
+
const request = (options) => {
|
|
3596
|
+
const shouldCache = shouldCacheQuery(options.method);
|
|
3597
|
+
const route = buildRoute({
|
|
3598
|
+
base: config.baseUrl,
|
|
3599
|
+
route: options.route,
|
|
3600
|
+
pathParams: options.pathParams,
|
|
3601
|
+
queryParams: options.queryParams,
|
|
3602
|
+
queryParamConfig: config.queryString,
|
|
3603
|
+
});
|
|
3604
|
+
const key = shouldCache &&
|
|
3605
|
+
buildQueryCacheKey(`${options.key ? options.key + '_' : ''}${route}`, {
|
|
3606
|
+
body: options.body,
|
|
3607
|
+
queryParams: options.queryParams,
|
|
3608
|
+
pathParams: options.pathParams,
|
|
3609
|
+
// TODO: remaining props
|
|
3610
|
+
});
|
|
3611
|
+
if (shouldCache && key) {
|
|
3612
|
+
const cacheEntry = cache.get(key);
|
|
3613
|
+
if (cacheEntry) {
|
|
3614
|
+
bind(key, options.destroyRef, cacheEntry.request);
|
|
3615
|
+
if (!options.skipExecution)
|
|
3616
|
+
cacheEntry.request.execute();
|
|
3617
|
+
return { key, request: cacheEntry.request };
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
const request = createHttpRequest({
|
|
3621
|
+
fullPath: route,
|
|
3622
|
+
body: options.body,
|
|
3623
|
+
reportProgress: options.reportProgress,
|
|
3624
|
+
withCredentials: options.withCredentials,
|
|
3625
|
+
transferCache: options.transferCache,
|
|
3626
|
+
responseType: options.responseType || 'json',
|
|
3627
|
+
method: options.method,
|
|
3628
|
+
headers: options.headers,
|
|
3629
|
+
httpClient,
|
|
3630
|
+
cacheAdapter: config.cacheAdapter,
|
|
3631
|
+
retryFn: config.retryFn,
|
|
3632
|
+
});
|
|
3633
|
+
if (!options.skipExecution)
|
|
3634
|
+
request.execute();
|
|
3635
|
+
if (shouldCache && key) {
|
|
3636
|
+
bind(key, options.destroyRef, request);
|
|
3637
|
+
}
|
|
3638
|
+
return { key, request };
|
|
3639
|
+
};
|
|
3640
|
+
const unbind = (key, destroyRef) => {
|
|
3641
|
+
if (!key)
|
|
3642
|
+
return;
|
|
3643
|
+
const cacheEntry = cache.get(key);
|
|
3644
|
+
if (!cacheEntry)
|
|
3645
|
+
return;
|
|
3646
|
+
cacheEntry.consumers.delete(destroyRef);
|
|
3647
|
+
if (cacheEntry.consumers.size === 0) {
|
|
3648
|
+
cacheEntry.request.destroy();
|
|
3649
|
+
cache.delete(key);
|
|
3650
|
+
}
|
|
3651
|
+
};
|
|
3652
|
+
const bind = (key, destroyRef, request) => {
|
|
3653
|
+
if (!key)
|
|
3654
|
+
return;
|
|
3655
|
+
const destroyListener = destroyRef.onDestroy(() => unbind(key, destroyRef));
|
|
3656
|
+
const cacheEntry = cache.get(key);
|
|
3657
|
+
if (cacheEntry) {
|
|
3658
|
+
cacheEntry.consumers.set(destroyRef, destroyListener);
|
|
3659
|
+
}
|
|
3660
|
+
else {
|
|
3661
|
+
const consumers = new Map([]);
|
|
3662
|
+
consumers.set(destroyRef, destroyListener);
|
|
3663
|
+
cache.set(key, {
|
|
3664
|
+
consumers,
|
|
3665
|
+
request,
|
|
3666
|
+
});
|
|
3667
|
+
}
|
|
3668
|
+
};
|
|
3669
|
+
const repository = {
|
|
3670
|
+
request,
|
|
3671
|
+
unbind,
|
|
3672
|
+
};
|
|
3673
|
+
return repository;
|
|
3674
|
+
};
|
|
3675
|
+
|
|
3676
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
3677
|
+
const createQueryClient = (config) => {
|
|
3678
|
+
const repository = createQueryRepository(config);
|
|
3679
|
+
const client = {
|
|
3680
|
+
repository,
|
|
3681
|
+
};
|
|
3682
|
+
return client;
|
|
3683
|
+
};
|
|
3684
|
+
const provideQueryClient = (config) => {
|
|
3685
|
+
return {
|
|
3686
|
+
provide: config.token,
|
|
3687
|
+
useFactory: () => createQueryClient(config),
|
|
3688
|
+
};
|
|
3689
|
+
};
|
|
3690
|
+
|
|
3691
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
3692
|
+
const createQueryClientConfig = (options) => {
|
|
3693
|
+
const token = new InjectionToken(`QueryClient_${options.name}`);
|
|
3694
|
+
const clientConfig = {
|
|
3695
|
+
baseUrl: options.baseUrl,
|
|
3696
|
+
token,
|
|
3697
|
+
name: options.name,
|
|
3698
|
+
queryString: options.queryString,
|
|
3699
|
+
};
|
|
3700
|
+
return clientConfig;
|
|
3701
|
+
};
|
|
3702
|
+
|
|
3703
|
+
const splitQueryConfig = (args) => {
|
|
3704
|
+
let queryConfig = {};
|
|
3705
|
+
let features = [];
|
|
3706
|
+
const first = args[0];
|
|
3707
|
+
if (first) {
|
|
3708
|
+
if ('type' in first) {
|
|
3709
|
+
features = args;
|
|
3710
|
+
}
|
|
3711
|
+
else {
|
|
3712
|
+
[queryConfig, ...features] = args;
|
|
3713
|
+
}
|
|
3714
|
+
}
|
|
3715
|
+
return { features, queryConfig };
|
|
3716
|
+
};
|
|
3717
|
+
const createQueryCreator = (options, internals) => {
|
|
3718
|
+
function queryCreator(...args) {
|
|
3719
|
+
const { features, queryConfig } = splitQueryConfig(args);
|
|
3720
|
+
return createQuery({
|
|
3721
|
+
creator: options,
|
|
3722
|
+
creatorInternals: internals,
|
|
3723
|
+
features,
|
|
3724
|
+
queryConfig,
|
|
3725
|
+
});
|
|
3726
|
+
}
|
|
3727
|
+
return queryCreator;
|
|
3728
|
+
};
|
|
3729
|
+
|
|
3730
|
+
const AUTH_HEADER = 'Authorization';
|
|
3731
|
+
const createSecureExecuteFn = (options) => {
|
|
3732
|
+
const executeState = setupQueryExecuteState();
|
|
3733
|
+
const authProvider = inject(options.creatorInternals.authProvider.token);
|
|
3734
|
+
let authQuerySubscription = Subscription.EMPTY;
|
|
3735
|
+
const reset = () => {
|
|
3736
|
+
authQuerySubscription.unsubscribe();
|
|
3737
|
+
authQuerySubscription = Subscription.EMPTY;
|
|
3738
|
+
resetExecuteState({ executeState, executeOptions: options });
|
|
3739
|
+
};
|
|
3740
|
+
const error = (query) => {
|
|
3741
|
+
const state = options.state;
|
|
3742
|
+
state.error.set(query.error());
|
|
3743
|
+
state.loading.set(null);
|
|
3744
|
+
state.response.set(null);
|
|
3745
|
+
state.latestHttpEvent.set(null);
|
|
3746
|
+
state.args.set(null);
|
|
3747
|
+
};
|
|
3748
|
+
const authAndExec = (args) => {
|
|
3749
|
+
const tokens = authProvider.tokens();
|
|
3750
|
+
let headers = args?.headers || new HttpHeaders();
|
|
3751
|
+
if (!tokens) {
|
|
3752
|
+
throw new Error('Tokens are not available inside authAndExec');
|
|
3753
|
+
}
|
|
3754
|
+
if (!headers.has(AUTH_HEADER)) {
|
|
3755
|
+
headers = headers.set(AUTH_HEADER, `Bearer ${tokens.accessToken}`);
|
|
3756
|
+
}
|
|
3757
|
+
const updatedArgs = { ...(args ?? {}), headers };
|
|
3758
|
+
queryExecute({
|
|
3759
|
+
executeOptions: options,
|
|
3760
|
+
executeState,
|
|
3761
|
+
args: updatedArgs,
|
|
3762
|
+
});
|
|
3763
|
+
};
|
|
3764
|
+
const exec = (args = options.state.args()) => {
|
|
3765
|
+
authQuerySubscription.unsubscribe();
|
|
3766
|
+
authQuerySubscription = Subscription.EMPTY;
|
|
3767
|
+
cleanupPreviousExecute({ executeOptions: options, executeState, args });
|
|
3768
|
+
const authQuery = authProvider.latestExecutedQuery();
|
|
3769
|
+
if (!authQuery || authQuery.loading()) {
|
|
3770
|
+
options.state.loading.set({ executeTime: Date.now(), progress: null });
|
|
3771
|
+
authQuerySubscription = toObservable(authProvider.latestExecutedQuery, { injector: options.deps.injector })
|
|
3772
|
+
.pipe(switchMap((query) => {
|
|
3773
|
+
if (!query)
|
|
3774
|
+
return of(null);
|
|
3775
|
+
return toObservable(query.isAlive, { injector: options.deps.injector }).pipe(tap((isAlive) => {
|
|
3776
|
+
if (isAlive)
|
|
3777
|
+
return;
|
|
3778
|
+
if (query.error()) {
|
|
3779
|
+
error(query);
|
|
3780
|
+
}
|
|
3781
|
+
else if (query.response()) {
|
|
3782
|
+
authAndExec(args);
|
|
3783
|
+
}
|
|
3784
|
+
}));
|
|
3785
|
+
}))
|
|
3786
|
+
.subscribe();
|
|
3787
|
+
}
|
|
3788
|
+
else if (authQuery.response()) {
|
|
3789
|
+
authAndExec(args);
|
|
3790
|
+
}
|
|
3791
|
+
else if (authQuery.error()) {
|
|
3792
|
+
error(authQuery);
|
|
3793
|
+
}
|
|
3794
|
+
else {
|
|
3795
|
+
throw new Error('Invalid state ocurred inside createSecureExecuteFn');
|
|
3796
|
+
}
|
|
3797
|
+
};
|
|
3798
|
+
exec['reset'] = reset;
|
|
3799
|
+
return exec;
|
|
3800
|
+
};
|
|
3801
|
+
|
|
3802
|
+
const createSecureQuery = (options) => {
|
|
3803
|
+
const deps = setupQueryDependencies({ clientConfig: options.creatorInternals.client });
|
|
3804
|
+
const state = setupQueryState({});
|
|
3805
|
+
const { creator, creatorInternals, queryConfig } = options;
|
|
3806
|
+
const flags = getQueryFeatureUsage(options);
|
|
3807
|
+
const execute = createSecureExecuteFn({
|
|
3808
|
+
deps,
|
|
3809
|
+
state,
|
|
3810
|
+
creator,
|
|
3811
|
+
creatorInternals,
|
|
3812
|
+
queryConfig: options.queryConfig,
|
|
3813
|
+
});
|
|
3814
|
+
const createSnapshot = createQuerySnapshotFn({ state, deps });
|
|
3815
|
+
const featureFnContext = {
|
|
3816
|
+
state,
|
|
3817
|
+
queryConfig,
|
|
3818
|
+
creatorConfig: creator,
|
|
3819
|
+
creatorInternals,
|
|
3820
|
+
execute,
|
|
3821
|
+
flags,
|
|
3822
|
+
};
|
|
3823
|
+
applyQueryFeatures(options, featureFnContext);
|
|
3824
|
+
maybeExecute({ execute, flags });
|
|
3825
|
+
const query = {
|
|
3826
|
+
execute,
|
|
3827
|
+
args: state.args.asReadonly(),
|
|
3828
|
+
response: state.response.asReadonly(),
|
|
3829
|
+
latestHttpEvent: state.latestHttpEvent.asReadonly(),
|
|
3830
|
+
loading: state.loading.asReadonly(),
|
|
3831
|
+
error: state.error.asReadonly(),
|
|
3832
|
+
lastTimeExecutedAt: state.lastTimeExecutedAt.asReadonly(),
|
|
3833
|
+
createSnapshot,
|
|
3834
|
+
};
|
|
3835
|
+
return query;
|
|
3836
|
+
};
|
|
3837
|
+
|
|
3838
|
+
const createSecureQueryCreator = (options, internals) => {
|
|
3839
|
+
function queryCreator(...args) {
|
|
3840
|
+
const { features, queryConfig } = splitQueryConfig(args);
|
|
3841
|
+
return createSecureQuery({
|
|
3842
|
+
creator: options,
|
|
3843
|
+
creatorInternals: internals,
|
|
3844
|
+
features,
|
|
3845
|
+
queryConfig,
|
|
3846
|
+
});
|
|
3847
|
+
}
|
|
3848
|
+
return queryCreator;
|
|
3849
|
+
};
|
|
3850
|
+
|
|
3851
|
+
const createGetQuery = (client) => {
|
|
3852
|
+
return (creatorOptions) => createQueryCreator(creatorOptions, { method: 'GET', client });
|
|
3853
|
+
};
|
|
3854
|
+
const createSecureGetQuery = (client, authProvider) => {
|
|
3855
|
+
return (creatorOptions) => createSecureQueryCreator(creatorOptions, { method: 'GET', client, authProvider });
|
|
3856
|
+
};
|
|
3857
|
+
const createPostQuery = (client) => {
|
|
3858
|
+
return (creatorOptions) => createQueryCreator(creatorOptions, { method: 'POST', client });
|
|
3859
|
+
};
|
|
3860
|
+
const createSecurePostQuery = (client, authProvider) => {
|
|
3861
|
+
return (creatorOptions) => createSecureQueryCreator(creatorOptions, { method: 'POST', client, authProvider });
|
|
3862
|
+
};
|
|
3863
|
+
const createPutQuery = (client) => {
|
|
3864
|
+
return (creatorOptions) => createQueryCreator(creatorOptions, { method: 'PUT', client });
|
|
3865
|
+
};
|
|
3866
|
+
const createSecurePutQuery = (client, authProvider) => {
|
|
3867
|
+
return (creatorOptions) => createSecureQueryCreator(creatorOptions, { method: 'PUT', client, authProvider });
|
|
3868
|
+
};
|
|
3869
|
+
const createDeleteQuery = (client) => {
|
|
3870
|
+
return (creatorOptions) => createQueryCreator(creatorOptions, { method: 'DELETE', client });
|
|
3871
|
+
};
|
|
3872
|
+
const createSecureDeleteQuery = (client, authProvider) => {
|
|
3873
|
+
return (creatorOptions) => createSecureQueryCreator(creatorOptions, { method: 'DELETE', client, authProvider });
|
|
3874
|
+
};
|
|
3875
|
+
const createPatchQuery = (client) => {
|
|
3876
|
+
return (creatorOptions) => createQueryCreator(creatorOptions, { method: 'PATCH', client });
|
|
3877
|
+
};
|
|
3878
|
+
const createSecurePatchQuery = (client, authProvider) => {
|
|
3879
|
+
return (creatorOptions) => createSecureQueryCreator(creatorOptions, { method: 'PATCH', client, authProvider });
|
|
3880
|
+
};
|
|
3881
|
+
|
|
3882
|
+
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
3883
|
+
const createQueryFeature = (config) => {
|
|
3884
|
+
return config;
|
|
3885
|
+
};
|
|
3886
|
+
const withArgs = (args) => {
|
|
3887
|
+
return createQueryFeature({
|
|
3888
|
+
type: "withArgs" /* QueryFeatureType.WithArgs */,
|
|
3889
|
+
fn: (context) => {
|
|
3890
|
+
const currArgs = computed(() => args());
|
|
3891
|
+
queryEffect(() => {
|
|
3892
|
+
const currArgsNow = currArgs();
|
|
3893
|
+
if (currArgsNow === null)
|
|
3894
|
+
return;
|
|
3895
|
+
untracked(() => {
|
|
3896
|
+
if (currArgsNow === QUERY_ARGS_RESET) {
|
|
3897
|
+
context.state.args.set(null);
|
|
3898
|
+
return;
|
|
3899
|
+
}
|
|
3900
|
+
context.state.args.set(currArgsNow);
|
|
3901
|
+
if (context.flags.shouldAutoExecute)
|
|
3902
|
+
context.execute(currArgsNow);
|
|
3903
|
+
});
|
|
3904
|
+
}, QUERY_EFFECT_ERROR_MESSAGE);
|
|
3905
|
+
},
|
|
3906
|
+
});
|
|
3907
|
+
};
|
|
3908
|
+
const withPolling = (options) => {
|
|
3909
|
+
return createQueryFeature({
|
|
3910
|
+
type: "withPolling" /* QueryFeatureType.WithPolling */,
|
|
3911
|
+
fn: (context) => {
|
|
3912
|
+
if (!context.flags.shouldAutoExecuteMethod) {
|
|
3913
|
+
throw withPollingUsedOnUnsupportedHttpMethod(context.creatorInternals.method);
|
|
3914
|
+
}
|
|
3915
|
+
let intervalId = null;
|
|
3916
|
+
queryEffect(() => {
|
|
3917
|
+
const args = context.state.args();
|
|
3918
|
+
untracked(() => {
|
|
3919
|
+
if (intervalId !== null)
|
|
3920
|
+
clearInterval(intervalId);
|
|
3921
|
+
if (args === null)
|
|
3922
|
+
return;
|
|
3923
|
+
if (options.executeInitially) {
|
|
3924
|
+
context.execute(args);
|
|
3925
|
+
}
|
|
3926
|
+
intervalId = window.setInterval(() => {
|
|
3927
|
+
context.execute(args);
|
|
3928
|
+
}, options.interval);
|
|
3929
|
+
});
|
|
3930
|
+
}, QUERY_EFFECT_ERROR_MESSAGE);
|
|
3931
|
+
inject(DestroyRef).onDestroy(() => intervalId !== null && clearInterval(intervalId));
|
|
3932
|
+
},
|
|
3933
|
+
});
|
|
3934
|
+
};
|
|
3935
|
+
const withLogging = (options) => {
|
|
3936
|
+
return createQueryFeature({
|
|
3937
|
+
type: "withLogging" /* QueryFeatureType.WithLogging */,
|
|
3938
|
+
fn: (context) => {
|
|
3939
|
+
effect(() => {
|
|
3940
|
+
const event = context.state.latestHttpEvent();
|
|
3941
|
+
if (event === null)
|
|
3942
|
+
return;
|
|
3943
|
+
untracked(() => {
|
|
3944
|
+
options.logFn(event);
|
|
3945
|
+
});
|
|
3946
|
+
});
|
|
3947
|
+
},
|
|
3948
|
+
});
|
|
3949
|
+
};
|
|
3950
|
+
const withErrorHandling = (options) => {
|
|
3951
|
+
return createQueryFeature({
|
|
3952
|
+
type: "withErrorHandling" /* QueryFeatureType.WithErrorHandling */,
|
|
3953
|
+
fn: (context) => {
|
|
3954
|
+
effect(() => {
|
|
3955
|
+
const error = context.state.error();
|
|
3956
|
+
if (error === null)
|
|
3957
|
+
return;
|
|
3958
|
+
untracked(() => {
|
|
3959
|
+
options.handler(error);
|
|
3960
|
+
});
|
|
3961
|
+
});
|
|
3962
|
+
},
|
|
3963
|
+
});
|
|
3964
|
+
};
|
|
3965
|
+
const withSuccessHandling = (options) => {
|
|
3966
|
+
return createQueryFeature({
|
|
3967
|
+
type: "withSuccessHandling" /* QueryFeatureType.WithSuccessHandling */,
|
|
3968
|
+
fn: (context) => {
|
|
3969
|
+
effect(() => {
|
|
3970
|
+
const response = context.state.response();
|
|
3971
|
+
if (response === null)
|
|
3972
|
+
return;
|
|
3973
|
+
untracked(() => {
|
|
3974
|
+
options.handler(response);
|
|
3975
|
+
});
|
|
3976
|
+
});
|
|
3977
|
+
},
|
|
3978
|
+
});
|
|
3979
|
+
};
|
|
3980
|
+
const withAutoRefresh = (options) => {
|
|
3981
|
+
return createQueryFeature({
|
|
3982
|
+
type: "withAutoRefresh" /* QueryFeatureType.WithAutoRefresh */,
|
|
3983
|
+
fn: (context) => {
|
|
3984
|
+
if (!context.flags.shouldAutoExecuteMethod) {
|
|
3985
|
+
throw withAutoRefreshUsedOnUnsupportedHttpMethod(context.creatorInternals.method);
|
|
3986
|
+
}
|
|
3987
|
+
if (context.queryConfig.onlyManualExecution && !options.ignoreOnlyManualExecution) {
|
|
3988
|
+
throw withAutoRefreshUsedOnUnsupportedHttpMethod(context.creatorInternals.method);
|
|
3989
|
+
}
|
|
3990
|
+
queryEffect(() => {
|
|
3991
|
+
for (const signal of options.signalChanges) {
|
|
3992
|
+
signal();
|
|
3993
|
+
}
|
|
3994
|
+
untracked(() => {
|
|
3995
|
+
const args = context.state.args();
|
|
3996
|
+
if (args === null)
|
|
3997
|
+
return;
|
|
3998
|
+
context.execute(args);
|
|
3999
|
+
});
|
|
4000
|
+
}, QUERY_EFFECT_ERROR_MESSAGE);
|
|
4001
|
+
},
|
|
4002
|
+
});
|
|
4003
|
+
};
|
|
4004
|
+
|
|
4005
|
+
var index = /*#__PURE__*/Object.freeze({
|
|
4006
|
+
__proto__: null,
|
|
4007
|
+
QUERY_ARGS_RESET: QUERY_ARGS_RESET,
|
|
4008
|
+
QUERY_EFFECT_ERROR_MESSAGE: QUERY_EFFECT_ERROR_MESSAGE,
|
|
4009
|
+
SPEED_BUFFER_TIME_IN_MS: SPEED_BUFFER_TIME_IN_MS,
|
|
4010
|
+
applyQueryFeatures: applyQueryFeatures,
|
|
4011
|
+
bearerExpiresInPropertyNotNumber: bearerExpiresInPropertyNotNumber,
|
|
4012
|
+
cleanupPreviousExecute: cleanupPreviousExecute,
|
|
4013
|
+
cookieLoginTriedButCookieDisabled: cookieLoginTriedButCookieDisabled,
|
|
4014
|
+
createBearerAuthProvider: createBearerAuthProvider,
|
|
4015
|
+
createBearerAuthProviderConfig: createBearerAuthProviderConfig,
|
|
4016
|
+
createDeleteQuery: createDeleteQuery,
|
|
4017
|
+
createExecuteFn: createExecuteFn,
|
|
4018
|
+
createGetQuery: createGetQuery,
|
|
4019
|
+
createHttpRequest: createHttpRequest,
|
|
4020
|
+
createPatchQuery: createPatchQuery,
|
|
4021
|
+
createPostQuery: createPostQuery,
|
|
4022
|
+
createPutQuery: createPutQuery,
|
|
4023
|
+
createQuery: createQuery,
|
|
4024
|
+
createQueryClient: createQueryClient,
|
|
4025
|
+
createQueryClientConfig: createQueryClientConfig,
|
|
4026
|
+
createQueryCreator: createQueryCreator,
|
|
4027
|
+
createQueryRepository: createQueryRepository,
|
|
4028
|
+
createQuerySnapshotFn: createQuerySnapshotFn,
|
|
4029
|
+
createSecureDeleteQuery: createSecureDeleteQuery,
|
|
4030
|
+
createSecureExecuteFn: createSecureExecuteFn,
|
|
4031
|
+
createSecureGetQuery: createSecureGetQuery,
|
|
4032
|
+
createSecurePatchQuery: createSecurePatchQuery,
|
|
4033
|
+
createSecurePostQuery: createSecurePostQuery,
|
|
4034
|
+
createSecurePutQuery: createSecurePutQuery,
|
|
4035
|
+
createSecureQuery: createSecureQuery,
|
|
4036
|
+
createSecureQueryCreator: createSecureQueryCreator,
|
|
4037
|
+
defaultResponseTransformerResponseNotContainingAccessToken: defaultResponseTransformerResponseNotContainingAccessToken,
|
|
4038
|
+
defaultResponseTransformerResponseNotContainingRefreshToken: defaultResponseTransformerResponseNotContainingRefreshToken,
|
|
4039
|
+
defaultResponseTransformerResponseNotObject: defaultResponseTransformerResponseNotObject,
|
|
4040
|
+
disableCookieCalledWithoutCookieConfig: disableCookieCalledWithoutCookieConfig,
|
|
4041
|
+
enableCookieCalledWithoutCookieConfig: enableCookieCalledWithoutCookieConfig,
|
|
4042
|
+
extractExpiresInSeconds: extractExpiresInSeconds,
|
|
4043
|
+
getQueryFeatureUsage: getQueryFeatureUsage,
|
|
4044
|
+
loginCalledWithoutConfig: loginCalledWithoutConfig,
|
|
4045
|
+
loginWithTokenCalledWithoutConfig: loginWithTokenCalledWithoutConfig,
|
|
4046
|
+
maybeExecute: maybeExecute,
|
|
4047
|
+
provideBearerAuthProvider: provideBearerAuthProvider,
|
|
4048
|
+
provideQueryClient: provideQueryClient,
|
|
4049
|
+
queryEffect: queryEffect,
|
|
4050
|
+
queryExecute: queryExecute,
|
|
4051
|
+
queryFeatureUsedMultipleTimes: queryFeatureUsedMultipleTimes,
|
|
4052
|
+
refreshTokenCalledWithoutConfig: refreshTokenCalledWithoutConfig,
|
|
4053
|
+
resetExecuteState: resetExecuteState,
|
|
4054
|
+
selectRoleCalledWithoutConfig: selectRoleCalledWithoutConfig,
|
|
4055
|
+
setupQueryDependencies: setupQueryDependencies,
|
|
4056
|
+
setupQueryExecuteState: setupQueryExecuteState,
|
|
4057
|
+
setupQueryState: setupQueryState,
|
|
4058
|
+
shouldAutoExecuteQuery: shouldAutoExecuteQuery,
|
|
4059
|
+
shouldRetryRequest: shouldRetryRequest,
|
|
4060
|
+
splitQueryConfig: splitQueryConfig,
|
|
4061
|
+
unableToDecryptBearerToken: unableToDecryptBearerToken,
|
|
4062
|
+
withArgs: withArgs,
|
|
4063
|
+
withArgsQueryFeatureMissingButRouteIsFunction: withArgsQueryFeatureMissingButRouteIsFunction,
|
|
4064
|
+
withAutoRefresh: withAutoRefresh,
|
|
4065
|
+
withAutoRefreshUsedInManualQuery: withAutoRefreshUsedInManualQuery,
|
|
4066
|
+
withAutoRefreshUsedOnUnsupportedHttpMethod: withAutoRefreshUsedOnUnsupportedHttpMethod,
|
|
4067
|
+
withErrorHandling: withErrorHandling,
|
|
4068
|
+
withLogging: withLogging,
|
|
4069
|
+
withPolling: withPolling,
|
|
4070
|
+
withPollingUsedOnUnsupportedHttpMethod: withPollingUsedOnUnsupportedHttpMethod,
|
|
4071
|
+
withSuccessHandling: withSuccessHandling
|
|
4072
|
+
});
|
|
4073
|
+
|
|
2813
4074
|
const transformToString = (value) => {
|
|
2814
4075
|
if (typeof value === 'string') {
|
|
2815
4076
|
return value;
|
|
@@ -2946,11 +4207,12 @@ class QueryForm {
|
|
|
2946
4207
|
this._router = inject(Router);
|
|
2947
4208
|
this._activatedRoute = inject(ActivatedRoute);
|
|
2948
4209
|
this._defaultValues = this._extractDefaultValues();
|
|
2949
|
-
this._routerStateService = inject(RouterStateService);
|
|
2950
4210
|
this._zone = inject(NgZone);
|
|
2951
4211
|
this._didValueChanges$ = new Subject();
|
|
2952
4212
|
this._isObserving = false;
|
|
2953
4213
|
this._skipNextResets = false;
|
|
4214
|
+
this._queryParamChanges$ = toObservable(injectQueryParamChanges());
|
|
4215
|
+
this._queryParams = injectQueryParams();
|
|
2954
4216
|
/**
|
|
2955
4217
|
* The angular form group that contains all the fields.
|
|
2956
4218
|
*
|
|
@@ -2997,6 +4259,7 @@ class QueryForm {
|
|
|
2997
4259
|
})
|
|
2998
4260
|
.filter((v) => v === false).length));
|
|
2999
4261
|
assertInInjectionContext(QueryForm);
|
|
4262
|
+
inject(DestroyRef).onDestroy(() => this._cleanup());
|
|
3000
4263
|
}
|
|
3001
4264
|
observe(options) {
|
|
3002
4265
|
if (this._isObserving) {
|
|
@@ -3008,7 +4271,7 @@ class QueryForm {
|
|
|
3008
4271
|
this._isObserving = true;
|
|
3009
4272
|
if (options?.syncOnNavigation !== false) {
|
|
3010
4273
|
const didChanges = this.setFormValueFromUrlQueryParams({
|
|
3011
|
-
queryParams: this.
|
|
4274
|
+
queryParams: this._queryParams(),
|
|
3012
4275
|
});
|
|
3013
4276
|
if (didChanges) {
|
|
3014
4277
|
this._handleFormChange(true);
|
|
@@ -3073,7 +4336,7 @@ class QueryForm {
|
|
|
3073
4336
|
}), takeUntil(this._destroy$), takeUntil(this._unobserveTrigger$))
|
|
3074
4337
|
.subscribe();
|
|
3075
4338
|
if (options?.syncOnNavigation !== false) {
|
|
3076
|
-
this.
|
|
4339
|
+
this._queryParamChanges$
|
|
3077
4340
|
.pipe(takeUntil(this._destroy$), takeUntil(this._unobserveTrigger$), tap((changes) => {
|
|
3078
4341
|
const didValueChanges = this.setFormValueFromUrlQueryParams({ queryParams: changes });
|
|
3079
4342
|
if (didValueChanges) {
|
|
@@ -3119,6 +4382,7 @@ class QueryForm {
|
|
|
3119
4382
|
}
|
|
3120
4383
|
unobserve() {
|
|
3121
4384
|
this._unobserveTrigger$.next(true);
|
|
4385
|
+
this._cleanup();
|
|
3122
4386
|
}
|
|
3123
4387
|
setFormValueFromUrlQueryParams(options) {
|
|
3124
4388
|
let didValueChanges = false;
|
|
@@ -3256,10 +4520,12 @@ class QueryForm {
|
|
|
3256
4520
|
}
|
|
3257
4521
|
}
|
|
3258
4522
|
this._zone.run(() => {
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
4523
|
+
queueMicrotask(() => {
|
|
4524
|
+
this._router.navigate([], {
|
|
4525
|
+
queryParams,
|
|
4526
|
+
replaceUrl,
|
|
4527
|
+
queryParamsHandling: 'merge',
|
|
4528
|
+
});
|
|
3263
4529
|
});
|
|
3264
4530
|
});
|
|
3265
4531
|
}
|
|
@@ -3277,6 +4543,22 @@ class QueryForm {
|
|
|
3277
4543
|
}
|
|
3278
4544
|
this._currentFormValue$.next(newVal);
|
|
3279
4545
|
}
|
|
4546
|
+
_cleanup() {
|
|
4547
|
+
const queryParamKeys = Object.keys(this._fields);
|
|
4548
|
+
const queryParams = queryParamKeys.reduce((acc, key) => {
|
|
4549
|
+
acc[this._transformKeyToQueryParam(key)] = undefined;
|
|
4550
|
+
return acc;
|
|
4551
|
+
}, {});
|
|
4552
|
+
this._zone.run(() => {
|
|
4553
|
+
queueMicrotask(() => {
|
|
4554
|
+
this._router.navigate([], {
|
|
4555
|
+
queryParams,
|
|
4556
|
+
replaceUrl: true,
|
|
4557
|
+
queryParamsHandling: 'merge',
|
|
4558
|
+
});
|
|
4559
|
+
});
|
|
4560
|
+
});
|
|
4561
|
+
}
|
|
3280
4562
|
}
|
|
3281
4563
|
|
|
3282
4564
|
// Burst cache
|
|
@@ -3285,5 +4567,5 @@ class QueryForm {
|
|
|
3285
4567
|
* Generated bundle index. Do not edit.
|
|
3286
4568
|
*/
|
|
3287
4569
|
|
|
3288
|
-
export { BasicAuthProvider, BearerAuthProvider, CustomHeaderAuthProvider, EntityStore, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, QUERY_CLIENT_DEVTOOLS_TOKEN, Query, QueryClient, QueryCreator, QueryDevtoolsComponent, QueryDirective, QueryError, QueryField, QueryForm, QueryShortNamePipe, QueryStore, addQueryContainerHandling, buildErrorMessage, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, castQueryCreatorTypes, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, createInfinityQueryConfig, createQueryCollection, createQueryCollectionSignal, createQueryCollectionSubject, decryptBearer, deepFreeze, def, detectContentTypeHeader, extractExpiresInSeconds, extractQuery, filterFailure, filterNull, filterQueryStates, filterSuccess, forEachHeader, getDefaultHeaders, getResponseUrl, gql, hasHeader, ignoreAutoRefresh, insertFrom, invalidBaseRouteError, invalidBodyError, invalidRouteError, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isClassValidatorError, isCustomHeaderAuthProvider, isEmptyString, isGqlQueryConfig, isNaN$1 as isNaN, isQuery, isQueryCollection, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyFormViolationListError, isSymfonyListError, isSymfonyPagerfantaOutOfRangeError, mapToPaginated, mergeHeaders, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, pathParamsMissingInRouteFunctionError, provideQueryClientForDevtools, queryArrayComputed, queryComputed, queryComputedTillTruthy, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, queryStateErrorSignal, queryStateLoadingSignal, queryStateResponseSignal, queryStateSignal, removeFrom, request, resetPageOnError, serializeBody, shouldCacheQuery, shouldRetryRequest, skipPaginationPageParamCalculator, switchQueryCollectionState, switchQueryState, takeUntilResponse, toQuerySignal, toQuerySubject, transformGql, transformMethod, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray };
|
|
4570
|
+
export { BasicAuthProvider, BearerAuthProvider, CustomHeaderAuthProvider, EntityStore, index as ExperimentalQuery, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, QUERY_CLIENT_DEVTOOLS_TOKEN, Query, QueryClient, QueryCreator, QueryDevtoolsComponent, QueryDirective, QueryError, QueryField, QueryForm, QueryShortNamePipe, QueryStore, addQueryContainerHandling, buildErrorMessage, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, castQueryCreatorTypes, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, createInfinityQueryConfig, createQueryCollection, createQueryCollectionSignal, createQueryCollectionSubject, decryptBearer, deepFreeze, def, detectContentTypeHeader, extractExpiresInSeconds$1 as extractExpiresInSeconds, extractQuery, filterFailure, filterNull, filterQueryStates, filterSuccess, forEachHeader, getDefaultHeaders, getResponseUrl, gql, hasHeader, ignoreAutoRefresh, insertFrom, invalidBaseRouteError, invalidBodyError, invalidRouteError, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isClassValidatorError, isCustomHeaderAuthProvider, isEmptyString, isGqlQueryConfig, isNaN$1 as isNaN, isQuery, isQueryCollection, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyFormViolationListError, isSymfonyListError, isSymfonyPagerfantaOutOfRangeError, mapToPaginated, mergeHeaders, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, pathParamsMissingInRouteFunctionError, provideQueryClientForDevtools, queryArrayComputed, queryComputed, queryComputedTillTruthy, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, queryStateErrorSignal, queryStateLoadingSignal, queryStateResponseSignal, queryStateSignal, removeFrom, request, resetPageOnError, serializeBody, shouldCacheQuery, shouldRetryRequest$1 as shouldRetryRequest, skipPaginationPageParamCalculator, switchQueryCollectionState, switchQueryState, takeUntilResponse, toQuerySignal, toQuerySubject, transformGql, transformMethod, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray };
|
|
3289
4571
|
//# sourceMappingURL=ethlete-query.mjs.map
|