@ethlete/query 6.0.0-next.39 → 6.0.0-next.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject,
|
|
3
|
-
import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
2
|
+
import { inject, Injector, effect, DestroyRef, InjectionToken, EnvironmentInjector, ElementRef, ErrorHandler, createEnvironmentInjector, untracked, signal, linkedSignal, computed, runInInjectionContext, isDevMode, PLATFORM_ID, resource, DOCUMENT, VERSION, makeEnvironmentProviders, assertInInjectionContext, provideEnvironmentInitializer, ChangeDetectorRef, ViewContainerRef, TemplateRef, Input, Directive, input, Pipe, ViewEncapsulation, Component, NgZone } from '@angular/core';
|
|
4
3
|
import { UrlTree, Router, RedirectCommand, ActivatedRoute } from '@angular/router';
|
|
5
|
-
import {
|
|
6
|
-
import { defineStaticProvider, RuntimeError, clamp, randomId, defineRootProvider, isObject, injectUnsavedChangesCoordinator, injectRoute, getCookie,
|
|
4
|
+
import { Observable, defer, from, filter, Subject, Subscription, throwError, of, timer, switchMap, tap, retry, catchError, EMPTY, take, takeUntil, finalize, mergeMap, toArray, map, merge, takeWhile, firstValueFrom, race, concatMap, fromEvent, throttleTime, interval, startWith, pairwise, BehaviorSubject, combineLatest, ReplaySubject, shareReplay, skip, withLatestFrom, debounceTime } from 'rxjs';
|
|
5
|
+
import { defineStaticProvider, RuntimeError, clamp, randomId, defineRootProvider, isObject, injectUnsavedChangesCoordinator, injectRoute, getCookie, deleteCookie, setCookie, CORE_VERSION, createDestroy, computedTillTruthy, defineProvider, toProvideFn, toInjectFn, nextFrame, injectQueryParams, injectQueryParamChanges, clone, equal, ET_PROPERTY_REMOVED, previousSignalValue } from '@ethlete/core';
|
|
7
6
|
import { HttpClient, HttpEventType, HttpErrorResponse, HttpResponse, HttpHeaders, HttpStatusCode } from '@angular/common/http';
|
|
7
|
+
import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
8
8
|
import { getActiveConsumer, setActiveConsumer } from '@angular/core/primitives/signals';
|
|
9
9
|
import { isPlatformBrowser, NgClass, AsyncPipe, JsonPipe } from '@angular/common';
|
|
10
10
|
import { validateAsync, form } from '@angular/forms/signals';
|
|
@@ -53,15 +53,15 @@ const createAuthGuard = (providerRef, config) => {
|
|
|
53
53
|
const behavior = config.navigationBehaviorOptions ?? { replaceUrl: true };
|
|
54
54
|
const guardFor = (requiresSession) => () => {
|
|
55
55
|
const router = inject(Router);
|
|
56
|
+
const injector = inject(Injector);
|
|
56
57
|
const provider = providerRef.inject();
|
|
57
58
|
// Captured before the wait below: once the session settles the router has moved on, and the URL
|
|
58
59
|
// the visitor actually asked for is no longer reachable from it.
|
|
59
60
|
const attemptedUrl = router.currentNavigation()?.extractedUrl.toString() ?? router.url;
|
|
60
|
-
const settled =
|
|
61
|
+
const settled = () => {
|
|
61
62
|
const status = provider.sessionStatus();
|
|
62
63
|
return status !== 'unknown' && status !== 'restoring';
|
|
63
|
-
}
|
|
64
|
-
...(ngDevMode ? [{ debugName: "settled" }] : /* istanbul ignore next */ []));
|
|
64
|
+
};
|
|
65
65
|
const decide = () => {
|
|
66
66
|
const authenticated = provider.sessionStatus() === 'authenticated';
|
|
67
67
|
if (authenticated === requiresSession)
|
|
@@ -75,7 +75,15 @@ const createAuthGuard = (providerRef, config) => {
|
|
|
75
75
|
};
|
|
76
76
|
if (settled())
|
|
77
77
|
return decide();
|
|
78
|
-
return
|
|
78
|
+
return new Observable((subscriber) => {
|
|
79
|
+
const watcher = effect(() => {
|
|
80
|
+
if (!settled())
|
|
81
|
+
return;
|
|
82
|
+
subscriber.next(decide());
|
|
83
|
+
subscriber.complete();
|
|
84
|
+
}, { ...(ngDevMode ? { debugName: "watcher" } : /* istanbul ignore next */ {}), injector });
|
|
85
|
+
return () => watcher.destroy();
|
|
86
|
+
});
|
|
79
87
|
};
|
|
80
88
|
const requireSession = guardFor(true);
|
|
81
89
|
const requireAnonymous = guardFor(false);
|
|
@@ -331,13 +339,12 @@ const consumeSuppressQueryStackDevtools = () => {
|
|
|
331
339
|
const isCreateGqlQueryOptions = (options) => 'transport' in options.creatorInternals;
|
|
332
340
|
|
|
333
341
|
const wrapAsObservableSignal = (source, defaultInjector) => {
|
|
342
|
+
const default$ = toObservable(source, { injector: defaultInjector });
|
|
334
343
|
const asObservable = (options) => {
|
|
335
|
-
const effectiveInjector = options?.injector ?? defaultInjector;
|
|
336
|
-
const base$ = toObservable(source, { injector: effectiveInjector });
|
|
337
344
|
if (options?.injector) {
|
|
338
|
-
return
|
|
345
|
+
return toObservable(source, { injector: options.injector }).pipe(takeUntilDestroyed(defaultInjector.get(DestroyRef)));
|
|
339
346
|
}
|
|
340
|
-
return
|
|
347
|
+
return default$;
|
|
341
348
|
};
|
|
342
349
|
return Object.assign(source, { asObservable });
|
|
343
350
|
};
|
|
@@ -693,7 +700,7 @@ const withPolling = (options) => {
|
|
|
693
700
|
// It should have args because a withArgs feature is present.
|
|
694
701
|
if (args === null && context.flags.hasWithArgsFeature)
|
|
695
702
|
return;
|
|
696
|
-
if (options.executeInitially) {
|
|
703
|
+
if (options.executeInitially && (!hold || hold.isHolder())) {
|
|
697
704
|
context.execute({ args });
|
|
698
705
|
}
|
|
699
706
|
intervalId = window.setInterval(() => {
|
|
@@ -1329,6 +1336,7 @@ const resetExecuteState = (options) => {
|
|
|
1329
1336
|
const { executeState, executeOptions: opts } = options;
|
|
1330
1337
|
const { state } = opts;
|
|
1331
1338
|
opts.deps.client.repository.unbind(executeState.previousKey(), opts.deps.destroyRef);
|
|
1339
|
+
executeState.previousKey.set(null);
|
|
1332
1340
|
state.args.set(null);
|
|
1333
1341
|
state.error.set(null);
|
|
1334
1342
|
state.latestHttpEvent.set(null);
|
|
@@ -1513,21 +1521,24 @@ const buildQueryString = (params, config) => {
|
|
|
1513
1521
|
}
|
|
1514
1522
|
else if (Array.isArray(value)) {
|
|
1515
1523
|
let currentFilteredIndex = 0;
|
|
1524
|
+
let didAddAnyValue = false;
|
|
1516
1525
|
for (const arrayValue of value) {
|
|
1517
1526
|
const nestedKey = writeArrayIndexes ? `${key}[${currentFilteredIndex}]` : `${key}[]`;
|
|
1518
1527
|
const didAddValue = processValue(nestedKey, arrayValue);
|
|
1519
1528
|
if (didAddValue) {
|
|
1520
1529
|
currentFilteredIndex++;
|
|
1530
|
+
didAddAnyValue = true;
|
|
1521
1531
|
}
|
|
1522
1532
|
}
|
|
1523
|
-
return
|
|
1533
|
+
return didAddAnyValue;
|
|
1524
1534
|
}
|
|
1525
1535
|
else if (typeof value === 'object' && value !== null) {
|
|
1536
|
+
let didAddAnyValue = false;
|
|
1526
1537
|
for (const [objKey, val] of Object.entries(value)) {
|
|
1527
1538
|
const nestedKey = objectNotation === 'dot' ? `${key}.${objKey}` : `${key}[${objKey}]`;
|
|
1528
|
-
processValue(nestedKey, val);
|
|
1539
|
+
didAddAnyValue = processValue(nestedKey, val) || didAddAnyValue;
|
|
1529
1540
|
}
|
|
1530
|
-
return
|
|
1541
|
+
return didAddAnyValue;
|
|
1531
1542
|
}
|
|
1532
1543
|
else {
|
|
1533
1544
|
if (ignoredValues.includes(value)) {
|
|
@@ -1593,7 +1604,7 @@ const decryptBearer = (token) => {
|
|
|
1593
1604
|
return JSON.parse(jsonPayload);
|
|
1594
1605
|
}
|
|
1595
1606
|
catch (error) {
|
|
1596
|
-
console.error(
|
|
1607
|
+
console.error('Invalid bearer token', error);
|
|
1597
1608
|
return null;
|
|
1598
1609
|
}
|
|
1599
1610
|
};
|
|
@@ -1605,26 +1616,18 @@ const extractExpiresInSeconds = (headers) => {
|
|
|
1605
1616
|
// In seconds
|
|
1606
1617
|
let expiresIn = null;
|
|
1607
1618
|
let maxAge = null;
|
|
1608
|
-
if (cacheControl
|
|
1619
|
+
if (cacheControl && /(?:^|,)\s*no-(?:cache|store)(?:\s|,|$)/i.test(cacheControl)) {
|
|
1609
1620
|
return null;
|
|
1610
1621
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
maxAge = parseInt(m);
|
|
1615
|
-
}
|
|
1622
|
+
const maxAgeMatch = cacheControl?.match(/(?:^|,)\s*(?:s-maxage|max-age)=(\d+)/i);
|
|
1623
|
+
if (maxAgeMatch?.[1]) {
|
|
1624
|
+
maxAge = parseInt(maxAgeMatch[1]);
|
|
1616
1625
|
}
|
|
1617
|
-
|
|
1618
|
-
const m = cacheControl.split('s-maxage=')[1];
|
|
1619
|
-
if (m) {
|
|
1620
|
-
maxAge = parseInt(m);
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
if (maxAge && age) {
|
|
1626
|
+
if (maxAge !== null && age) {
|
|
1624
1627
|
const ageSeconds = parseInt(age);
|
|
1625
|
-
expiresIn = maxAge - ageSeconds;
|
|
1628
|
+
expiresIn = Math.max(maxAge - ageSeconds, 0);
|
|
1626
1629
|
}
|
|
1627
|
-
else if (maxAge) {
|
|
1630
|
+
else if (maxAge !== null) {
|
|
1628
1631
|
expiresIn = maxAge / 2; // We assume the response is half way to its expiration
|
|
1629
1632
|
}
|
|
1630
1633
|
else if (expires) {
|
|
@@ -1647,21 +1650,27 @@ const shouldCacheQuery = (method) => {
|
|
|
1647
1650
|
return method === 'GET' || method === 'OPTIONS' || method === 'HEAD';
|
|
1648
1651
|
};
|
|
1649
1652
|
const buildQueryCacheKey = (route, args) => {
|
|
1653
|
+
const headers = typeof args?.headers === 'function' ? args.headers() : args?.headers;
|
|
1654
|
+
const serializedHeaders = headers
|
|
1655
|
+
?.keys()
|
|
1656
|
+
.filter((name) => name.toLowerCase() !== 'authorization')
|
|
1657
|
+
.sort()
|
|
1658
|
+
.map((name) => [name.toLowerCase(), headers.getAll(name)]);
|
|
1650
1659
|
// We need to hash the body in case it's a gql query and the query get's transported in the body
|
|
1651
1660
|
const body = JSON.stringify(args?.body || {})
|
|
1652
1661
|
// replace all curly braces with empty string
|
|
1653
1662
|
.replace(/{|}/g, '')
|
|
1654
1663
|
// replace new lines and whitespaces with empty string
|
|
1655
1664
|
.replace(/\s/g, '');
|
|
1656
|
-
const
|
|
1665
|
+
const headerInput = serializedHeaders?.length ? `_${JSON.stringify(serializedHeaders)}` : '';
|
|
1666
|
+
const seed = `${route}_${body}${headerInput}`;
|
|
1657
1667
|
let hash = 0;
|
|
1668
|
+
let secondaryHash = 5381;
|
|
1658
1669
|
for (const char of seed) {
|
|
1659
1670
|
hash = (Math.imul(31, hash) + char.charCodeAt(0)) << 0;
|
|
1671
|
+
secondaryHash = Math.imul(33, secondaryHash) ^ char.charCodeAt(0);
|
|
1660
1672
|
}
|
|
1661
|
-
|
|
1662
|
-
// 2147483647 = equivalent of Integer.MAX_VALUE.
|
|
1663
|
-
hash += 2147483647 + 1;
|
|
1664
|
-
return hash.toString();
|
|
1673
|
+
return `${(hash >>> 0).toString().padStart(10, '0')}${(secondaryHash >>> 0).toString().padStart(10, '0')}`;
|
|
1665
1674
|
};
|
|
1666
1675
|
|
|
1667
1676
|
const parsers = [];
|
|
@@ -1725,7 +1734,7 @@ const queryErrorMessages = (error) => {
|
|
|
1725
1734
|
* {@link queryErrorMessages}, for a toast or a form-field hint.
|
|
1726
1735
|
*/
|
|
1727
1736
|
const queryErrorMessage = (error) => queryErrorMessages(error)[0] ?? null;
|
|
1728
|
-
const createQueryErrorResponse = (error) => {
|
|
1737
|
+
const createQueryErrorResponse = (error, retry) => {
|
|
1729
1738
|
let err = error instanceof HttpErrorResponse ? error : null;
|
|
1730
1739
|
if (!err) {
|
|
1731
1740
|
err = new HttpErrorResponse({
|
|
@@ -1734,7 +1743,8 @@ const createQueryErrorResponse = (error) => {
|
|
|
1734
1743
|
statusText: 'Unknown Error',
|
|
1735
1744
|
});
|
|
1736
1745
|
}
|
|
1737
|
-
const
|
|
1746
|
+
const retryOptions = { retryCount: retry?.retryCount ?? 0, error: err };
|
|
1747
|
+
const retryState = typeof retry?.retryFn === 'function' ? retry.retryFn(retryOptions) : runDefaultQueryRetry(retryOptions);
|
|
1738
1748
|
const detail = err.error;
|
|
1739
1749
|
const errorList = [];
|
|
1740
1750
|
const parsed = runQueryErrorParsers(detail, err);
|
|
@@ -2010,7 +2020,10 @@ const createHttpRequest = (options) => {
|
|
|
2010
2020
|
event$.next(event);
|
|
2011
2021
|
};
|
|
2012
2022
|
const updateErrorState = (errorResponse) => {
|
|
2013
|
-
const errorRes = createQueryErrorResponse(errorResponse
|
|
2023
|
+
const errorRes = createQueryErrorResponse(errorResponse, {
|
|
2024
|
+
retryCount: attempts(),
|
|
2025
|
+
retryFn: options.retryFn,
|
|
2026
|
+
});
|
|
2014
2027
|
error.set(errorRes);
|
|
2015
2028
|
loading.set(null);
|
|
2016
2029
|
lastDurationMs.set(Date.now() - lastExecuteTime());
|
|
@@ -2047,7 +2060,7 @@ const createHttpRequest = (options) => {
|
|
|
2047
2060
|
if (isMeasurable && elapsedTimeSinceLastExecute > SPEED_BUFFER_TIME_IN_MS) {
|
|
2048
2061
|
const bytesPerSecond = (loadedAmount / elapsedTimeSinceLastEvent) * 1000;
|
|
2049
2062
|
progress.speed = bytesPerSecond;
|
|
2050
|
-
progress.remainingTime = Math.round((event.total - event.loaded) / bytesPerSecond) * 1000;
|
|
2063
|
+
progress.remainingTime = Math.round(((event.total - event.loaded) / bytesPerSecond) * 1000);
|
|
2051
2064
|
}
|
|
2052
2065
|
if (isMeasurable) {
|
|
2053
2066
|
lastLoadEventTime.set(currentTime);
|
|
@@ -2357,7 +2370,8 @@ const createPagedQueryStack = (options) => {
|
|
|
2357
2370
|
return { queries: oldQueries, lastQuery };
|
|
2358
2371
|
}
|
|
2359
2372
|
else if (dir === 'previous') {
|
|
2360
|
-
|
|
2373
|
+
const queries = [newQuery, ...oldQueries];
|
|
2374
|
+
return { queries, lastQuery: queries[queries.length - 1] ?? null };
|
|
2361
2375
|
}
|
|
2362
2376
|
else {
|
|
2363
2377
|
return { queries: [...oldQueries, newQuery], lastQuery: newQuery };
|
|
@@ -2414,10 +2428,14 @@ const createPagedQueryStack = (options) => {
|
|
|
2414
2428
|
}
|
|
2415
2429
|
return null;
|
|
2416
2430
|
}
|
|
2417
|
-
|
|
2418
|
-
loadedMinPage.set(page);
|
|
2431
|
+
const args = options.args(page, allResponses);
|
|
2419
2432
|
pageDirection.set('previous');
|
|
2420
|
-
|
|
2433
|
+
const query = stack.subtle.runWithArgs(args);
|
|
2434
|
+
if (query) {
|
|
2435
|
+
currentPageArgs.set(args);
|
|
2436
|
+
loadedMinPage.set(page);
|
|
2437
|
+
}
|
|
2438
|
+
return query;
|
|
2421
2439
|
};
|
|
2422
2440
|
const fetchNextPage = () => {
|
|
2423
2441
|
const page = loadedMaxPage() + 1;
|
|
@@ -2438,10 +2456,14 @@ const createPagedQueryStack = (options) => {
|
|
|
2438
2456
|
}
|
|
2439
2457
|
return null;
|
|
2440
2458
|
}
|
|
2441
|
-
|
|
2442
|
-
loadedMaxPage.set(page);
|
|
2459
|
+
const args = options.args(page, allResponses);
|
|
2443
2460
|
pageDirection.set('next');
|
|
2444
|
-
|
|
2461
|
+
const query = stack.subtle.runWithArgs(args);
|
|
2462
|
+
if (query) {
|
|
2463
|
+
currentPageArgs.set(args);
|
|
2464
|
+
loadedMaxPage.set(page);
|
|
2465
|
+
}
|
|
2466
|
+
return query;
|
|
2445
2467
|
};
|
|
2446
2468
|
const canFetchNewPage = (pageToLoad) => {
|
|
2447
2469
|
const currentMaxPagination = maxPagination();
|
|
@@ -3157,7 +3179,11 @@ const createQueryBatch = (options) => {
|
|
|
3157
3179
|
completedBeforeRun.set(completed());
|
|
3158
3180
|
runStartedAt.set(Date.now());
|
|
3159
3181
|
lastSettleAt.set(null);
|
|
3160
|
-
return from(entries).pipe(mergeMap((entry) => runEntry(entry), concurrency), toArray(), map(() => settleRun(entries)))
|
|
3182
|
+
return from(entries).pipe(mergeMap((entry) => runEntry(entry), concurrency), toArray(), map(() => settleRun(entries)), finalize(() => {
|
|
3183
|
+
if (status() === 'running')
|
|
3184
|
+
status.set('idle');
|
|
3185
|
+
running.set(false);
|
|
3186
|
+
}));
|
|
3161
3187
|
});
|
|
3162
3188
|
const run = (items) => runEntries(() => {
|
|
3163
3189
|
settled = new Array(items.length);
|
|
@@ -4065,6 +4091,10 @@ const createQueryRepository = (config) => {
|
|
|
4065
4091
|
const destroyEntry = (key, cacheEntry, cause) => {
|
|
4066
4092
|
const { method, url } = cacheEntry.request;
|
|
4067
4093
|
clearTimeout(cacheEntry.evictTimer);
|
|
4094
|
+
for (const unregister of cacheEntry.consumers.values()) {
|
|
4095
|
+
unregister();
|
|
4096
|
+
}
|
|
4097
|
+
cacheEntry.consumers.clear();
|
|
4068
4098
|
cacheEntry.request.destroy();
|
|
4069
4099
|
cacheEntry.eventSubscription?.unsubscribe();
|
|
4070
4100
|
cache.delete(key);
|
|
@@ -4088,6 +4118,7 @@ const createQueryRepository = (config) => {
|
|
|
4088
4118
|
}
|
|
4089
4119
|
};
|
|
4090
4120
|
const retain = (key, cacheEntry) => {
|
|
4121
|
+
clearTimeout(cacheEntry.evictTimer);
|
|
4091
4122
|
cacheEntry.unusedSince = Date.now();
|
|
4092
4123
|
cacheEntry.evictTimer = setTimeout(() => evict(key, 'expired'), cacheEntry.keepUnusedFor);
|
|
4093
4124
|
enforceUnusedEntryLimit();
|
|
@@ -4098,6 +4129,10 @@ const createQueryRepository = (config) => {
|
|
|
4098
4129
|
const cacheEntry = cache.get(key);
|
|
4099
4130
|
if (!cacheEntry)
|
|
4100
4131
|
return false;
|
|
4132
|
+
const unregister = cacheEntry.consumers.get(consumerDestroyRef);
|
|
4133
|
+
if (!unregister)
|
|
4134
|
+
return false;
|
|
4135
|
+
unregister();
|
|
4101
4136
|
cacheEntry.consumers.delete(consumerDestroyRef);
|
|
4102
4137
|
if (cacheEntry.consumers.size === 0) {
|
|
4103
4138
|
// Only data is worth keeping around: an entry that never produced a response has nothing to
|
|
@@ -4172,32 +4207,48 @@ const createQueryRepository = (config) => {
|
|
|
4172
4207
|
};
|
|
4173
4208
|
const bind = (options) => {
|
|
4174
4209
|
const { key, consumerDestroyRef, request, isSecure, isCached, isRefreshable, isMultiTabSyncEnabled, isPersistEnabled, keepUnusedFor, } = options;
|
|
4175
|
-
const destroyListener = consumerDestroyRef.onDestroy(() => unbind(key, consumerDestroyRef));
|
|
4176
4210
|
const cacheEntry = cache.get(key);
|
|
4177
4211
|
if (cacheEntry && isCached) {
|
|
4178
|
-
cacheEntry.
|
|
4212
|
+
cacheEntry.isSecure ||= isSecure;
|
|
4213
|
+
cacheEntry.isRefreshable ||= isRefreshable;
|
|
4214
|
+
cacheEntry.isMultiTabSyncEnabled &&= isMultiTabSyncEnabled;
|
|
4215
|
+
cacheEntry.isPersistEnabled &&= isPersistEnabled;
|
|
4216
|
+
cacheEntry.keepUnusedFor = Math.min(cacheEntry.keepUnusedFor, keepUnusedFor);
|
|
4217
|
+
if (!cacheEntry.consumers.has(consumerDestroyRef)) {
|
|
4218
|
+
cacheEntry.consumers.set(consumerDestroyRef, consumerDestroyRef.onDestroy(() => unbind(key, consumerDestroyRef)));
|
|
4219
|
+
}
|
|
4179
4220
|
}
|
|
4180
4221
|
else {
|
|
4181
4222
|
const consumers = new Map([]);
|
|
4182
|
-
consumers.set(consumerDestroyRef,
|
|
4223
|
+
consumers.set(consumerDestroyRef, consumerDestroyRef.onDestroy(() => unbind(key, consumerDestroyRef)));
|
|
4183
4224
|
// Drive repository events off the request's discrete, terminal event stream rather than
|
|
4184
4225
|
// recombining the `error` + `response` signals via combineLatest (which could observe stale
|
|
4185
4226
|
// pairings). Each settle emits exactly one terminal event.
|
|
4186
4227
|
const eventSubscription = request.events$.subscribe((event) => {
|
|
4228
|
+
const currentEntry = cache.get(key);
|
|
4229
|
+
const currentIsSecure = currentEntry?.isSecure ?? isSecure;
|
|
4230
|
+
const currentIsMultiTabSyncEnabled = currentEntry?.isMultiTabSyncEnabled ?? isMultiTabSyncEnabled;
|
|
4231
|
+
const currentIsPersistEnabled = currentEntry?.isPersistEnabled ?? isPersistEnabled;
|
|
4187
4232
|
if (event.type === 'error') {
|
|
4188
4233
|
if (event.error.raw instanceof HttpErrorResponse) {
|
|
4189
|
-
eventsSubject.next({
|
|
4234
|
+
eventsSubject.next({
|
|
4235
|
+
type: 'request-error',
|
|
4236
|
+
error: event.error.raw,
|
|
4237
|
+
key,
|
|
4238
|
+
isSecure: currentIsSecure,
|
|
4239
|
+
request,
|
|
4240
|
+
});
|
|
4190
4241
|
}
|
|
4191
4242
|
}
|
|
4192
4243
|
else if (event.type === HttpEventType.Response) {
|
|
4193
4244
|
eventsSubject.next({
|
|
4194
4245
|
type: 'request-success',
|
|
4195
4246
|
key,
|
|
4196
|
-
isSecure,
|
|
4247
|
+
isSecure: currentIsSecure,
|
|
4197
4248
|
request,
|
|
4198
4249
|
isCached,
|
|
4199
|
-
isMultiTabSyncEnabled,
|
|
4200
|
-
isPersistEnabled,
|
|
4250
|
+
isMultiTabSyncEnabled: currentIsMultiTabSyncEnabled,
|
|
4251
|
+
isPersistEnabled: currentIsPersistEnabled,
|
|
4201
4252
|
});
|
|
4202
4253
|
}
|
|
4203
4254
|
});
|
|
@@ -4440,7 +4491,7 @@ const createSecureExecuteFactory = (options) => {
|
|
|
4440
4491
|
.pipe(filter(() => {
|
|
4441
4492
|
const currentError = options.state.error();
|
|
4442
4493
|
return currentError?.code === 401 && options.authProvider.accessToken() !== lastRequestedWithToken;
|
|
4443
|
-
}), take(1), tap(() => exec(execArgsWithDefaults)))
|
|
4494
|
+
}), take(1), tap(() => exec(execArgsWithDefaults)), takeUntilDestroyed(options.deps.destroyRef))
|
|
4444
4495
|
.subscribe();
|
|
4445
4496
|
// `setTokens()` seeds an auth session from outside the query registry (an SSO/OIDC callback, a
|
|
4446
4497
|
// native shell) - no query ever runs for `latestExecutedQuery` to report, so a successful token
|
|
@@ -4606,30 +4657,35 @@ const buildSequence = (steps, state, devtoolsHandle) => {
|
|
|
4606
4657
|
const stepArgs = [];
|
|
4607
4658
|
const responses = [];
|
|
4608
4659
|
let previousResponse = undefined;
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4660
|
+
try {
|
|
4661
|
+
for (const [i, step] of steps.entries()) {
|
|
4662
|
+
state.currentStep.set(i + 1);
|
|
4663
|
+
const { args } = step.produceArgs(previousResponse, responses);
|
|
4664
|
+
stepArgs.push(args);
|
|
4665
|
+
state.stepArgs.set([...stepArgs]);
|
|
4666
|
+
const snapshot = await executeUntilSettled(step.query, { args });
|
|
4667
|
+
snapshots.push(snapshot);
|
|
4668
|
+
state.snapshots.set([...snapshots]);
|
|
4669
|
+
const error = snapshot.error();
|
|
4670
|
+
if (error) {
|
|
4671
|
+
state.status.set('error');
|
|
4672
|
+
state.error.set(error);
|
|
4673
|
+
state.failedAt.set(i);
|
|
4674
|
+
return { ok: false, failedAt: i, error, snapshots };
|
|
4675
|
+
}
|
|
4676
|
+
const response = snapshot.response();
|
|
4677
|
+
responses.push(response);
|
|
4678
|
+
state.responses.set([...responses]);
|
|
4679
|
+
previousResponse = response;
|
|
4624
4680
|
}
|
|
4625
|
-
|
|
4626
|
-
responses
|
|
4627
|
-
|
|
4628
|
-
|
|
4681
|
+
state.status.set('success');
|
|
4682
|
+
return { ok: true, responses: responses, snapshots };
|
|
4683
|
+
}
|
|
4684
|
+
finally {
|
|
4685
|
+
if (state.status() === 'running')
|
|
4686
|
+
state.status.set('idle');
|
|
4687
|
+
state.running.set(false);
|
|
4629
4688
|
}
|
|
4630
|
-
state.status.set('success');
|
|
4631
|
-
state.running.set(false);
|
|
4632
|
-
return { ok: true, responses: responses, snapshots };
|
|
4633
4689
|
};
|
|
4634
4690
|
const completed = computed(() => state.snapshots().length, /* @ts-ignore */
|
|
4635
4691
|
...(ngDevMode ? [{ debugName: "completed" }] : /* istanbul ignore next */ []));
|
|
@@ -5002,39 +5058,10 @@ const setupBearerQueryRegistry = (builders, context) => {
|
|
|
5002
5058
|
...(ngDevMode ? [{ debugName: "querySnapshot" }] : /* istanbul ignore next */ []));
|
|
5003
5059
|
querySnapshots.set(builder.key, querySnapshot);
|
|
5004
5060
|
const extractTokens = builder.config.extractTokens ?? defaultExtractTokens;
|
|
5005
|
-
// A 2xx whose body carries no usable tokens is a failed execution, not a successful one - the
|
|
5006
|
-
// state effect below reads this so it cannot report `success` for an attempt that left the tab
|
|
5007
|
-
// unauthenticated.
|
|
5008
|
-
const extractionError = signal(null, /* @ts-ignore */
|
|
5009
|
-
...(ngDevMode ? [{ debugName: "extractionError" }] : /* istanbul ignore next */ []));
|
|
5010
5061
|
const currentExecution = signal(null, /* @ts-ignore */
|
|
5011
5062
|
...(ngDevMode ? [{ debugName: "currentExecution" }] : /* istanbul ignore next */ []));
|
|
5012
5063
|
currentExecutions.push(currentExecution);
|
|
5013
5064
|
const isSuperseded = (execution) => execution.id !== null && execution.id !== latestExecutionId;
|
|
5014
|
-
// Runs before the state effect below, which reads the extraction error this one writes. Angular
|
|
5015
|
-
// runs effects in creation order, so the two must stay in this order.
|
|
5016
|
-
effect(() => {
|
|
5017
|
-
const execution = currentExecution();
|
|
5018
|
-
if (!execution)
|
|
5019
|
-
return;
|
|
5020
|
-
const { snapshot } = execution;
|
|
5021
|
-
const response = snapshot.response();
|
|
5022
|
-
const loading = snapshot.loading();
|
|
5023
|
-
const error = snapshot.error();
|
|
5024
|
-
if (response && !loading && !error && !isSuperseded(execution)) {
|
|
5025
|
-
try {
|
|
5026
|
-
const tokens = extractTokens(response);
|
|
5027
|
-
extractionError.set(null);
|
|
5028
|
-
applyTokens(tokens.accessToken, tokens.refreshToken);
|
|
5029
|
-
}
|
|
5030
|
-
catch (extractError) {
|
|
5031
|
-
extractionError.set(createQueryErrorResponse(extractError));
|
|
5032
|
-
if (isDevMode()) {
|
|
5033
|
-
console.error(`Failed to extract tokens from ${builder.key} response:`, extractError);
|
|
5034
|
-
}
|
|
5035
|
-
}
|
|
5036
|
-
}
|
|
5037
|
-
});
|
|
5038
5065
|
effect(() => {
|
|
5039
5066
|
const execution = currentExecution();
|
|
5040
5067
|
if (!execution)
|
|
@@ -5049,13 +5076,17 @@ const setupBearerQueryRegistry = (builders, context) => {
|
|
|
5049
5076
|
executionState.set({ type, state: 'error', error });
|
|
5050
5077
|
}
|
|
5051
5078
|
else if (response) {
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
}
|
|
5056
|
-
else {
|
|
5079
|
+
try {
|
|
5080
|
+
const tokens = extractTokens(response);
|
|
5081
|
+
applyTokens(tokens.accessToken, tokens.refreshToken);
|
|
5057
5082
|
executionState.set({ type, state: 'success', response });
|
|
5058
5083
|
}
|
|
5084
|
+
catch (extractError) {
|
|
5085
|
+
executionState.set({ type, state: 'error', error: createQueryErrorResponse(extractError) });
|
|
5086
|
+
if (isDevMode()) {
|
|
5087
|
+
console.error(`Failed to extract tokens from ${builder.key} response:`, extractError);
|
|
5088
|
+
}
|
|
5089
|
+
}
|
|
5059
5090
|
}
|
|
5060
5091
|
// Keyed on `isAlive` rather than on the branches above: a cancelled restore produces neither a
|
|
5061
5092
|
// response nor an error, and would otherwise leave `sessionStatus` at `restoring` forever.
|
|
@@ -5069,7 +5100,6 @@ const setupBearerQueryRegistry = (builders, context) => {
|
|
|
5069
5100
|
let query = null;
|
|
5070
5101
|
const execute = (args, options) => {
|
|
5071
5102
|
query ??= builder.config.queryCreator({ onlyManualExecution: true, injector });
|
|
5072
|
-
extractionError.set(null);
|
|
5073
5103
|
query.execute({ args, options });
|
|
5074
5104
|
const snapshot = query.createSnapshot();
|
|
5075
5105
|
const stateType = deriveExecutionStateType(builder, options?.triggeredBy);
|
|
@@ -5098,7 +5128,10 @@ const setupBearerQueryRegistry = (builders, context) => {
|
|
|
5098
5128
|
return !!current && current.id !== null && current.snapshot.isAlive();
|
|
5099
5129
|
}), /* @ts-ignore */
|
|
5100
5130
|
...(ngDevMode ? [{ debugName: "hasTokenIssuingExecutionInFlight" }] : /* istanbul ignore next */ []));
|
|
5101
|
-
|
|
5131
|
+
const invalidateTokenIssuingExecutions = () => {
|
|
5132
|
+
latestExecutionId++;
|
|
5133
|
+
};
|
|
5134
|
+
return { queries, querySnapshots, hasTokenIssuingExecutionInFlight, invalidateTokenIssuingExecutions };
|
|
5102
5135
|
};
|
|
5103
5136
|
const setupFeatures = (featureBuilders, context) => {
|
|
5104
5137
|
const features = {};
|
|
@@ -5219,7 +5252,7 @@ const createBearerAuthProviderImpl = (config) => {
|
|
|
5219
5252
|
applyTokens(access, refresh);
|
|
5220
5253
|
executionState.set({ type: 'tokenSeed', state: 'success' });
|
|
5221
5254
|
};
|
|
5222
|
-
const { queries, hasTokenIssuingExecutionInFlight } = setupBearerQueryRegistry(config.queries, {
|
|
5255
|
+
const { queries, hasTokenIssuingExecutionInFlight, invalidateTokenIssuingExecutions } = setupBearerQueryRegistry(config.queries, {
|
|
5223
5256
|
injector,
|
|
5224
5257
|
latestExecutedQuery,
|
|
5225
5258
|
latestNonInternalQuery,
|
|
@@ -5229,6 +5262,7 @@ const createBearerAuthProviderImpl = (config) => {
|
|
|
5229
5262
|
isAuthenticated,
|
|
5230
5263
|
});
|
|
5231
5264
|
const logout = (cause = 'user') => {
|
|
5265
|
+
invalidateTokenIssuingExecutions();
|
|
5232
5266
|
accessToken.set(null);
|
|
5233
5267
|
refreshToken.set(null);
|
|
5234
5268
|
queryClient.repository.unbindAllSecure();
|
|
@@ -5264,12 +5298,14 @@ const createBearerAuthProviderImpl = (config) => {
|
|
|
5264
5298
|
logout,
|
|
5265
5299
|
afterTokenRefresh$,
|
|
5266
5300
|
queries: queries,
|
|
5301
|
+
executionState: executionState.asReadonly(),
|
|
5267
5302
|
hasTokenIssuingExecutionInFlight,
|
|
5268
5303
|
};
|
|
5269
5304
|
for (const builder of config.queries) {
|
|
5270
5305
|
builder.setup?.(querySetupContext);
|
|
5271
5306
|
}
|
|
5272
5307
|
const featureSetupContext = {
|
|
5308
|
+
name: config.name,
|
|
5273
5309
|
refreshToken,
|
|
5274
5310
|
accessToken,
|
|
5275
5311
|
bearerData,
|
|
@@ -5283,6 +5319,7 @@ const createBearerAuthProviderImpl = (config) => {
|
|
|
5283
5319
|
activityCoordination: isLeader.activityCoordination,
|
|
5284
5320
|
afterTokenRefresh$,
|
|
5285
5321
|
queries: queries,
|
|
5322
|
+
latestExecutedQuery: latestExecutedQuery.asReadonly(),
|
|
5286
5323
|
executionState,
|
|
5287
5324
|
sessionStatus: sessionStatus.asReadonly(),
|
|
5288
5325
|
sessionEndCause: sessionEndCause.asReadonly(),
|
|
@@ -5396,7 +5433,11 @@ const withAuthenticationQuery = (key, config, setup) => ({
|
|
|
5396
5433
|
...config,
|
|
5397
5434
|
// A spent credential entry must not sit out a retention window: the request body holds the
|
|
5398
5435
|
// username and password, the response the tokens it was exchanged for.
|
|
5399
|
-
queryCreator: config.queryCreator.clone({
|
|
5436
|
+
queryCreator: config.queryCreator.clone({
|
|
5437
|
+
...(config.retryFn ? { retryFn: config.retryFn } : {}),
|
|
5438
|
+
keepUnusedFor: 0,
|
|
5439
|
+
subtle: { useQueryRepositoryCache: true },
|
|
5440
|
+
}),
|
|
5400
5441
|
},
|
|
5401
5442
|
setup,
|
|
5402
5443
|
});
|
|
@@ -5593,7 +5634,9 @@ const withRefreshQuery = (key, config) => {
|
|
|
5593
5634
|
};
|
|
5594
5635
|
const calculateRefreshBuffer = (tokenLifetimeMs) => {
|
|
5595
5636
|
if (typeof config.refreshStrategy === 'number') {
|
|
5596
|
-
return config.refreshStrategy
|
|
5637
|
+
return config.refreshStrategy >= 0 && config.refreshStrategy <= 1
|
|
5638
|
+
? tokenLifetimeMs * (1 - config.refreshStrategy)
|
|
5639
|
+
: config.refreshStrategy;
|
|
5597
5640
|
}
|
|
5598
5641
|
const percentage = config.refreshStrategy?.percentage ?? 0.75;
|
|
5599
5642
|
const minBufferMs = config.refreshStrategy?.minBufferMs ?? 60000; // 1 minute
|
|
@@ -5659,7 +5702,7 @@ const withRefreshQuery = (key, config) => {
|
|
|
5659
5702
|
* Without the re-arm a single declined attempt strands the session on a token nothing renews until
|
|
5660
5703
|
* a request fails with a 401 - by which time the refresh token may be gone too.
|
|
5661
5704
|
*/
|
|
5662
|
-
const scheduledRefresh = (dueInMs, attemptsLeft) => (dueInMs <= 0 ? of(0) : timer(dueInMs)).pipe(concatMap(() => {
|
|
5705
|
+
const scheduledRefresh = (dueInMs, attemptsLeft) => (dueInMs <= 0 ? of(0) : timer(Math.min(dueInMs, maxTimerDelayMs))).pipe(concatMap(() => {
|
|
5663
5706
|
const attempt = executeRefresh('scheduled');
|
|
5664
5707
|
const retryInMs = retryScheduledIn(attempt);
|
|
5665
5708
|
if (retryInMs === null)
|
|
@@ -5711,13 +5754,10 @@ const withRefreshQuery = (key, config) => {
|
|
|
5711
5754
|
logout();
|
|
5712
5755
|
});
|
|
5713
5756
|
effect(() => {
|
|
5714
|
-
const
|
|
5715
|
-
if (
|
|
5757
|
+
const state = context.executionState();
|
|
5758
|
+
if (state?.type !== 'tokenRefresh' || state.state !== 'error')
|
|
5716
5759
|
return;
|
|
5717
|
-
|
|
5718
|
-
if (!error)
|
|
5719
|
-
return;
|
|
5720
|
-
onRefreshFailure({ error, logout: () => context.logout('expired') });
|
|
5760
|
+
onRefreshFailure({ error: state.error, logout: () => context.logout('expired') });
|
|
5721
5761
|
});
|
|
5722
5762
|
// Auto-retry on 401: Listen to repository events and trigger refresh on 401 errors
|
|
5723
5763
|
const autoRetryOn401 = config.autoRetryOn401 ?? true;
|
|
@@ -5750,7 +5790,7 @@ const withRefreshQuery = (key, config) => {
|
|
|
5750
5790
|
config: {
|
|
5751
5791
|
...config,
|
|
5752
5792
|
queryCreator: config.queryCreator.clone({
|
|
5753
|
-
retryFn: refreshRetryFn,
|
|
5793
|
+
retryFn: config.retryFn ?? refreshRetryFn,
|
|
5754
5794
|
keepUnusedFor: 0,
|
|
5755
5795
|
subtle: { useQueryRepositoryCache: true },
|
|
5756
5796
|
}),
|
|
@@ -6185,31 +6225,38 @@ const setupLeaderElection = (options) => {
|
|
|
6185
6225
|
|
|
6186
6226
|
const ENCRYPTION_KEY_STORAGE = '__eth_ek';
|
|
6187
6227
|
const generateEncryptionKey = () => {
|
|
6188
|
-
const navigatorInfo = typeof navigator !== 'undefined'
|
|
6189
|
-
|
|
6190
|
-
: 'server';
|
|
6228
|
+
const navigatorInfo = typeof navigator !== 'undefined' ? `${navigator.userAgent}${navigator.language}` : 'server';
|
|
6229
|
+
const screenInfo = typeof screen !== 'undefined' ? `${screen.width}${screen.height}${screen.colorDepth}` : 'no-screen';
|
|
6191
6230
|
const random = Math.random().toString(36).substring(2, 15);
|
|
6192
|
-
return btoa(`${navigatorInfo}${random}`);
|
|
6231
|
+
return btoa(`${navigatorInfo}${screenInfo}${random}`);
|
|
6193
6232
|
};
|
|
6194
6233
|
let cachedKey = null;
|
|
6195
6234
|
const getEncryptionKey = () => {
|
|
6196
6235
|
if (cachedKey)
|
|
6197
6236
|
return cachedKey;
|
|
6198
6237
|
if (typeof localStorage !== 'undefined') {
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6238
|
+
try {
|
|
6239
|
+
const stored = localStorage.getItem(ENCRYPTION_KEY_STORAGE);
|
|
6240
|
+
if (stored) {
|
|
6241
|
+
cachedKey = stored;
|
|
6242
|
+
return stored;
|
|
6243
|
+
}
|
|
6244
|
+
}
|
|
6245
|
+
catch {
|
|
6246
|
+
cachedKey = null;
|
|
6203
6247
|
}
|
|
6204
|
-
const newKey = generateEncryptionKey();
|
|
6205
|
-
localStorage.setItem(ENCRYPTION_KEY_STORAGE, newKey);
|
|
6206
|
-
cachedKey = newKey;
|
|
6207
|
-
return newKey;
|
|
6208
6248
|
}
|
|
6209
|
-
|
|
6210
|
-
|
|
6249
|
+
const newKey = generateEncryptionKey();
|
|
6250
|
+
cachedKey = newKey;
|
|
6251
|
+
if (typeof localStorage !== 'undefined') {
|
|
6252
|
+
try {
|
|
6253
|
+
localStorage.setItem(ENCRYPTION_KEY_STORAGE, newKey);
|
|
6254
|
+
}
|
|
6255
|
+
catch {
|
|
6256
|
+
return newKey;
|
|
6257
|
+
}
|
|
6211
6258
|
}
|
|
6212
|
-
return
|
|
6259
|
+
return newKey;
|
|
6213
6260
|
};
|
|
6214
6261
|
const xorCipher = (text, key) => {
|
|
6215
6262
|
let result = '';
|
|
@@ -6227,7 +6274,7 @@ const encryptToken = (token) => {
|
|
|
6227
6274
|
return btoa(encrypted);
|
|
6228
6275
|
}
|
|
6229
6276
|
catch {
|
|
6230
|
-
return
|
|
6277
|
+
return '';
|
|
6231
6278
|
}
|
|
6232
6279
|
};
|
|
6233
6280
|
const decryptToken = (encryptedToken) => {
|
|
@@ -6331,6 +6378,8 @@ const setupMultiTabSync = (config, context) => {
|
|
|
6331
6378
|
return;
|
|
6332
6379
|
}
|
|
6333
6380
|
if (message.type === 'logout' && syncLogout) {
|
|
6381
|
+
if (!context.accessToken() && !context.refreshToken())
|
|
6382
|
+
return;
|
|
6334
6383
|
lastSyncedState = LOGGED_OUT;
|
|
6335
6384
|
hadTokens = false;
|
|
6336
6385
|
context.logout(incomingCause(message.cause));
|
|
@@ -6343,7 +6392,10 @@ const setupMultiTabSync = (config, context) => {
|
|
|
6343
6392
|
if (!access || !refresh)
|
|
6344
6393
|
return;
|
|
6345
6394
|
const isNewSession = !context.accessToken();
|
|
6346
|
-
|
|
6395
|
+
const incomingState = tokenState(access, refresh);
|
|
6396
|
+
if (incomingState === lastSyncedState)
|
|
6397
|
+
return;
|
|
6398
|
+
lastSyncedState = incomingState;
|
|
6347
6399
|
hadTokens = true;
|
|
6348
6400
|
if (isNewSession) {
|
|
6349
6401
|
context.setTokens(access, refresh);
|
|
@@ -6481,25 +6533,30 @@ const SINGLE_TAB = /* @__PURE__ */ (() => {
|
|
|
6481
6533
|
* // provider.features.multiTabSync.isLeader()
|
|
6482
6534
|
*/
|
|
6483
6535
|
const withBearerAuthMultiTabSync = (config = {}) => {
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
label: '
|
|
6495
|
-
value: config.
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6536
|
+
const pendingSetups = [];
|
|
6537
|
+
const setup = (context) => {
|
|
6538
|
+
const state = pendingSetups.shift() ?? {
|
|
6539
|
+
instance: SINGLE_TAB,
|
|
6540
|
+
channelName: config.channelName ?? defaultSyncChannelName(context.name),
|
|
6541
|
+
};
|
|
6542
|
+
return {
|
|
6543
|
+
type: BearerAuthFeatureType.MULTI_TAB_SYNC,
|
|
6544
|
+
instance: state.instance,
|
|
6545
|
+
devtools: () => [
|
|
6546
|
+
{ label: 'channel', value: state.channelName },
|
|
6547
|
+
{ label: 'tokens', value: config.syncTokens === false ? 'tab local' : 'synced' },
|
|
6548
|
+
{ label: 'logout', value: config.syncLogout === false ? 'tab local' : 'synced' },
|
|
6549
|
+
{
|
|
6550
|
+
label: 'leader election',
|
|
6551
|
+
value: config.leaderElection === false ? 'every tab refreshes' : 'one tab refreshes',
|
|
6552
|
+
},
|
|
6553
|
+
],
|
|
6554
|
+
};
|
|
6555
|
+
};
|
|
6499
6556
|
// The elected leader gates the auth queries' automatic refresh, which is wired up before the
|
|
6500
6557
|
// regular feature setup runs - so this half has to happen earlier than `setup`.
|
|
6501
6558
|
const earlySetup = (context) => {
|
|
6502
|
-
channelName = config.channelName ?? defaultSyncChannelName(context.name);
|
|
6559
|
+
const channelName = config.channelName ?? defaultSyncChannelName(context.name);
|
|
6503
6560
|
// Filled in below once the election exists. Until then this tab answers as its own leader, which
|
|
6504
6561
|
// is what it is: the sync is set up first because the auth queries read `isLeader` while being
|
|
6505
6562
|
// wired, and a `state-request` cannot arrive before this function returns anyway.
|
|
@@ -6515,15 +6572,17 @@ const withBearerAuthMultiTabSync = (config = {}) => {
|
|
|
6515
6572
|
logout: context.logout,
|
|
6516
6573
|
});
|
|
6517
6574
|
if (config.leaderElection === false) {
|
|
6575
|
+
pendingSetups.push({ instance: SINGLE_TAB, channelName });
|
|
6518
6576
|
return { sessionAdoption: sync.sessionAdoption, activityCoordination: sync.activityCoordination };
|
|
6519
6577
|
}
|
|
6520
6578
|
const election = setupLeaderElection({ name: context.name });
|
|
6521
6579
|
isLeaderRef = () => election.isLeader();
|
|
6522
|
-
instance = {
|
|
6580
|
+
const instance = {
|
|
6523
6581
|
isLeader: election.isLeader,
|
|
6524
6582
|
instanceCount: election.instanceCount,
|
|
6525
6583
|
leadership: election.isSupported ? 'election' : 'unsupported',
|
|
6526
6584
|
};
|
|
6585
|
+
pendingSetups.push({ instance, channelName });
|
|
6527
6586
|
return {
|
|
6528
6587
|
isLeader: () => election.isLeader(),
|
|
6529
6588
|
leaderElection: instance,
|
|
@@ -6578,7 +6637,7 @@ const createPersistentAuthFeature = (config, context) => {
|
|
|
6578
6637
|
};
|
|
6579
6638
|
const rememberMeSignal = signal(initializeRememberMe(), /* @ts-ignore */
|
|
6580
6639
|
...(ngDevMode ? [{ debugName: "rememberMeSignal" }] : /* istanbul ignore next */ []));
|
|
6581
|
-
const cookieDomain = () => config.cookie?.domain ??
|
|
6640
|
+
const cookieDomain = () => config.cookie?.domain ?? null;
|
|
6582
6641
|
const cookiePath = () => config.cookie?.path ?? '/';
|
|
6583
6642
|
const removeCookie = () => deleteCookie(cookieName, cookiePath(), cookieDomain());
|
|
6584
6643
|
effect(() => {
|
|
@@ -6593,14 +6652,15 @@ const createPersistentAuthFeature = (config, context) => {
|
|
|
6593
6652
|
const expiresInDays = rememberMe ? (config.cookie?.expiresInDays ?? 30) : null;
|
|
6594
6653
|
setCookie(cookieName, encryptToken(token), expiresInDays, cookieDomain(), cookiePath(), config.cookie?.sameSite ?? 'lax');
|
|
6595
6654
|
});
|
|
6655
|
+
effect(() => {
|
|
6656
|
+
const endCause = context.sessionEndCause();
|
|
6657
|
+
if (endCause)
|
|
6658
|
+
removeCookie();
|
|
6659
|
+
});
|
|
6596
6660
|
effect(() => {
|
|
6597
6661
|
const state = executionState();
|
|
6598
6662
|
if (!state)
|
|
6599
6663
|
return;
|
|
6600
|
-
if (state.type === 'logout') {
|
|
6601
|
-
removeCookie();
|
|
6602
|
-
return;
|
|
6603
|
-
}
|
|
6604
6664
|
// A token the server itself rejected is worth nothing on the next visit; anything else (offline, a
|
|
6605
6665
|
// 500, an aborted startup) leaves it in place so a reload can try again.
|
|
6606
6666
|
const wasRejected = state.state === 'error' &&
|
|
@@ -6674,14 +6734,15 @@ const withTokenExpirationWarning = (config = {}) => {
|
|
|
6674
6734
|
return new Date(exp * 1000);
|
|
6675
6735
|
}, /* @ts-ignore */
|
|
6676
6736
|
...(ngDevMode ? [{ debugName: "expiresAt" }] : /* istanbul ignore next */ []));
|
|
6677
|
-
const expiresIn$ =
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6737
|
+
const expiresIn$ = toObservable(context.bearerData).pipe(switchMap((bearerData) => bearerData
|
|
6738
|
+
? timer(0, checkInterval).pipe(map(() => {
|
|
6739
|
+
const expiry = expiresAt();
|
|
6740
|
+
if (!expiry)
|
|
6741
|
+
return null;
|
|
6742
|
+
const msUntilExpiry = expiry.getTime() - Date.now();
|
|
6743
|
+
return msUntilExpiry > 0 ? msUntilExpiry : null;
|
|
6744
|
+
}))
|
|
6745
|
+
: of(null)));
|
|
6685
6746
|
const isExpiringSoon$ = expiresIn$.pipe(map((msUntilExpiry) => {
|
|
6686
6747
|
if (msUntilExpiry === null)
|
|
6687
6748
|
return false;
|
|
@@ -6811,8 +6872,9 @@ const createTrackingFeature = (context, config) => {
|
|
|
6811
6872
|
});
|
|
6812
6873
|
}
|
|
6813
6874
|
};
|
|
6875
|
+
const pendingForwardedMessages = [];
|
|
6814
6876
|
const forwardingChannel = context.leaderElection && typeof BroadcastChannel !== 'undefined'
|
|
6815
|
-
? new BroadcastChannel(
|
|
6877
|
+
? new BroadcastChannel(`ethlete-auth-tracking:${context.name}`)
|
|
6816
6878
|
: null;
|
|
6817
6879
|
if (forwardingChannel) {
|
|
6818
6880
|
forwardingChannel.onmessage = (messageEvent) => {
|
|
@@ -6822,21 +6884,44 @@ const createTrackingFeature = (context, config) => {
|
|
|
6822
6884
|
};
|
|
6823
6885
|
context.destroyRef.onDestroy(() => forwardingChannel.close());
|
|
6824
6886
|
}
|
|
6887
|
+
const forward = (message) => {
|
|
6888
|
+
if (!forwardingChannel)
|
|
6889
|
+
return false;
|
|
6890
|
+
try {
|
|
6891
|
+
forwardingChannel.postMessage(message);
|
|
6892
|
+
return true;
|
|
6893
|
+
}
|
|
6894
|
+
catch (error) {
|
|
6895
|
+
if (isDevMode()) {
|
|
6896
|
+
console.warn(`[@ethlete/query] Could not forward the "${message.event}" tracking event to the leader tab.`, error);
|
|
6897
|
+
}
|
|
6898
|
+
return false;
|
|
6899
|
+
}
|
|
6900
|
+
};
|
|
6901
|
+
if (context.leaderElection) {
|
|
6902
|
+
effect(() => {
|
|
6903
|
+
const isLeader = context.leaderElection?.isLeader() ?? false;
|
|
6904
|
+
const instanceCount = context.leaderElection?.instanceCount() ?? 1;
|
|
6905
|
+
if (!pendingForwardedMessages.length || (!isLeader && instanceCount <= 1))
|
|
6906
|
+
return;
|
|
6907
|
+
untracked(() => {
|
|
6908
|
+
const pending = pendingForwardedMessages.splice(0);
|
|
6909
|
+
for (const message of pending) {
|
|
6910
|
+
if (isLeader || !forward(message))
|
|
6911
|
+
fireHandlers(message.event, message.data);
|
|
6912
|
+
}
|
|
6913
|
+
});
|
|
6914
|
+
}, { injector: context.injector });
|
|
6915
|
+
}
|
|
6825
6916
|
const emit = (event, data) => {
|
|
6826
6917
|
if (forwardingChannel && !context.isLeader()) {
|
|
6827
|
-
|
|
6828
|
-
|
|
6918
|
+
const message = { event, data };
|
|
6919
|
+
if ((context.leaderElection?.instanceCount() ?? 1) <= 1) {
|
|
6920
|
+
pendingForwardedMessages.push(message);
|
|
6829
6921
|
return;
|
|
6830
6922
|
}
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
// signals, and the structured clone algorithm throws on functions. Firing the handlers here
|
|
6834
|
-
// is the lesser evil - the event reaches a handler in the wrong tab rather than taking the
|
|
6835
|
-
// effect it was emitted from down with it.
|
|
6836
|
-
if (isDevMode()) {
|
|
6837
|
-
console.warn(`[@ethlete/query] Could not forward the "${event}" tracking event to the leader tab.`, error);
|
|
6838
|
-
}
|
|
6839
|
-
}
|
|
6923
|
+
if (forward(message))
|
|
6924
|
+
return;
|
|
6840
6925
|
}
|
|
6841
6926
|
fireHandlers(event, data);
|
|
6842
6927
|
};
|
|
@@ -6857,17 +6942,18 @@ const createTrackingFeature = (context, config) => {
|
|
|
6857
6942
|
const error = snapshot.error();
|
|
6858
6943
|
const response = snapshot.response();
|
|
6859
6944
|
const prevState = trackedQueries.get(key);
|
|
6945
|
+
if (prevState?.snapshot !== snapshot) {
|
|
6946
|
+
trackedQueries.set(key, { snapshot, lastResult: null });
|
|
6947
|
+
emit(`${key}Execute`, { queryKey: key, args: snapshot.args() });
|
|
6948
|
+
}
|
|
6860
6949
|
if (response && !loading && !error && prevState?.lastResult !== 'success') {
|
|
6861
|
-
trackedQueries.set(key, {
|
|
6950
|
+
trackedQueries.set(key, { snapshot, lastResult: 'success' });
|
|
6862
6951
|
emit(`${key}Success`, { snapshot });
|
|
6863
6952
|
}
|
|
6864
6953
|
if (error && !loading && prevState?.lastResult !== 'error') {
|
|
6865
|
-
trackedQueries.set(key, {
|
|
6954
|
+
trackedQueries.set(key, { snapshot, lastResult: 'error' });
|
|
6866
6955
|
emit(`${key}Failure`, { error });
|
|
6867
6956
|
}
|
|
6868
|
-
if (loading) {
|
|
6869
|
-
trackedQueries.set(key, { loading: true, lastResult: null });
|
|
6870
|
-
}
|
|
6871
6957
|
});
|
|
6872
6958
|
});
|
|
6873
6959
|
let hadTokens = false;
|
|
@@ -6880,10 +6966,14 @@ const createTrackingFeature = (context, config) => {
|
|
|
6880
6966
|
}
|
|
6881
6967
|
hadTokens = hasTokens;
|
|
6882
6968
|
});
|
|
6883
|
-
|
|
6969
|
+
let lastTrackedRefreshState = null;
|
|
6970
|
+
effect(() => {
|
|
6971
|
+
const state = context.executionState();
|
|
6972
|
+
if (state === lastTrackedRefreshState || state?.type !== 'tokenRefresh' || state.state !== 'success')
|
|
6973
|
+
return;
|
|
6974
|
+
lastTrackedRefreshState = state;
|
|
6884
6975
|
emit('tokenRefreshSuccess', {
|
|
6885
|
-
|
|
6886
|
-
snapshot: undefined,
|
|
6976
|
+
automatic: !!untracked(context.latestExecutedQuery)?.snapshot.triggeredBy(),
|
|
6887
6977
|
});
|
|
6888
6978
|
});
|
|
6889
6979
|
if (config?.on) {
|
|
@@ -8178,12 +8268,13 @@ const armQueryDevtoolsOverrideTransfer = (recorder, ops) => {
|
|
|
8178
8268
|
|
|
8179
8269
|
// Generated from package.json by tools/scripts/generate-version.js - do not edit.
|
|
8180
8270
|
/** The version of `@ethlete/query` this build was cut from. */
|
|
8181
|
-
const QUERY_VERSION = '6.0.0-next.
|
|
8271
|
+
const QUERY_VERSION = '6.0.0-next.40';
|
|
8182
8272
|
|
|
8183
8273
|
/** How deep a schema is expanded before a nested branch is given up on. */
|
|
8184
8274
|
const MAX_DEPTH = 12;
|
|
8185
8275
|
/** How many elements are generated for an array, whatever its `minItems` says. */
|
|
8186
8276
|
const MAX_ITEMS = 3;
|
|
8277
|
+
const MAX_STRING_LENGTH = 10_000;
|
|
8187
8278
|
/**
|
|
8188
8279
|
* How many array elements are generated on their own rather than copied from the first. Nested arrays
|
|
8189
8280
|
* multiply, so without a ceiling a body of arrays-in-arrays costs `MAX_ITEMS ^ MAX_DEPTH` walks.
|
|
@@ -8376,12 +8467,12 @@ const finiteNumber = (value) => (typeof value === 'number' && Number.isFinite(va
|
|
|
8376
8467
|
const pickStressStringPreset = () => STRESS_STRING_PRESETS[Math.floor(Math.random() * STRESS_STRING_PRESETS.length)];
|
|
8377
8468
|
/** Keeps a generated string inside `minLength`/`maxLength`, since a seed is exported as a real body. */
|
|
8378
8469
|
const fitLength = (value, schema) => {
|
|
8379
|
-
const min = finiteNumber(schema['minLength']);
|
|
8380
|
-
const max = finiteNumber(schema['maxLength']);
|
|
8470
|
+
const min = Math.min(finiteNumber(schema['minLength']) ?? 0, MAX_STRING_LENGTH);
|
|
8471
|
+
const max = Math.min(finiteNumber(schema['maxLength']) ?? MAX_STRING_LENGTH, MAX_STRING_LENGTH);
|
|
8381
8472
|
let out = value;
|
|
8382
|
-
while (
|
|
8473
|
+
while (out.length < min)
|
|
8383
8474
|
out += value || 'x';
|
|
8384
|
-
return
|
|
8475
|
+
return out.slice(0, max);
|
|
8385
8476
|
};
|
|
8386
8477
|
/**
|
|
8387
8478
|
* The value of a string field. A declared format wins in every style - a `date-time` full of lorem is
|
|
@@ -9212,6 +9303,7 @@ const snapshotQueryDevtoolsHandle = (handle) => {
|
|
|
9212
9303
|
attempts: read(() => frozen(live.subtle.attempts()), frozen(1)),
|
|
9213
9304
|
lastDurationMs: read(() => frozen(live.subtle.lastDurationMs()), frozen(null)),
|
|
9214
9305
|
resolveHeaders: read(() => frozen(live.subtle.resolveHeaders()), frozen(undefined)),
|
|
9306
|
+
lastSentHeaders: read(() => frozen(live.subtle.lastSentHeaders()), frozen(undefined)),
|
|
9215
9307
|
lastPersistedResponseAt: read(() => frozen(live.subtle.lastPersistedResponseAt()), frozen(null)),
|
|
9216
9308
|
lastExternalResponseAt: read(() => frozen(live.subtle.lastExternalResponseAt()), frozen(null)),
|
|
9217
9309
|
},
|
|
@@ -9438,6 +9530,7 @@ const clearQueryDevtoolsTombstones = (ids) => {
|
|
|
9438
9530
|
const doomed = ids ? new Set(ids) : null;
|
|
9439
9531
|
entries.update((list) => list.filter((e) => !e.destroyedAt || (doomed ? !doomed.has(e.id) : false)));
|
|
9440
9532
|
};
|
|
9533
|
+
let queryDevtoolsInitialized = false;
|
|
9441
9534
|
/**
|
|
9442
9535
|
* Enables the `@ethlete/query` devtools. Add this to your application providers (e.g. in
|
|
9443
9536
|
* `bootstrapApplication`) to make query clients, queries, stacks, sequences and auth providers
|
|
@@ -9454,6 +9547,9 @@ const clearQueryDevtoolsTombstones = (ids) => {
|
|
|
9454
9547
|
* ```
|
|
9455
9548
|
*/
|
|
9456
9549
|
const provideQueryDevtools = (options) => {
|
|
9550
|
+
if (queryDevtoolsInitialized)
|
|
9551
|
+
return makeEnvironmentProviders([]);
|
|
9552
|
+
queryDevtoolsInitialized = true;
|
|
9457
9553
|
// First: the stored settings say where the override store lives and whether the panel has raised the
|
|
9458
9554
|
// retention this app asked for, and both are read by the calls below.
|
|
9459
9555
|
initQueryDevtoolsSettings();
|
|
@@ -9478,7 +9574,7 @@ const provideQueryDevtools = (options) => {
|
|
|
9478
9574
|
return makeEnvironmentProviders([]);
|
|
9479
9575
|
};
|
|
9480
9576
|
|
|
9481
|
-
const getOpName =
|
|
9577
|
+
const getOpName = /\b(?:query|mutation)\s+([\w-]+)(?:\s*\([^)]*\))?\s*\{/;
|
|
9482
9578
|
const transformGql = (str) => {
|
|
9483
9579
|
const normalizedStr = Array.isArray(str) ? str.join('') : str;
|
|
9484
9580
|
const name = getOpName.exec(normalizedStr);
|
|
@@ -9488,7 +9584,7 @@ const transformGql = (str) => {
|
|
|
9488
9584
|
data['variables'] = JSON.stringify(variables);
|
|
9489
9585
|
}
|
|
9490
9586
|
if (name && name.length) {
|
|
9491
|
-
const operationName = name[
|
|
9587
|
+
const operationName = name[1];
|
|
9492
9588
|
if (operationName) {
|
|
9493
9589
|
data['operationName'] = operationName;
|
|
9494
9590
|
}
|
|
@@ -9519,7 +9615,7 @@ const createGqlExecuteFn = (executeOptions) => {
|
|
|
9519
9615
|
if (args?.queryParams && executeOptions.creatorInternals.transport === 'GET') {
|
|
9520
9616
|
gqlParams = { ...gqlParams, ...args.queryParams };
|
|
9521
9617
|
}
|
|
9522
|
-
const computedArgs = args ?? {};
|
|
9618
|
+
const computedArgs = { ...(args ?? {}) };
|
|
9523
9619
|
if (executeOptions.creatorInternals.transport === 'GET') {
|
|
9524
9620
|
computedArgs.queryParams = gqlParams;
|
|
9525
9621
|
}
|
|
@@ -9607,7 +9703,7 @@ const createSecureGqlExecuteFn = (executeOptions) => {
|
|
|
9607
9703
|
...executeOptions,
|
|
9608
9704
|
creatorInternals: {
|
|
9609
9705
|
client: executeOptions.creatorInternals.client,
|
|
9610
|
-
method: executeOptions.creatorInternals.
|
|
9706
|
+
method: executeOptions.creatorInternals.transport,
|
|
9611
9707
|
route: (executeOptions.creator?.route ?? ''),
|
|
9612
9708
|
},
|
|
9613
9709
|
};
|
|
@@ -9639,7 +9735,7 @@ const createSecureGqlQueryCreator = (options, internals) => createBaseQueryCreat
|
|
|
9639
9735
|
if (rawResponse && typeof rawResponse === 'object' && 'data' in rawResponse) {
|
|
9640
9736
|
return rawResponse.data;
|
|
9641
9737
|
}
|
|
9642
|
-
|
|
9738
|
+
throw gqlDataPropertyMissingInResponse();
|
|
9643
9739
|
}),
|
|
9644
9740
|
},
|
|
9645
9741
|
internals,
|
|
@@ -10285,7 +10381,7 @@ function queryStateSignal(source, options) {
|
|
|
10285
10381
|
const { cacheResponse } = options ?? {};
|
|
10286
10382
|
const roSignal = toSignal(toObservable(source).pipe(switchMap((q) => extractQuery(q)?.state$ ?? of(null)), switchMap((state) => {
|
|
10287
10383
|
if (cacheResponse) {
|
|
10288
|
-
return of(state).pipe(filterQueryStates([
|
|
10384
|
+
return of(state).pipe(filterQueryStates([QueryStateType.Success, QueryStateType.Failure]));
|
|
10289
10385
|
}
|
|
10290
10386
|
return of(state);
|
|
10291
10387
|
})), {
|
|
@@ -10468,6 +10564,8 @@ class QueryStore {
|
|
|
10468
10564
|
this._queryCreated$.next(query);
|
|
10469
10565
|
}
|
|
10470
10566
|
initSmartQueryHandling() {
|
|
10567
|
+
if (typeof window === 'undefined')
|
|
10568
|
+
return;
|
|
10471
10569
|
const windowBlur$ = fromEvent(window, 'blur');
|
|
10472
10570
|
const windowFocus$ = fromEvent(window, 'focus');
|
|
10473
10571
|
windowBlur$.subscribe(() => {
|
|
@@ -10522,6 +10620,8 @@ class QueryStore {
|
|
|
10522
10620
|
console.log(stateAsJson);
|
|
10523
10621
|
}
|
|
10524
10622
|
initGarbageCollector() {
|
|
10623
|
+
if (typeof window === 'undefined')
|
|
10624
|
+
return;
|
|
10525
10625
|
if (this.garbageCollector !== null) {
|
|
10526
10626
|
return;
|
|
10527
10627
|
}
|
|
@@ -10531,6 +10631,8 @@ class QueryStore {
|
|
|
10531
10631
|
}, 15000);
|
|
10532
10632
|
}
|
|
10533
10633
|
stopGarbageCollector() {
|
|
10634
|
+
if (typeof window === 'undefined')
|
|
10635
|
+
return;
|
|
10534
10636
|
if (this.garbageCollector !== null) {
|
|
10535
10637
|
window.clearInterval(this.garbageCollector);
|
|
10536
10638
|
this.garbageCollector = null;
|
|
@@ -10632,7 +10734,10 @@ class V2QueryClient {
|
|
|
10632
10734
|
return this._authProvider$.getValue() ?? this._clientConfig.parent?._authProvider$.getValue() ?? null;
|
|
10633
10735
|
}
|
|
10634
10736
|
get authProvider$() {
|
|
10635
|
-
|
|
10737
|
+
const parent = this._clientConfig.parent?._authProvider$;
|
|
10738
|
+
return parent
|
|
10739
|
+
? combineLatest([this._authProvider$, parent]).pipe(map(([ownProvider, parentProvider]) => ownProvider ?? parentProvider))
|
|
10740
|
+
: this._authProvider$.asObservable();
|
|
10636
10741
|
}
|
|
10637
10742
|
}
|
|
10638
10743
|
|
|
@@ -10662,6 +10767,17 @@ const v2BuildQueryCacheKey = (route, args) => {
|
|
|
10662
10767
|
return hash.toString();
|
|
10663
10768
|
};
|
|
10664
10769
|
|
|
10770
|
+
/**
|
|
10771
|
+
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
10772
|
+
*/
|
|
10773
|
+
const QueryStateType = {
|
|
10774
|
+
Prepared: 'PREPARED',
|
|
10775
|
+
Loading: 'LOADING',
|
|
10776
|
+
Success: 'SUCCESS',
|
|
10777
|
+
Failure: 'FAILURE',
|
|
10778
|
+
Cancelled: 'CANCELLED',
|
|
10779
|
+
};
|
|
10780
|
+
|
|
10665
10781
|
let fallbackInjector = null;
|
|
10666
10782
|
/**
|
|
10667
10783
|
* The stashed root injector, or `null` when the fallback was never provided (or was provided on the
|
|
@@ -10726,7 +10842,7 @@ const transformExecStateToQueryState = (execState) => {
|
|
|
10726
10842
|
case 'loading': {
|
|
10727
10843
|
const loading = {
|
|
10728
10844
|
meta,
|
|
10729
|
-
type:
|
|
10845
|
+
type: QueryStateType.Loading,
|
|
10730
10846
|
...(execState.loading.progress
|
|
10731
10847
|
? {
|
|
10732
10848
|
progress: {
|
|
@@ -10744,7 +10860,7 @@ const transformExecStateToQueryState = (execState) => {
|
|
|
10744
10860
|
headers: {},
|
|
10745
10861
|
meta,
|
|
10746
10862
|
response: execState.response,
|
|
10747
|
-
type:
|
|
10863
|
+
type: QueryStateType.Success,
|
|
10748
10864
|
};
|
|
10749
10865
|
return success;
|
|
10750
10866
|
}
|
|
@@ -10758,14 +10874,14 @@ const transformExecStateToQueryState = (execState) => {
|
|
|
10758
10874
|
url: execState.error.raw.url || '',
|
|
10759
10875
|
},
|
|
10760
10876
|
meta,
|
|
10761
|
-
type:
|
|
10877
|
+
type: QueryStateType.Failure,
|
|
10762
10878
|
};
|
|
10763
10879
|
return error;
|
|
10764
10880
|
}
|
|
10765
10881
|
default: {
|
|
10766
10882
|
const prepared = {
|
|
10767
10883
|
meta,
|
|
10768
|
-
type:
|
|
10884
|
+
type: QueryStateType.Prepared,
|
|
10769
10885
|
};
|
|
10770
10886
|
return prepared;
|
|
10771
10887
|
}
|
|
@@ -11354,23 +11470,23 @@ const resetPageOnError = (config) => (source) => {
|
|
|
11354
11470
|
/**
|
|
11355
11471
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
11356
11472
|
*/
|
|
11357
|
-
const isQueryStateLoading = (state) => state?.type ===
|
|
11473
|
+
const isQueryStateLoading = (state) => state?.type === QueryStateType.Loading;
|
|
11358
11474
|
/**
|
|
11359
11475
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
11360
11476
|
*/
|
|
11361
|
-
const isQueryStateSuccess = (state) => state?.type ===
|
|
11477
|
+
const isQueryStateSuccess = (state) => state?.type === QueryStateType.Success;
|
|
11362
11478
|
/**
|
|
11363
11479
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
11364
11480
|
*/
|
|
11365
|
-
const isQueryStateFailure = (state) => state?.type ===
|
|
11481
|
+
const isQueryStateFailure = (state) => state?.type === QueryStateType.Failure;
|
|
11366
11482
|
/**
|
|
11367
11483
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
11368
11484
|
*/
|
|
11369
|
-
const isQueryStateCancelled = (state) => state?.type ===
|
|
11485
|
+
const isQueryStateCancelled = (state) => state?.type === QueryStateType.Cancelled;
|
|
11370
11486
|
/**
|
|
11371
11487
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
11372
11488
|
*/
|
|
11373
|
-
const isQueryStatePrepared = (state) => state?.type ===
|
|
11489
|
+
const isQueryStatePrepared = (state) => state?.type === QueryStateType.Prepared;
|
|
11374
11490
|
/**
|
|
11375
11491
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
11376
11492
|
*/
|
|
@@ -11522,17 +11638,12 @@ const computeQueryBody = (config) => {
|
|
|
11522
11638
|
*/
|
|
11523
11639
|
const computeQueryAuthHeader = (config) => {
|
|
11524
11640
|
let authHeader = null;
|
|
11525
|
-
if (config.config.secure) {
|
|
11641
|
+
if (config.config.secure === true) {
|
|
11526
11642
|
const header = config.client.authProvider?.header;
|
|
11527
11643
|
if (header) {
|
|
11528
11644
|
authHeader = header;
|
|
11529
11645
|
}
|
|
11530
11646
|
}
|
|
11531
|
-
else if (config.client.authProvider?.header) {
|
|
11532
|
-
if (config.config.secure === undefined || config.config.secure) {
|
|
11533
|
-
authHeader = config.client.authProvider.header;
|
|
11534
|
-
}
|
|
11535
|
-
}
|
|
11536
11647
|
return authHeader;
|
|
11537
11648
|
};
|
|
11538
11649
|
/**
|
|
@@ -11637,7 +11748,7 @@ class V2Query {
|
|
|
11637
11748
|
this._isPollingPaused = false;
|
|
11638
11749
|
this.memoizedState$ = null;
|
|
11639
11750
|
this._state$ = new BehaviorSubject({
|
|
11640
|
-
type:
|
|
11751
|
+
type: QueryStateType.Prepared,
|
|
11641
11752
|
meta: { id: this.currentLocalId, triggeredVia: 'program' },
|
|
11642
11753
|
});
|
|
11643
11754
|
}
|
|
@@ -11732,7 +11843,7 @@ class V2Query {
|
|
|
11732
11843
|
return this;
|
|
11733
11844
|
}
|
|
11734
11845
|
}
|
|
11735
|
-
this.updateState({ type:
|
|
11846
|
+
this.updateState({ type: QueryStateType.Loading, meta });
|
|
11736
11847
|
if (this._isInMockMode) {
|
|
11737
11848
|
this.mockRequest({}, meta, options);
|
|
11738
11849
|
}
|
|
@@ -11789,7 +11900,7 @@ class V2Query {
|
|
|
11789
11900
|
}
|
|
11790
11901
|
this.onAbort$.next();
|
|
11791
11902
|
this.updateState({
|
|
11792
|
-
type:
|
|
11903
|
+
type: QueryStateType.Cancelled,
|
|
11793
11904
|
meta: { id: this.rawState.meta.id, triggeredVia: this.rawState.meta.triggeredVia },
|
|
11794
11905
|
});
|
|
11795
11906
|
return this;
|
|
@@ -11883,7 +11994,7 @@ class V2Query {
|
|
|
11883
11994
|
const { type, retryDelay, retryNumber } = requestEvent;
|
|
11884
11995
|
const newMeta = { ...meta, isWaitingForRetry: type === 'delay-retry', retryDelay, retryNumber };
|
|
11885
11996
|
this.updateState({
|
|
11886
|
-
type:
|
|
11997
|
+
type: QueryStateType.Loading,
|
|
11887
11998
|
meta: newMeta,
|
|
11888
11999
|
});
|
|
11889
12000
|
break;
|
|
@@ -11891,7 +12002,7 @@ class V2Query {
|
|
|
11891
12002
|
case 'upload-progress':
|
|
11892
12003
|
case 'download-progress': {
|
|
11893
12004
|
this.updateState({
|
|
11894
|
-
type:
|
|
12005
|
+
type: QueryStateType.Loading,
|
|
11895
12006
|
progress: requestEvent.progress,
|
|
11896
12007
|
partialText: 'partialText' in requestEvent ? requestEvent.partialText : undefined,
|
|
11897
12008
|
meta,
|
|
@@ -11914,7 +12025,7 @@ class V2Query {
|
|
|
11914
12025
|
});
|
|
11915
12026
|
}
|
|
11916
12027
|
this.updateState({
|
|
11917
|
-
type:
|
|
12028
|
+
type: QueryStateType.Success,
|
|
11918
12029
|
response: responseData,
|
|
11919
12030
|
headers: headers,
|
|
11920
12031
|
meta: { ...meta, expiresAt: expiresInTimestamp },
|
|
@@ -11923,7 +12034,7 @@ class V2Query {
|
|
|
11923
12034
|
}
|
|
11924
12035
|
case 'failure': {
|
|
11925
12036
|
const { error } = requestEvent;
|
|
11926
|
-
const failure = () => this.updateState({ type:
|
|
12037
|
+
const failure = () => this.updateState({ type: QueryStateType.Failure, error, meta });
|
|
11927
12038
|
const bearerAuthProvider = this.getBearerAuthProvider();
|
|
11928
12039
|
if (!bearerAuthProvider ||
|
|
11929
12040
|
options?._isUnauthorizedRetry ||
|
|
@@ -11935,13 +12046,15 @@ class V2Query {
|
|
|
11935
12046
|
if (!query)
|
|
11936
12047
|
return failure();
|
|
11937
12048
|
query.state$
|
|
11938
|
-
.pipe(takeUntilResponse(), takeUntil(this.onAbort$), tap((state) => isQueryStateSuccess(state)
|
|
12049
|
+
.pipe(takeUntilResponse(), takeUntil(this.onAbort$), tap((state) => isQueryStateSuccess(state)
|
|
12050
|
+
? this.execute({ ...options, _isUnauthorizedRetry: true, cancelPrevious: true })
|
|
12051
|
+
: failure()))
|
|
11939
12052
|
.subscribe();
|
|
11940
12053
|
break;
|
|
11941
12054
|
}
|
|
11942
12055
|
case 'cancel': {
|
|
11943
12056
|
this.updateState({
|
|
11944
|
-
type:
|
|
12057
|
+
type: QueryStateType.Cancelled,
|
|
11945
12058
|
meta,
|
|
11946
12059
|
});
|
|
11947
12060
|
break;
|
|
@@ -12022,6 +12135,17 @@ class V2Query {
|
|
|
12022
12135
|
}
|
|
12023
12136
|
}
|
|
12024
12137
|
|
|
12138
|
+
/**
|
|
12139
|
+
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
12140
|
+
*/
|
|
12141
|
+
const AuthBearerRefreshStrategy = {
|
|
12142
|
+
/**
|
|
12143
|
+
* Automatically refresh the token 5 minutes before expiration.
|
|
12144
|
+
* The time can be configured with the `refreshBuffer` property.
|
|
12145
|
+
*/
|
|
12146
|
+
BeforeExpiration: 'beforeExpiration',
|
|
12147
|
+
};
|
|
12148
|
+
|
|
12025
12149
|
/**
|
|
12026
12150
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
12027
12151
|
*/
|
|
@@ -12070,7 +12194,8 @@ class V2BearerAuthProvider {
|
|
|
12070
12194
|
}
|
|
12071
12195
|
}
|
|
12072
12196
|
get header() {
|
|
12073
|
-
|
|
12197
|
+
const token = this._tokens$.getValue().token;
|
|
12198
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
12074
12199
|
}
|
|
12075
12200
|
get tokens$() {
|
|
12076
12201
|
return this._tokens$.asObservable();
|
|
@@ -12090,8 +12215,9 @@ class V2BearerAuthProvider {
|
|
|
12090
12215
|
this._config.refreshConfig.refreshOnUnauthorizedResponse));
|
|
12091
12216
|
}
|
|
12092
12217
|
cleanUp() {
|
|
12093
|
-
this.destroy$.next(
|
|
12094
|
-
this.destroy$.
|
|
12218
|
+
this.destroy$.next();
|
|
12219
|
+
this.destroy$.complete();
|
|
12220
|
+
this.destroy$ = new Subject();
|
|
12095
12221
|
this._currentRefreshQuery$.next(null);
|
|
12096
12222
|
if (this._config.refreshConfig?.cookieName) {
|
|
12097
12223
|
this.deleteCookie();
|
|
@@ -12173,12 +12299,12 @@ class V2BearerAuthProvider {
|
|
|
12173
12299
|
setCookie() {
|
|
12174
12300
|
if (!this._config.refreshConfig?.cookieName || !this.tokens.refreshToken)
|
|
12175
12301
|
return;
|
|
12176
|
-
setCookie(this._config.refreshConfig.cookieName, this.tokens.refreshToken, this._config.refreshConfig.cookieExpiresInDays, this._config.refreshConfig.cookieDomain, this._config.refreshConfig.cookiePath, this._config.refreshConfig.cookieSameSite);
|
|
12302
|
+
setCookie(this._config.refreshConfig.cookieName, this.tokens.refreshToken, this._config.refreshConfig.cookieExpiresInDays, this._config.refreshConfig.cookieDomain ?? null, this._config.refreshConfig.cookiePath, this._config.refreshConfig.cookieSameSite);
|
|
12177
12303
|
}
|
|
12178
12304
|
deleteCookie() {
|
|
12179
12305
|
if (!this._config.refreshConfig?.cookieName)
|
|
12180
12306
|
return;
|
|
12181
|
-
deleteCookie(this._config.refreshConfig.cookieName, this._config.refreshConfig.cookiePath, this._config.refreshConfig.cookieDomain);
|
|
12307
|
+
deleteCookie(this._config.refreshConfig.cookieName, this._config.refreshConfig.cookiePath, this._config.refreshConfig.cookieDomain ?? null);
|
|
12182
12308
|
}
|
|
12183
12309
|
prepareForRefresh() {
|
|
12184
12310
|
if (!this.tokens.token || !this._config.refreshConfig) {
|
|
@@ -12192,13 +12318,12 @@ class V2BearerAuthProvider {
|
|
|
12192
12318
|
const expiresIn = bearer[expiresInPropertyName];
|
|
12193
12319
|
const fiveMinutes = 5 * 60 * 1000;
|
|
12194
12320
|
const refreshBuffer = this._config.refreshConfig.refreshBuffer ?? fiveMinutes;
|
|
12195
|
-
if (expiresIn
|
|
12196
|
-
|
|
12197
|
-
}
|
|
12321
|
+
if (typeof expiresIn !== 'number')
|
|
12322
|
+
return;
|
|
12198
12323
|
const remainingTime = new Date(expiresIn * 1000).getTime() - refreshBuffer - new Date().getTime();
|
|
12199
|
-
const strategy = this._config.refreshConfig.strategy ??
|
|
12324
|
+
const strategy = this._config.refreshConfig.strategy ?? AuthBearerRefreshStrategy.BeforeExpiration;
|
|
12200
12325
|
switch (strategy) {
|
|
12201
|
-
case
|
|
12326
|
+
case AuthBearerRefreshStrategy.BeforeExpiration:
|
|
12202
12327
|
timer(remainingTime)
|
|
12203
12328
|
.pipe(takeUntil(this.destroy$))
|
|
12204
12329
|
.subscribe(() => this._refreshQuery());
|
|
@@ -12336,6 +12461,7 @@ class InfinityQuery {
|
|
|
12336
12461
|
}
|
|
12337
12462
|
reset(newConfig) {
|
|
12338
12463
|
this._config = { ...this._config, ...(newConfig ?? {}) };
|
|
12464
|
+
this.destroyQueries();
|
|
12339
12465
|
this._currentPage$.next(null);
|
|
12340
12466
|
this._currentCalculatedPage$.next(null);
|
|
12341
12467
|
this._totalPages$.next(null);
|
|
@@ -12343,6 +12469,18 @@ class InfinityQuery {
|
|
|
12343
12469
|
this.queries$.next([]);
|
|
12344
12470
|
this.nextPage();
|
|
12345
12471
|
}
|
|
12472
|
+
destroy() {
|
|
12473
|
+
this.destroyQueries();
|
|
12474
|
+
this.queries$.next([]);
|
|
12475
|
+
}
|
|
12476
|
+
destroyQueries() {
|
|
12477
|
+
for (const query of this.queries$.value) {
|
|
12478
|
+
query.stopPolling();
|
|
12479
|
+
query.abort();
|
|
12480
|
+
if ('destroy' in query && typeof query.destroy === 'function')
|
|
12481
|
+
query.destroy();
|
|
12482
|
+
}
|
|
12483
|
+
}
|
|
12346
12484
|
prepareArgs(config, page) {
|
|
12347
12485
|
const pageParamLocation = this.getPageParamLocation(config?.pageParam?.location);
|
|
12348
12486
|
const pageArgs = {
|
|
@@ -12416,8 +12554,6 @@ const INFINITY_QUERY_TOKEN = new InjectionToken('INFINITY_QUERY_TOKEN');
|
|
|
12416
12554
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
12417
12555
|
*/
|
|
12418
12556
|
class InfinityQueryDirective {
|
|
12419
|
-
// TODO: Skipped for migration because:
|
|
12420
|
-
// Accessor inputs cannot be migrated as they are too complex.
|
|
12421
12557
|
get infinityQuery() {
|
|
12422
12558
|
return this._infinityQuery;
|
|
12423
12559
|
}
|
|
@@ -12530,6 +12666,8 @@ class InfinityQueryDirective {
|
|
|
12530
12666
|
}
|
|
12531
12667
|
cleanup() {
|
|
12532
12668
|
this.queryConfigChanged$.next(true);
|
|
12669
|
+
this.infinityQueryInstance?.destroy();
|
|
12670
|
+
this.infinityQueryInstance = null;
|
|
12533
12671
|
this.viewContext.loading = false;
|
|
12534
12672
|
this.viewContext.error = null;
|
|
12535
12673
|
this.viewContext.etInfinityQuery = null;
|
|
@@ -12909,7 +13047,7 @@ class QueryDevtoolsComponent {
|
|
|
12909
13047
|
cookiePath: refreshCfg?.cookiePath ?? '/ (default)',
|
|
12910
13048
|
cookieEnabled: refreshCfg?.cookieEnabled ?? 'true (default)',
|
|
12911
13049
|
cookieSameSite: refreshCfg?.cookieSameSite ?? 'lax (default)',
|
|
12912
|
-
refreshBuffer: refreshCfg?.refreshBuffer ?? '
|
|
13050
|
+
refreshBuffer: refreshCfg?.refreshBuffer ?? '300000 (default)',
|
|
12913
13051
|
expiresInPropertyName: refreshCfg?.expiresInPropertyName ?? 'exp (default)',
|
|
12914
13052
|
strategy: refreshCfg?.strategy ?? 'AuthBearerRefreshStrategy.BeforeExpiration (default)',
|
|
12915
13053
|
requestArgsAdapter: refreshCfg?.requestArgsAdapter ? 'custom' : 'default',
|
|
@@ -13193,7 +13331,6 @@ class EntityStore {
|
|
|
13193
13331
|
function mapToPaginated(response) {
|
|
13194
13332
|
return map((items) => ({ ...response, items }));
|
|
13195
13333
|
}
|
|
13196
|
-
// FIXME: This breaks if SubStoreType is an array
|
|
13197
13334
|
/**
|
|
13198
13335
|
* Use an other store to represent a property of the current entity.
|
|
13199
13336
|
*
|
|
@@ -13265,6 +13402,7 @@ const invalidBodyError = (data) => new RuntimeError(QueryRuntimeErrorCode.LEGACY
|
|
|
13265
13402
|
* @deprecated Part of the legacy (v2) query system. Migrate to the current query API - see https://ethlete-sdk-docs.web.app/query/migrating-from-v2, and run `nx g @ethlete/query:migrate-to-query-v3` to rewrite the mechanical parts. Intent to remove in v7.
|
|
13266
13403
|
*/
|
|
13267
13404
|
const validateWithV2Query = (path, config) => {
|
|
13405
|
+
const injector = inject(Injector);
|
|
13268
13406
|
applyQueryAsyncValidator(path, {
|
|
13269
13407
|
params: config.args,
|
|
13270
13408
|
debounce: config.debounce,
|
|
@@ -13275,18 +13413,30 @@ const validateWithV2Query = (path, config) => {
|
|
|
13275
13413
|
loader: ({ params: prepareArgs, abortSignal }) => {
|
|
13276
13414
|
// Prepared per request - v2 caches by the prepared args, so a fresh `prepare()` is the
|
|
13277
13415
|
// legacy idiom (the sibling `selectOptionsFromV2Query` does the same via `queryComputed`).
|
|
13278
|
-
const query = config.queryCreator.prepare(prepareArgs);
|
|
13279
|
-
|
|
13416
|
+
const query = runInInjectionContext(injector, () => config.queryCreator.prepare(prepareArgs));
|
|
13417
|
+
let destroyed = false;
|
|
13418
|
+
const destroy = () => {
|
|
13419
|
+
if (destroyed)
|
|
13420
|
+
return;
|
|
13421
|
+
destroyed = true;
|
|
13422
|
+
query.destroy?.();
|
|
13423
|
+
};
|
|
13424
|
+
abortSignal.addEventListener('abort', () => {
|
|
13425
|
+
query.abort();
|
|
13426
|
+
destroy();
|
|
13427
|
+
}, { once: true });
|
|
13280
13428
|
query.execute();
|
|
13281
13429
|
// Resolve once the query settles. A failure is thrown so it lands in `onError`, where the
|
|
13282
13430
|
// violations are mapped onto the fields; the underlying `HttpErrorResponse` is thrown so
|
|
13283
13431
|
// `extractFormViolations` can unwrap the 422 body.
|
|
13284
|
-
return firstValueFrom(query.state$.pipe(filter((state) => isQueryStateSuccess(state) || isQueryStateFailure(state)), take(1)))
|
|
13432
|
+
return firstValueFrom(query.state$.pipe(filter((state) => isQueryStateSuccess(state) || isQueryStateFailure(state)), take(1)))
|
|
13433
|
+
.then((state) => {
|
|
13285
13434
|
if (isQueryStateFailure(state)) {
|
|
13286
13435
|
throw state.error.httpErrorResponse;
|
|
13287
13436
|
}
|
|
13288
13437
|
return state.response;
|
|
13289
|
-
})
|
|
13438
|
+
})
|
|
13439
|
+
.finally(destroy);
|
|
13290
13440
|
},
|
|
13291
13441
|
}),
|
|
13292
13442
|
});
|
|
@@ -13703,7 +13853,7 @@ const transformToStringArray = (value) => {
|
|
|
13703
13853
|
return value.map(transformToString).filter(Boolean);
|
|
13704
13854
|
}
|
|
13705
13855
|
else if (typeof value === 'string') {
|
|
13706
|
-
return [
|
|
13856
|
+
return value ? [value] : [];
|
|
13707
13857
|
}
|
|
13708
13858
|
return null;
|
|
13709
13859
|
};
|
|
@@ -13712,7 +13862,10 @@ const transformToNumber = (value) => {
|
|
|
13712
13862
|
return value;
|
|
13713
13863
|
}
|
|
13714
13864
|
if (typeof value === 'string') {
|
|
13715
|
-
|
|
13865
|
+
if (!value.trim())
|
|
13866
|
+
return null;
|
|
13867
|
+
const number = Number(value);
|
|
13868
|
+
return Number.isNaN(number) ? null : number;
|
|
13716
13869
|
}
|
|
13717
13870
|
return null;
|
|
13718
13871
|
};
|
|
@@ -13720,8 +13873,9 @@ const transformToNumberArray = (value) => {
|
|
|
13720
13873
|
if (Array.isArray(value)) {
|
|
13721
13874
|
return value.map(transformToNumber).filter((item) => item !== null);
|
|
13722
13875
|
}
|
|
13723
|
-
else if (typeof value === 'number') {
|
|
13724
|
-
|
|
13876
|
+
else if (typeof value === 'string' || typeof value === 'number') {
|
|
13877
|
+
const number = transformToNumber(value);
|
|
13878
|
+
return number === null ? [] : [number];
|
|
13725
13879
|
}
|
|
13726
13880
|
return null;
|
|
13727
13881
|
};
|
|
@@ -13739,7 +13893,8 @@ const transformToBooleanArray = (value) => {
|
|
|
13739
13893
|
return value.map(transformToBoolean).filter((item) => item !== null);
|
|
13740
13894
|
}
|
|
13741
13895
|
else if (typeof value === 'string' || typeof value === 'boolean') {
|
|
13742
|
-
|
|
13896
|
+
const boolean = transformToBoolean(value);
|
|
13897
|
+
return boolean === null ? [] : [boolean];
|
|
13743
13898
|
}
|
|
13744
13899
|
return null;
|
|
13745
13900
|
};
|
|
@@ -13761,7 +13916,8 @@ const transformToDateArray = (value) => {
|
|
|
13761
13916
|
return value.map(transformToDate).filter((item) => item !== null);
|
|
13762
13917
|
}
|
|
13763
13918
|
else if (typeof value === 'string' || value instanceof Date) {
|
|
13764
|
-
|
|
13919
|
+
const date = transformToDate(value);
|
|
13920
|
+
return date === null ? [] : [date];
|
|
13765
13921
|
}
|
|
13766
13922
|
return null;
|
|
13767
13923
|
};
|
|
@@ -13773,7 +13929,7 @@ const transformToSort = (value) => {
|
|
|
13773
13929
|
}
|
|
13774
13930
|
return {
|
|
13775
13931
|
active,
|
|
13776
|
-
direction: direction,
|
|
13932
|
+
direction: direction === 'asc' || direction === 'desc' ? direction : '',
|
|
13777
13933
|
};
|
|
13778
13934
|
}
|
|
13779
13935
|
return null;
|
|
@@ -13791,7 +13947,9 @@ const transformToSortQueryParam = (value) => {
|
|
|
13791
13947
|
|
|
13792
13948
|
const ET_ARR_PREFIX = 'ET_ARR__';
|
|
13793
13949
|
const ET_OBJ_PREFIX = 'ET_OBJ__';
|
|
13950
|
+
const ET_DATE_PREFIX = 'ET_DATE__';
|
|
13794
13951
|
const ET_PROP_NULL_VALUE = 'ET_NULL__';
|
|
13952
|
+
/** @deprecated Use `queryField` with `defineQueryForm`. */
|
|
13795
13953
|
class QueryField {
|
|
13796
13954
|
constructor(data) {
|
|
13797
13955
|
this.data = data;
|
|
@@ -13800,6 +13958,7 @@ class QueryField {
|
|
|
13800
13958
|
return this.data.control;
|
|
13801
13959
|
}
|
|
13802
13960
|
}
|
|
13961
|
+
/** @deprecated Use `searchQueryField` with `defineQueryForm`. */
|
|
13803
13962
|
class SearchQueryField {
|
|
13804
13963
|
constructor(_data) {
|
|
13805
13964
|
this._data = _data;
|
|
@@ -13814,6 +13973,7 @@ class SearchQueryField {
|
|
|
13814
13973
|
return this.data.control;
|
|
13815
13974
|
}
|
|
13816
13975
|
}
|
|
13976
|
+
/** @deprecated Use `sortQueryField` with `defineQueryForm`. */
|
|
13817
13977
|
class SortQueryField {
|
|
13818
13978
|
constructor(_data) {
|
|
13819
13979
|
this._data = _data;
|
|
@@ -13828,6 +13988,7 @@ class SortQueryField {
|
|
|
13828
13988
|
return this.data.control;
|
|
13829
13989
|
}
|
|
13830
13990
|
}
|
|
13991
|
+
/** @deprecated Use `stringArrayQueryField` with `defineQueryForm`. */
|
|
13831
13992
|
class StringArrayQueryField {
|
|
13832
13993
|
constructor(_data) {
|
|
13833
13994
|
this._data = _data;
|
|
@@ -13841,6 +14002,7 @@ class StringArrayQueryField {
|
|
|
13841
14002
|
return this.data.control;
|
|
13842
14003
|
}
|
|
13843
14004
|
}
|
|
14005
|
+
/** @deprecated Use `booleanArrayQueryField` with `defineQueryForm`. */
|
|
13844
14006
|
class BooleanArrayQueryField {
|
|
13845
14007
|
constructor(_data) {
|
|
13846
14008
|
this._data = _data;
|
|
@@ -13854,6 +14016,7 @@ class BooleanArrayQueryField {
|
|
|
13854
14016
|
return this.data.control;
|
|
13855
14017
|
}
|
|
13856
14018
|
}
|
|
14019
|
+
/** @deprecated Use `numberArrayQueryField` with `defineQueryForm`. */
|
|
13857
14020
|
class NumberArrayQueryField {
|
|
13858
14021
|
constructor(_data) {
|
|
13859
14022
|
this._data = _data;
|
|
@@ -13867,6 +14030,7 @@ class NumberArrayQueryField {
|
|
|
13867
14030
|
return this.data.control;
|
|
13868
14031
|
}
|
|
13869
14032
|
}
|
|
14033
|
+
/** @deprecated Use `dateQueryField` with `defineQueryForm`. */
|
|
13870
14034
|
class DateQueryField {
|
|
13871
14035
|
constructor(_data) {
|
|
13872
14036
|
this._data = _data;
|
|
@@ -13880,6 +14044,7 @@ class DateQueryField {
|
|
|
13880
14044
|
return this.data.control;
|
|
13881
14045
|
}
|
|
13882
14046
|
}
|
|
14047
|
+
/** @deprecated Use `dateArrayQueryField` with `defineQueryForm`. */
|
|
13883
14048
|
class DateArrayQueryField {
|
|
13884
14049
|
constructor(_data) {
|
|
13885
14050
|
this._data = _data;
|
|
@@ -13894,6 +14059,7 @@ class DateArrayQueryField {
|
|
|
13894
14059
|
}
|
|
13895
14060
|
}
|
|
13896
14061
|
const IGNORED_FILTER_COUNT_FIELDS$1 = ['page', 'skip', 'take', 'limit', 'sort', 'sortBy', 'sortOrder', 'query', 'search'];
|
|
14062
|
+
/** @deprecated Use `defineQueryForm`. */
|
|
13897
14063
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13898
14064
|
class QueryForm {
|
|
13899
14065
|
// with prefix eg. page should become ${prefix}-page
|
|
@@ -13901,7 +14067,6 @@ class QueryForm {
|
|
|
13901
14067
|
this._fields = _fields;
|
|
13902
14068
|
this._options = _options;
|
|
13903
14069
|
this.router = inject(Router);
|
|
13904
|
-
this.activatedRoute = inject(ActivatedRoute);
|
|
13905
14070
|
this.zone = inject(NgZone);
|
|
13906
14071
|
this.queryParams = injectQueryParams();
|
|
13907
14072
|
this.destroy$ = createDestroy();
|
|
@@ -13909,7 +14074,10 @@ class QueryForm {
|
|
|
13909
14074
|
this.defaultValues = this.extractDefaultValues();
|
|
13910
14075
|
this.didValueChanges$ = new Subject();
|
|
13911
14076
|
this.isObserving = false;
|
|
14077
|
+
this.removeQueryParamsOnCleanup = true;
|
|
13912
14078
|
this.skipNextResets = false;
|
|
14079
|
+
this.urlWriteVersion = 0;
|
|
14080
|
+
this.urlNavigationMarker = {};
|
|
13913
14081
|
this.queryParamChanges$ = toObservable(injectQueryParamChanges());
|
|
13914
14082
|
/**
|
|
13915
14083
|
* The angular form group that contains all the fields.
|
|
@@ -13957,7 +14125,7 @@ class QueryForm {
|
|
|
13957
14125
|
})
|
|
13958
14126
|
.filter((v) => v === false).length));
|
|
13959
14127
|
assertInInjectionContext(QueryForm);
|
|
13960
|
-
inject(DestroyRef).onDestroy(() => this.cleanup());
|
|
14128
|
+
inject(DestroyRef).onDestroy(() => this.cleanup(false));
|
|
13961
14129
|
}
|
|
13962
14130
|
get controls() {
|
|
13963
14131
|
return this.form.controls;
|
|
@@ -13979,6 +14147,7 @@ class QueryForm {
|
|
|
13979
14147
|
return this;
|
|
13980
14148
|
}
|
|
13981
14149
|
this.isObserving = true;
|
|
14150
|
+
this.removeQueryParamsOnCleanup = options?.writeToQueryParams !== false;
|
|
13982
14151
|
if (options?.syncOnNavigation !== false) {
|
|
13983
14152
|
const didChanges = this.setFormValueFromUrlQueryParams({
|
|
13984
14153
|
queryParams: this.queryParams(),
|
|
@@ -14048,6 +14217,9 @@ class QueryForm {
|
|
|
14048
14217
|
if (options?.syncOnNavigation !== false) {
|
|
14049
14218
|
this.queryParamChanges$
|
|
14050
14219
|
.pipe(takeUntil(this.destroy$), takeUntil(this.unobserveTrigger$), tap((changes) => {
|
|
14220
|
+
const info = this.router.lastSuccessfulNavigation()?.extras.info;
|
|
14221
|
+
if (info?.queryForm === this.urlNavigationMarker && (info.version ?? 0) < this.urlWriteVersion)
|
|
14222
|
+
return;
|
|
14051
14223
|
const didValueChanges = this.setFormValueFromUrlQueryParams({ queryParams: changes });
|
|
14052
14224
|
if (didValueChanges) {
|
|
14053
14225
|
this.didValueChanges$.next(true);
|
|
@@ -14087,7 +14259,7 @@ class QueryForm {
|
|
|
14087
14259
|
const valueContainsWhitespace = typeof value === 'string' && value.trim() !== value;
|
|
14088
14260
|
const valueHasLeadingZero = typeof value === 'string' && value.startsWith('0');
|
|
14089
14261
|
const valueEndsWithDot = typeof value === 'string' && value.endsWith('.');
|
|
14090
|
-
const defaultIsBool = this.getDefaultValue(key) === 'boolean';
|
|
14262
|
+
const defaultIsBool = typeof this.getDefaultValue(key) === 'boolean';
|
|
14091
14263
|
const valueIsBool = value === 'true' || value === 'false';
|
|
14092
14264
|
if (value === ET_PROP_NULL_VALUE) {
|
|
14093
14265
|
deserializedValue = null;
|
|
@@ -14109,16 +14281,20 @@ class QueryForm {
|
|
|
14109
14281
|
return didValueChanges;
|
|
14110
14282
|
}
|
|
14111
14283
|
setValue(value, options) {
|
|
14112
|
-
this._form._setValue(value, options);
|
|
14113
14284
|
if (options?.skipResets) {
|
|
14114
14285
|
this.skipNextResets = true;
|
|
14115
14286
|
}
|
|
14287
|
+
this._form._setValue(value, options);
|
|
14288
|
+
if (!this.isObserving)
|
|
14289
|
+
this.handleFormChange(true);
|
|
14116
14290
|
}
|
|
14117
14291
|
patchValue(value, options) {
|
|
14118
|
-
this._form._patchValue(value, options);
|
|
14119
14292
|
if (options?.skipResets) {
|
|
14120
14293
|
this.skipNextResets = true;
|
|
14121
14294
|
}
|
|
14295
|
+
this._form._patchValue(value, options);
|
|
14296
|
+
if (!this.isObserving)
|
|
14297
|
+
this.handleFormChange(true);
|
|
14122
14298
|
}
|
|
14123
14299
|
resetFieldToDefault(key, options) {
|
|
14124
14300
|
const defaultValue = this.getDefaultValue(key);
|
|
@@ -14196,6 +14372,9 @@ class QueryForm {
|
|
|
14196
14372
|
else if (typeof val === 'string' && val.startsWith(ET_OBJ_PREFIX)) {
|
|
14197
14373
|
return JSON.parse(val.slice(ET_OBJ_PREFIX.length));
|
|
14198
14374
|
}
|
|
14375
|
+
else if (typeof val === 'string' && val.startsWith(ET_DATE_PREFIX)) {
|
|
14376
|
+
return new Date(val.slice(ET_DATE_PREFIX.length));
|
|
14377
|
+
}
|
|
14199
14378
|
else if (typeof val === 'function') {
|
|
14200
14379
|
return val();
|
|
14201
14380
|
}
|
|
@@ -14215,11 +14394,13 @@ class QueryForm {
|
|
|
14215
14394
|
isDefaultValue(key, value) {
|
|
14216
14395
|
const normalizedValue = Array.isArray(value)
|
|
14217
14396
|
? `${ET_ARR_PREFIX}${JSON.stringify(value)}`
|
|
14218
|
-
:
|
|
14219
|
-
? `${
|
|
14220
|
-
: value === null
|
|
14221
|
-
?
|
|
14222
|
-
: value
|
|
14397
|
+
: value instanceof Date
|
|
14398
|
+
? `${ET_DATE_PREFIX}${value.toISOString()}`
|
|
14399
|
+
: typeof value === 'object' && value !== null
|
|
14400
|
+
? `${ET_OBJ_PREFIX}${JSON.stringify(value)}`
|
|
14401
|
+
: value === null
|
|
14402
|
+
? ET_PROP_NULL_VALUE
|
|
14403
|
+
: value;
|
|
14223
14404
|
return this.defaultValues[key] === normalizedValue;
|
|
14224
14405
|
}
|
|
14225
14406
|
setupFormGroup() {
|
|
@@ -14240,6 +14421,9 @@ class QueryForm {
|
|
|
14240
14421
|
if (Array.isArray(value)) {
|
|
14241
14422
|
defaultValues[key] = `${ET_ARR_PREFIX}${JSON.stringify(value)}`;
|
|
14242
14423
|
}
|
|
14424
|
+
else if (value instanceof Date) {
|
|
14425
|
+
defaultValues[key] = `${ET_DATE_PREFIX}${value.toISOString()}`;
|
|
14426
|
+
}
|
|
14243
14427
|
else if (typeof value === 'object' && value !== null) {
|
|
14244
14428
|
defaultValues[key] = `${ET_OBJ_PREFIX}${JSON.stringify(value)}`;
|
|
14245
14429
|
}
|
|
@@ -14253,7 +14437,8 @@ class QueryForm {
|
|
|
14253
14437
|
return defaultValues;
|
|
14254
14438
|
}
|
|
14255
14439
|
_syncViaUrlQueryParams(values, replaceUrl) {
|
|
14256
|
-
const queryParams = {
|
|
14440
|
+
const queryParams = {};
|
|
14441
|
+
const version = ++this.urlWriteVersion;
|
|
14257
14442
|
for (const [key, value] of Object.entries(values)) {
|
|
14258
14443
|
const queryParamKey = this.transformKeyToQueryParam(key);
|
|
14259
14444
|
const field = this._fields[key];
|
|
@@ -14280,6 +14465,7 @@ class QueryForm {
|
|
|
14280
14465
|
queryParams,
|
|
14281
14466
|
replaceUrl,
|
|
14282
14467
|
queryParamsHandling: 'merge',
|
|
14468
|
+
info: { queryForm: this.urlNavigationMarker, version },
|
|
14283
14469
|
});
|
|
14284
14470
|
});
|
|
14285
14471
|
});
|
|
@@ -14303,6 +14489,7 @@ class QueryForm {
|
|
|
14303
14489
|
const currentVal = clone(this.currentFormValue$.value);
|
|
14304
14490
|
const newVal = clone(this.formValue);
|
|
14305
14491
|
if (equal(currentVal, newVal)) {
|
|
14492
|
+
this.skipNextResets = false;
|
|
14306
14493
|
return;
|
|
14307
14494
|
}
|
|
14308
14495
|
if (forceOverwrite) {
|
|
@@ -14313,10 +14500,12 @@ class QueryForm {
|
|
|
14313
14500
|
}
|
|
14314
14501
|
this.currentFormValue$.next(newVal);
|
|
14315
14502
|
}
|
|
14316
|
-
cleanup() {
|
|
14503
|
+
cleanup(removeQueryParams = this.removeQueryParamsOnCleanup) {
|
|
14317
14504
|
if (!this.isObserving)
|
|
14318
14505
|
return;
|
|
14319
14506
|
this.isObserving = false;
|
|
14507
|
+
if (!removeQueryParams)
|
|
14508
|
+
return;
|
|
14320
14509
|
const queryParamKeys = Object.keys(this._fields);
|
|
14321
14510
|
const queryParams = queryParamKeys.reduce((acc, key) => {
|
|
14322
14511
|
acc[this.transformKeyToQueryParam(key)] = undefined;
|
|
@@ -14395,14 +14584,23 @@ const createBranch = (fields, initial, injector) => {
|
|
|
14395
14584
|
const model = signal(clone(initial), /* @ts-ignore */
|
|
14396
14585
|
...(ngDevMode ? [{ debugName: "model" }] : /* istanbul ignore next */ []));
|
|
14397
14586
|
const tree = form(model, { injector });
|
|
14587
|
+
const defaultFor = (key) => {
|
|
14588
|
+
const value = resolveDefault(fields[key]);
|
|
14589
|
+
defaults[key] = value;
|
|
14590
|
+
return value;
|
|
14591
|
+
};
|
|
14398
14592
|
return {
|
|
14399
14593
|
fields: tree,
|
|
14400
14594
|
value: model.asReadonly(),
|
|
14401
14595
|
activeFilterCount: computed(() => computeFilterCount(fields, model(), defaults)),
|
|
14402
14596
|
setValue: (value) => model.set(clone(value)),
|
|
14403
14597
|
patchValue: (value) => model.update((cur) => ({ ...cur, ...value })),
|
|
14404
|
-
resetFieldToDefault: (key) => model.update((cur) => ({ ...cur, [key]:
|
|
14405
|
-
resetAllFieldsToDefault: () =>
|
|
14598
|
+
resetFieldToDefault: (key) => model.update((cur) => ({ ...cur, [key]: defaultFor(key) })),
|
|
14599
|
+
resetAllFieldsToDefault: () => {
|
|
14600
|
+
for (const key of Object.keys(fields))
|
|
14601
|
+
defaultFor(key);
|
|
14602
|
+
model.set(clone(defaults));
|
|
14603
|
+
},
|
|
14406
14604
|
};
|
|
14407
14605
|
};
|
|
14408
14606
|
/**
|
|
@@ -14440,6 +14638,12 @@ const defineQueryForm = (config) => {
|
|
|
14440
14638
|
const prefix = config.queryParamPrefix;
|
|
14441
14639
|
const defaults = buildDefaults(fieldDefs);
|
|
14442
14640
|
const defaultValue = clone(defaults);
|
|
14641
|
+
const defaultFor = (key) => {
|
|
14642
|
+
const value = resolveDefault(fieldDefs[key]);
|
|
14643
|
+
defaults[key] = value;
|
|
14644
|
+
defaultValue[key] = clone(value);
|
|
14645
|
+
return value;
|
|
14646
|
+
};
|
|
14443
14647
|
/** Live field values (updated immediately by bound controls). */
|
|
14444
14648
|
const model = signal(clone(defaults), /* @ts-ignore */
|
|
14445
14649
|
...(ngDevMode ? [{ debugName: "model" }] : /* istanbul ignore next */ []));
|
|
@@ -14455,6 +14659,8 @@ const defineQueryForm = (config) => {
|
|
|
14455
14659
|
let observeOptions;
|
|
14456
14660
|
let pendingTimer = null;
|
|
14457
14661
|
let skipNextResets = false;
|
|
14662
|
+
let urlWriteVersion = 0;
|
|
14663
|
+
const urlNavigationMarker = {};
|
|
14458
14664
|
const fields = form(model);
|
|
14459
14665
|
const activeFilterCount = computed(() => computeFilterCount(fieldDefs, committed(), defaults), /* @ts-ignore */
|
|
14460
14666
|
...(ngDevMode ? [{ debugName: "activeFilterCount" }] : /* istanbul ignore next */ []));
|
|
@@ -14472,6 +14678,8 @@ const defineQueryForm = (config) => {
|
|
|
14472
14678
|
return undefined;
|
|
14473
14679
|
if (def.valueToQueryParam)
|
|
14474
14680
|
return def.valueToQueryParam(value);
|
|
14681
|
+
if (value === '' && defaults[key] === null)
|
|
14682
|
+
return undefined;
|
|
14475
14683
|
return value === null ? ET_NULL_VALUE : value;
|
|
14476
14684
|
};
|
|
14477
14685
|
const deserialize = (def, raw) => {
|
|
@@ -14490,6 +14698,7 @@ const defineQueryForm = (config) => {
|
|
|
14490
14698
|
};
|
|
14491
14699
|
const writeToUrl = (value) => {
|
|
14492
14700
|
const queryParams = {};
|
|
14701
|
+
const version = ++urlWriteVersion;
|
|
14493
14702
|
for (const [key, def] of Object.entries(fieldDefs)) {
|
|
14494
14703
|
queryParams[paramKey(key)] = queryParamFor(key, def, value[key]);
|
|
14495
14704
|
}
|
|
@@ -14498,10 +14707,11 @@ const defineQueryForm = (config) => {
|
|
|
14498
14707
|
queryParams,
|
|
14499
14708
|
queryParamsHandling: 'merge',
|
|
14500
14709
|
replaceUrl: observeOptions?.replaceUrl,
|
|
14710
|
+
info: { queryForm: urlNavigationMarker, version },
|
|
14501
14711
|
});
|
|
14502
14712
|
});
|
|
14503
14713
|
};
|
|
14504
|
-
const applyResets = (live, changedKeys) => {
|
|
14714
|
+
const applyResets = (live, changedKeys, resetDefaults) => {
|
|
14505
14715
|
const next = { ...live };
|
|
14506
14716
|
for (const [key, def] of Object.entries(fieldDefs)) {
|
|
14507
14717
|
const resets = def.isResetBy;
|
|
@@ -14518,7 +14728,11 @@ const defineQueryForm = (config) => {
|
|
|
14518
14728
|
});
|
|
14519
14729
|
if (!triggered)
|
|
14520
14730
|
continue;
|
|
14521
|
-
|
|
14731
|
+
let fieldDefault = resetDefaults.get(key);
|
|
14732
|
+
if (!resetDefaults.has(key)) {
|
|
14733
|
+
fieldDefault = defaultFor(key);
|
|
14734
|
+
resetDefaults.set(key, fieldDefault);
|
|
14735
|
+
}
|
|
14522
14736
|
if (!equal(next[key], fieldDefault)) {
|
|
14523
14737
|
next[key] = fieldDefault;
|
|
14524
14738
|
}
|
|
@@ -14534,8 +14748,9 @@ const defineQueryForm = (config) => {
|
|
|
14534
14748
|
*/
|
|
14535
14749
|
const resolveResets = (prev, live) => {
|
|
14536
14750
|
let next = live;
|
|
14751
|
+
const resetDefaults = new Map();
|
|
14537
14752
|
for (let pass = 0; pass < MAX_RESET_PASSES; pass++) {
|
|
14538
|
-
const applied = applyResets(next, changedKeysBetween(prev, next));
|
|
14753
|
+
const applied = applyResets(next, changedKeysBetween(prev, next), resetDefaults);
|
|
14539
14754
|
if (equal(applied, next))
|
|
14540
14755
|
return applied;
|
|
14541
14756
|
next = applied;
|
|
@@ -14547,10 +14762,24 @@ const defineQueryForm = (config) => {
|
|
|
14547
14762
|
};
|
|
14548
14763
|
const flush = () => {
|
|
14549
14764
|
clearTimer();
|
|
14550
|
-
const
|
|
14765
|
+
const rawLive = model();
|
|
14766
|
+
const live = { ...rawLive };
|
|
14767
|
+
for (const [key, def] of Object.entries(fieldDefs)) {
|
|
14768
|
+
if (equal(live[key], defaults[key]))
|
|
14769
|
+
continue;
|
|
14770
|
+
const serialized = def.valueToQueryParam?.(live[key]);
|
|
14771
|
+
const serializedToNothing = !!def.valueToQueryParam && (serialized === null || serialized === undefined);
|
|
14772
|
+
const clearedNullableText = live[key] === '' && defaults[key] === null;
|
|
14773
|
+
if (serializedToNothing || clearedNullableText) {
|
|
14774
|
+
live[key] = defaults[key];
|
|
14775
|
+
}
|
|
14776
|
+
}
|
|
14551
14777
|
const prev = committed();
|
|
14552
14778
|
if (equal(live, prev)) {
|
|
14553
14779
|
skipNextResets = false;
|
|
14780
|
+
if (!equal(live, rawLive)) {
|
|
14781
|
+
model.set(clone(live));
|
|
14782
|
+
}
|
|
14554
14783
|
return;
|
|
14555
14784
|
}
|
|
14556
14785
|
const next = skipNextResets ? { ...live } : resolveResets(prev, live);
|
|
@@ -14559,7 +14788,7 @@ const defineQueryForm = (config) => {
|
|
|
14559
14788
|
committed.set(clone(next));
|
|
14560
14789
|
// Reflect any reset overrides back into the bound controls. The effect re-runs
|
|
14561
14790
|
// but no-ops because the model now equals the committed value.
|
|
14562
|
-
if (!equal(next,
|
|
14791
|
+
if (!equal(next, rawLive)) {
|
|
14563
14792
|
model.set(clone(next));
|
|
14564
14793
|
}
|
|
14565
14794
|
if (observing() && observeOptions?.writeToQueryParams !== false) {
|
|
@@ -14626,12 +14855,12 @@ const defineQueryForm = (config) => {
|
|
|
14626
14855
|
return;
|
|
14627
14856
|
commitFromUrl(current);
|
|
14628
14857
|
};
|
|
14629
|
-
const cleanup = () => {
|
|
14858
|
+
const cleanup = (removeQueryParams = true) => {
|
|
14630
14859
|
if (!observing())
|
|
14631
14860
|
return;
|
|
14632
14861
|
observing.set(false);
|
|
14633
14862
|
clearTimer();
|
|
14634
|
-
if (observeOptions?.writeToQueryParams === false)
|
|
14863
|
+
if (!removeQueryParams || observeOptions?.writeToQueryParams === false)
|
|
14635
14864
|
return;
|
|
14636
14865
|
const queryParams = {};
|
|
14637
14866
|
for (const key of Object.keys(fieldDefs)) {
|
|
@@ -14657,7 +14886,7 @@ const defineQueryForm = (config) => {
|
|
|
14657
14886
|
model.update((cur) => {
|
|
14658
14887
|
const next = { ...cur };
|
|
14659
14888
|
for (const key of keys) {
|
|
14660
|
-
next[key] =
|
|
14889
|
+
next[key] = defaultFor(key);
|
|
14661
14890
|
}
|
|
14662
14891
|
return next;
|
|
14663
14892
|
});
|
|
@@ -14694,6 +14923,10 @@ const defineQueryForm = (config) => {
|
|
|
14694
14923
|
}
|
|
14695
14924
|
// Commit whatever the model holds now (URL-restored or programmatic defaults).
|
|
14696
14925
|
flush();
|
|
14926
|
+
if (options?.writeToQueryParams !== false &&
|
|
14927
|
+
Object.values(fieldDefs).some((field) => field.appendDefaultValueToUrl === true)) {
|
|
14928
|
+
writeToUrl(committed());
|
|
14929
|
+
}
|
|
14697
14930
|
return queryForm;
|
|
14698
14931
|
},
|
|
14699
14932
|
unobserve: () => cleanup(),
|
|
@@ -14706,7 +14939,7 @@ const defineQueryForm = (config) => {
|
|
|
14706
14939
|
const keys = Object.keys(fieldDefs).filter((key) => !skip.has(key));
|
|
14707
14940
|
resetFieldsToDefault(keys, options);
|
|
14708
14941
|
},
|
|
14709
|
-
branch: () => createBranch(fieldDefs, clone(committed()),
|
|
14942
|
+
branch: (branchInjector = injector) => createBranch(fieldDefs, clone(committed()), branchInjector),
|
|
14710
14943
|
};
|
|
14711
14944
|
// React to live control edits: schedule a debounced commit.
|
|
14712
14945
|
effect(() => {
|
|
@@ -14719,10 +14952,13 @@ const defineQueryForm = (config) => {
|
|
|
14719
14952
|
untracked(() => {
|
|
14720
14953
|
if (!observing() || observeOptions?.syncOnNavigation === false)
|
|
14721
14954
|
return;
|
|
14955
|
+
const info = router.lastSuccessfulNavigation()?.extras.info;
|
|
14956
|
+
if (info?.queryForm === urlNavigationMarker && (info.version ?? 0) < urlWriteVersion)
|
|
14957
|
+
return;
|
|
14722
14958
|
applyFromUrl(changes);
|
|
14723
14959
|
});
|
|
14724
14960
|
});
|
|
14725
|
-
destroyRef.onDestroy(() => cleanup());
|
|
14961
|
+
destroyRef.onDestroy(() => cleanup(false));
|
|
14726
14962
|
if (devtoolsId) {
|
|
14727
14963
|
/**
|
|
14728
14964
|
* The live view `<et-query-devtools>` renders. Only built while the devtools are installed - it walks
|
|
@@ -14896,13 +15132,14 @@ const createWebSocketClient = (options) => {
|
|
|
14896
15132
|
const pre = previousSignalValue(computed(() => roomFn()));
|
|
14897
15133
|
const roomData = signal(null, /* @ts-ignore */
|
|
14898
15134
|
...(ngDevMode ? [{ debugName: "roomData" }] : /* istanbul ignore next */ []));
|
|
15135
|
+
let joinedRoomName = null;
|
|
14899
15136
|
const join = (name) => {
|
|
14900
|
-
emit({ event: 'join-room', data: name, room: name });
|
|
14901
15137
|
const existingRoom = rooms.get(name);
|
|
14902
15138
|
if (existingRoom) {
|
|
14903
15139
|
existingRoom.joinCount++;
|
|
14904
15140
|
return existingRoom;
|
|
14905
15141
|
}
|
|
15142
|
+
emit({ event: 'join-room', data: name, room: name });
|
|
14906
15143
|
const message = signal(null, /* @ts-ignore */
|
|
14907
15144
|
...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
|
|
14908
15145
|
const newRoom = {
|
|
@@ -14919,12 +15156,16 @@ const createWebSocketClient = (options) => {
|
|
|
14919
15156
|
const previous = pre();
|
|
14920
15157
|
if (previous === current)
|
|
14921
15158
|
return;
|
|
14922
|
-
if (previous)
|
|
15159
|
+
if (previous) {
|
|
14923
15160
|
leaveRoom(previous);
|
|
15161
|
+
joinedRoomName = null;
|
|
15162
|
+
}
|
|
14924
15163
|
if (current) {
|
|
14925
15164
|
const joinedRoom = join(current);
|
|
14926
|
-
if (joinedRoom)
|
|
15165
|
+
if (joinedRoom) {
|
|
15166
|
+
joinedRoomName = current;
|
|
14927
15167
|
roomData.set(joinedRoom);
|
|
15168
|
+
}
|
|
14928
15169
|
}
|
|
14929
15170
|
else {
|
|
14930
15171
|
roomData.set(null);
|
|
@@ -14932,9 +15173,9 @@ const createWebSocketClient = (options) => {
|
|
|
14932
15173
|
});
|
|
14933
15174
|
});
|
|
14934
15175
|
inject(DestroyRef).onDestroy(() => {
|
|
14935
|
-
|
|
14936
|
-
|
|
14937
|
-
|
|
15176
|
+
if (joinedRoomName) {
|
|
15177
|
+
leaveRoom(joinedRoomName);
|
|
15178
|
+
joinedRoomName = null;
|
|
14938
15179
|
roomData.set(null);
|
|
14939
15180
|
}
|
|
14940
15181
|
});
|
|
@@ -14964,8 +15205,11 @@ const createWebSocketClient = (options) => {
|
|
|
14964
15205
|
socket.on('disconnect', () => isConnected.set(false));
|
|
14965
15206
|
};
|
|
14966
15207
|
const setupWebSocketListener = () => {
|
|
14967
|
-
socket.onAny((
|
|
15208
|
+
socket.onAny((_eventName, ...args) => {
|
|
14968
15209
|
try {
|
|
15210
|
+
const data = args[0];
|
|
15211
|
+
if (typeof data !== 'string')
|
|
15212
|
+
throw messageMalformed();
|
|
14969
15213
|
const json = JSON.parse(data);
|
|
14970
15214
|
recordDevtoolsMessage({ room: json.room, event: json.event, data: json.data, direction: 'in' });
|
|
14971
15215
|
const room = rooms.get(json.room);
|
|
@@ -15014,5 +15258,5 @@ const createWebSocketClient = (options) => {
|
|
|
15014
15258
|
* Generated bundle index. Do not edit.
|
|
15015
15259
|
*/
|
|
15016
15260
|
|
|
15017
|
-
export { BasicAuthProvider, BearerAuthFeatureType, BooleanArrayQueryField, CustomHeaderAuthProvider, DEFAULT_KEEP_UNUSED_FOR, DEFAULT_QUERY_PERSISTENCE_MAX_AGE, DEFAULT_QUERY_PERSISTENCE_MAX_ENTRIES, DEFAULT_QUERY_PERSISTENCE_VERSION, DEFAULT_QUERY_PERSISTENCE_WRITE_DELAY, DateArrayQueryField, DateQueryField, EMPTY_QUERY_DEVTOOLS_FAULT, EntityStore, IGNORED_FILTER_COUNT_FIELDS, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, LegacyQuery, LegacyQueryCreator, MAX_QUERY_BATCH_TOMBSTONES, MAX_QUERY_DEVTOOLS_TOMBSTONES, MAX_UNUSED_ENTRIES, NumberArrayQueryField, ParseHttpErrorCodeToMessageDePipe, ParseHttpErrorCodeToMessageEnPipe, ParseHttpErrorCodeToTitleDePipe, ParseHttpErrorCodeToTitleEnPipe, QUERY_CLIENT_DEVTOOLS_TOKEN, QUERY_DEVTOOLS_FAULT_STATUSES, QUERY_DEVTOOLS_TOKEN_TTL_LIMIT, QUERY_PERSISTENCE_STORE_VERSION, QUERY_SYNC_PROTOCOL_VERSION, QUERY_VERSION, QueryClientFeatureType, QueryDevtoolsComponent, QueryDirective, QueryFeatureType, QueryField, QueryForm, QueryRuntimeErrorCode, QueryShortNamePipe, QueryStore, SERVER_ERROR_KIND, SERVER_VIOLATION_ERROR_KIND, SPEED_BUFFER_TIME_IN_MS, SearchQueryField, SortQueryField, StringArrayQueryField, V2BearerAuthProvider, V2Query, V2QueryClient, V2QueryCreator, addQueryContainerHandling, applyQueryDevtoolsOverrides, applyQueryDevtoolsTokenTtl, applyQueryFeatures, armAllQueryDevtoolsMocks, armQueryDevtoolsMock, armQueryDevtoolsOverrideTransfer, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, booleanArrayQueryField, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, canOverrideQueryDevtoolsTokenTtl, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, clearQueryDevtoolsArmedMocks, clearQueryDevtoolsFaults, clearQueryDevtoolsMockStore, clearQueryDevtoolsOverrideStore, clearQueryDevtoolsStore, clearQueryDevtoolsTokenTtl, clearQueryDevtoolsTombstones, clearRestoredQueryDevtoolsOverrides, collectLeafPaths, collectQueryDevtoolsSchemaComponents, collectQueryFormLinks, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, consumeSuppressQueryStackDevtools, contentfulGqlLikePaginationAdapter, countUnresolvedQueryDevtoolsOverrides, createAuthGuard, createBaseQuery, createBaseQueryCreator, createBearerAuthProvider, createDefaultRetryFn, createDeleteQuery, createExecuteFn, createGetQuery, createGqlExecuteFn, createGqlMutationViaGet, createGqlMutationViaPost, createGqlQuery, createGqlQueryCreator, createGqlQueryViaGet, createGqlQueryViaPost, createHttpRequest, createIndexedDbQueryPersistenceAdapter, createInfinityQueryConfig, createLegacyQueryCreator, createNoopQueryPersistenceAdapter, createPagedQueryStack, createPatchQuery, createPersistentAuthFeature, createPostQuery, createPutQuery, createQuery, createQueryBatch, createQueryClient, createQueryCollection, createQueryCollectionSignal, createQueryCollectionSubject, createQueryContext, createQueryCreator, createQueryDevtoolsFormLinks, createQueryDevtoolsFormLinksRecorder, createQueryDevtoolsOverrides, createQueryDevtoolsOverridesRecorder, createQueryDevtoolsStats, createQueryDevtoolsStatsRecorder, createQueryErrorResponse, createQueryFeature, createQueryInvalidationFilter, createQueryKeyLockManager, createQueryObject, createQueryPersistenceEngine, createQueryRepository, createQuerySnapshotFn, createQueryStack, createQuerySubmission, createQuerySyncEngine, createQuerySyncTransport, createSecureDeleteQuery, createSecureExecuteFactory, createSecureExecuteFn, createSecureGetQuery, createSecureGqlExecuteFn, createSecureGqlMutationViaGet, createSecureGqlMutationViaPost, createSecureGqlQuery, createSecureGqlQueryCreator, createSecureGqlQueryViaGet, createSecureGqlQueryViaPost, createSecurePatchQuery, createSecurePostQuery, createSecurePutQuery, createSecureQuery, createSecureQueryCreator, createTrackingFeature, createWebSocketClient, currentQueryDevtoolsBatch, dateArrayQueryField, dateQueryField, decryptBearer, deepFreeze, def, defineQueryForm, deleteQueryDevtoolsMock, describeQueryDevtoolsFeatures, detectContentTypeHeader, detectPaginationShape, dynLikePaginationAdapter, effectComputed, emptyQueryArgs, ethletePaginationAdapter, executeUntilSettled, extractExpiresInSeconds, extractFormViolations, extractHtmlErrorMessage, extractQuery, fakePaginationAdapter, filterFailure, filterNull, filterQueryStates, filterSuccess, forEachHeader, formatQueryDevtoolsDuration, generateQueryDevtoolsNumberPreset, generateQueryDevtoolsSampleNumber, generateQueryDevtoolsStringPreset, getBearerAuthProviderName, getDefaultHeaders, getQueryClientName, getQueryFeatureUsage, getResponseUrl, ggLikePaginationAdapter, gql, gqlDataPropertyMissingInResponse, hasHeader, hasQueryDevtoolsOverridesAtPath, htmlErrorPayload, htmlQueryErrorParser, ignoreAutoRefresh, initQueryDevtoolsFaults, initQueryDevtoolsMocks, initQueryDevtoolsOverridePersistence, initQueryDevtoolsSettings, injectInfinityQueryResponseDelay, injectQueryContext, insertFrom, invalidBaseRouteError, invalidBodyError, invalidRouteError, invalidStateInsideSecureExecuteFactory, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isClassValidatorError, isCreateGqlQueryOptions, isCustomHeaderAuthProvider, isDateShapedLeaf, isEmptyString, isGqlQueryConfig, isHtmlErrorPayload, isLegacyQuery, isNaN$1 as isNaN, isPageOutOfRangeError, isQuery, isQueryCollection, isQueryDevtoolsEnabled, isQueryDevtoolsFaultArmed, isQueryDevtoolsRequestInterceptionEnabled, isQueryErrorResponse, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyFormViolationListError, isSymfonyListError, isSymfonyPagerfantaOutOfRangeError, isUnderInvalidatedUrl, legacyPrepareFallbackInjector, legacyPrepareWithoutInjectionContext, loadQueryDevtoolsSchema, mapToPaginated, mapViolationsToFormErrors, matchesQueryDevtoolsMockPattern, matchesQueryDevtoolsMockQuery, maybeExecute, measureQueryDevtoolsPayload, mergeHeaders, nestedEffect, noteQueryFormRead, numberArrayQueryField, pagedQueryStackNextPageCalledWithoutPreviousPage, pagedQueryStackPageBiggerThanTotalPages, pagedQueryStackPreviousPageCalledButAlreadyAtFirstPage, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, parseHttpErrorCodeToMessageDe, parseHttpErrorCodeToMessageEn, parseHttpErrorCodeToTitleDe, parseHttpErrorCodeToTitleEn, parseQueryDevtoolsOverrideTransfer, parseQueryRoute, patchQueryDevtoolsTokenPayload, pathParamsMissingInRouteFunctionError, provideInfinityQueryResponseDelay, provideLegacyPrepareFallback, provideQueryClientForDevtools, provideQueryDevtools, queryArrayComputed, queryBatchAlreadyRunning, queryBatchWithArgsUsed, queryClientFeatureUsedMultipleTimes, queryComputed, queryComputedTillTruthy, queryDevtoolsAbout, queryDevtoolsArmedMocks, queryDevtoolsArmedMocksRestored, queryDevtoolsEntries, queryDevtoolsFaults, queryDevtoolsFaultsRestored, queryDevtoolsFnDetail, queryDevtoolsMockId, queryDevtoolsMocks, queryDevtoolsOverridePersistence, queryDevtoolsRequestPath, queryDevtoolsResponseHistory, queryDevtoolsRestoredOverridesScope, queryDevtoolsSchemaNames, queryDevtoolsSchemaRoutes, queryDevtoolsSchemaState, queryDevtoolsSettings, queryDevtoolsStorage, queryDevtoolsTokenTtls, queryErrorMessage, queryErrorMessages, queryExecute, queryFeatureUsedMultipleTimes, queryField, querySequence, querySequenceAlreadyRunning, queryStackTotalQueriesAndExpectedQueriesMismatch, queryStackWithArgsUsed, queryStackWithResponseUpdateUsed, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, queryStateErrorSignal, queryStateLoadingSignal, queryStateResponseSignal, queryStateSignal, readQueryDevtoolsStore, registerEthleteVersion, registerQueryDevtoolsEntry, registerQueryErrorParser, removeFrom, request, resetExecuteState, resetPageOnError, resolveInvalidationUrl, resolveQueryDevtoolsFault, resolveQueryDevtoolsFaultForAttempt, resolveQueryDevtoolsMock, resolveQueryDevtoolsMockForAttempt, restoredQueryDevtoolsOverrides, runDefaultQueryRetry, runInQueryDevtoolsBatch, runQueryErrorParsers, saveQueryDevtoolsMock, searchQueryField, seedQueryDevtoolsSchemaBody, seedQueryDevtoolsSchemaRoute, serializeBody, serializeQueryDevtoolsOverrideTransfer, setDefaultQueryRetryFn, setQueryDevtoolsAppInfo, setQueryDevtoolsArmedMocksScope, setQueryDevtoolsFault, setQueryDevtoolsFaultResolver, setQueryDevtoolsFaultsScope, setQueryDevtoolsFormLinksFactory, setQueryDevtoolsMockResolver, setQueryDevtoolsOverridePersistence, setQueryDevtoolsOverridesFactory, setQueryDevtoolsOverridesScope, setQueryDevtoolsRegistrar, setQueryDevtoolsResponseHistory, setQueryDevtoolsSchemaLoader, setQueryDevtoolsSettings, setQueryDevtoolsStatsFactory, setQueryDevtoolsTokenPayloadPatcher, setQueryDevtoolsTokenTtl, setupQueryDependencies, setupQueryExecuteState, setupQueryState, shouldAutoExecuteGqlQuery, shouldAutoExecuteQuery, shouldCacheQuery, shouldRetryRequest, silenceMissingWithArgsFeatureErrorUsedButWithArgsPresent, skipPaginationPageParamCalculator, smartDuplicateArrayItem, snapshotQueryDevtoolsHandle, sortQueryField, splitQueryConfig, stringArrayQueryField, stringifyQueryRouteParts, sumQueryDevtoolsStats, suppressNextQueryStackDevtools, switchQueryCollectionState, switchQueryState, symfonyQueryErrorParser, takeUntilResponse, toQuerySignal, toQuerySubject, tokensNotAvailableInsideAuthAndExec, tombstoneOf, transformArrayResponse, transformExecStateToQueryState, transformGql, transformMethod, transformPaginatedResponse, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray, uncacheableRequestHasAllowCacheParam, uncacheableRequestHasCacheKeyParam, unwrapQuerySyncMessage, v2BuildQueryCacheKey, v2ExtractExpiresInSeconds, v2ShouldCacheQuery, v2ShouldRetryRequest, validateWithQuery, validateWithV2Query, withArgs, withArgsQueryFeatureMissingButRouteIsFunction, withAuthenticationQuery, withAutoRefresh, withAutoRefreshUsedInManualQuery, withAutoRefreshUsedOnUnsupportedHttpMethod, withBearerAuthMultiTabSync, withDefaultRetry, withErrorHandling, withEthleteApiErrors, withHtmlErrorParsing, withInactivityLogout, withLogging, withLongPolling, withLongPollingUsedOnUnsupportedHttpMethod, withLongPollingUsedWithPolling, withMultiTabSync, withPageResetOnError, withPersistentAuth, withPolling, withPollingUsedOnUnsupportedHttpMethod, withQueryDevtoolsOverridePersistence, withQueryPersistence, withRefreshQuery, withResponseUpdate, withSuccessHandling, withSymfonyErrors, withTokenExpirationWarning, withTokenRevocation, withTracking, wrapAsObservableSignal, wrapQuerySyncMessage, writeQueryDevtoolsStore };
|
|
15261
|
+
export { AuthBearerRefreshStrategy, BasicAuthProvider, BearerAuthFeatureType, BooleanArrayQueryField, CustomHeaderAuthProvider, DEFAULT_KEEP_UNUSED_FOR, DEFAULT_QUERY_PERSISTENCE_MAX_AGE, DEFAULT_QUERY_PERSISTENCE_MAX_ENTRIES, DEFAULT_QUERY_PERSISTENCE_VERSION, DEFAULT_QUERY_PERSISTENCE_WRITE_DELAY, DateArrayQueryField, DateQueryField, EMPTY_QUERY_DEVTOOLS_FAULT, EntityStore, IGNORED_FILTER_COUNT_FIELDS, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, LegacyQuery, LegacyQueryCreator, MAX_QUERY_BATCH_TOMBSTONES, MAX_QUERY_DEVTOOLS_TOMBSTONES, MAX_UNUSED_ENTRIES, NumberArrayQueryField, ParseHttpErrorCodeToMessageDePipe, ParseHttpErrorCodeToMessageEnPipe, ParseHttpErrorCodeToTitleDePipe, ParseHttpErrorCodeToTitleEnPipe, QUERY_CLIENT_DEVTOOLS_TOKEN, QUERY_DEVTOOLS_FAULT_STATUSES, QUERY_DEVTOOLS_TOKEN_TTL_LIMIT, QUERY_PERSISTENCE_STORE_VERSION, QUERY_SYNC_PROTOCOL_VERSION, QUERY_VERSION, QueryClientFeatureType, QueryDevtoolsComponent, QueryDirective, QueryFeatureType, QueryField, QueryForm, QueryRuntimeErrorCode, QueryShortNamePipe, QueryStateType, QueryStore, SERVER_ERROR_KIND, SERVER_VIOLATION_ERROR_KIND, SPEED_BUFFER_TIME_IN_MS, SearchQueryField, SortQueryField, StringArrayQueryField, V2BearerAuthProvider, V2Query, V2QueryClient, V2QueryCreator, addQueryContainerHandling, applyQueryDevtoolsOverrides, applyQueryDevtoolsTokenTtl, applyQueryFeatures, armAllQueryDevtoolsMocks, armQueryDevtoolsMock, armQueryDevtoolsOverrideTransfer, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, booleanArrayQueryField, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, canOverrideQueryDevtoolsTokenTtl, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, clearQueryDevtoolsArmedMocks, clearQueryDevtoolsFaults, clearQueryDevtoolsMockStore, clearQueryDevtoolsOverrideStore, clearQueryDevtoolsStore, clearQueryDevtoolsTokenTtl, clearQueryDevtoolsTombstones, clearRestoredQueryDevtoolsOverrides, collectLeafPaths, collectQueryDevtoolsSchemaComponents, collectQueryFormLinks, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, consumeSuppressQueryStackDevtools, contentfulGqlLikePaginationAdapter, countUnresolvedQueryDevtoolsOverrides, createAuthGuard, createBaseQuery, createBaseQueryCreator, createBearerAuthProvider, createDefaultRetryFn, createDeleteQuery, createExecuteFn, createGetQuery, createGqlExecuteFn, createGqlMutationViaGet, createGqlMutationViaPost, createGqlQuery, createGqlQueryCreator, createGqlQueryViaGet, createGqlQueryViaPost, createHttpRequest, createIndexedDbQueryPersistenceAdapter, createInfinityQueryConfig, createLegacyQueryCreator, createNoopQueryPersistenceAdapter, createPagedQueryStack, createPatchQuery, createPersistentAuthFeature, createPostQuery, createPutQuery, createQuery, createQueryBatch, createQueryClient, createQueryCollection, createQueryCollectionSignal, createQueryCollectionSubject, createQueryContext, createQueryCreator, createQueryDevtoolsFormLinks, createQueryDevtoolsFormLinksRecorder, createQueryDevtoolsOverrides, createQueryDevtoolsOverridesRecorder, createQueryDevtoolsStats, createQueryDevtoolsStatsRecorder, createQueryErrorResponse, createQueryFeature, createQueryInvalidationFilter, createQueryKeyLockManager, createQueryObject, createQueryPersistenceEngine, createQueryRepository, createQuerySnapshotFn, createQueryStack, createQuerySubmission, createQuerySyncEngine, createQuerySyncTransport, createSecureDeleteQuery, createSecureExecuteFactory, createSecureExecuteFn, createSecureGetQuery, createSecureGqlExecuteFn, createSecureGqlMutationViaGet, createSecureGqlMutationViaPost, createSecureGqlQuery, createSecureGqlQueryCreator, createSecureGqlQueryViaGet, createSecureGqlQueryViaPost, createSecurePatchQuery, createSecurePostQuery, createSecurePutQuery, createSecureQuery, createSecureQueryCreator, createTrackingFeature, createWebSocketClient, currentQueryDevtoolsBatch, dateArrayQueryField, dateQueryField, decryptBearer, deepFreeze, def, defineQueryForm, deleteQueryDevtoolsMock, describeQueryDevtoolsFeatures, detectContentTypeHeader, detectPaginationShape, dynLikePaginationAdapter, effectComputed, emptyQueryArgs, ethletePaginationAdapter, executeUntilSettled, extractExpiresInSeconds, extractFormViolations, extractHtmlErrorMessage, extractQuery, fakePaginationAdapter, filterFailure, filterNull, filterQueryStates, filterSuccess, forEachHeader, formatQueryDevtoolsDuration, generateQueryDevtoolsNumberPreset, generateQueryDevtoolsSampleNumber, generateQueryDevtoolsStringPreset, getBearerAuthProviderName, getDefaultHeaders, getQueryClientName, getQueryFeatureUsage, getResponseUrl, ggLikePaginationAdapter, gql, gqlDataPropertyMissingInResponse, hasHeader, hasQueryDevtoolsOverridesAtPath, htmlErrorPayload, htmlQueryErrorParser, ignoreAutoRefresh, initQueryDevtoolsFaults, initQueryDevtoolsMocks, initQueryDevtoolsOverridePersistence, initQueryDevtoolsSettings, injectInfinityQueryResponseDelay, injectQueryContext, insertFrom, invalidBaseRouteError, invalidBodyError, invalidRouteError, invalidStateInsideSecureExecuteFactory, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isClassValidatorError, isCreateGqlQueryOptions, isCustomHeaderAuthProvider, isDateShapedLeaf, isEmptyString, isGqlQueryConfig, isHtmlErrorPayload, isLegacyQuery, isNaN$1 as isNaN, isPageOutOfRangeError, isQuery, isQueryCollection, isQueryDevtoolsEnabled, isQueryDevtoolsFaultArmed, isQueryDevtoolsRequestInterceptionEnabled, isQueryErrorResponse, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyFormViolationListError, isSymfonyListError, isSymfonyPagerfantaOutOfRangeError, isUnderInvalidatedUrl, legacyPrepareFallbackInjector, legacyPrepareWithoutInjectionContext, loadQueryDevtoolsSchema, mapToPaginated, mapViolationsToFormErrors, matchesQueryDevtoolsMockPattern, matchesQueryDevtoolsMockQuery, maybeExecute, measureQueryDevtoolsPayload, mergeHeaders, nestedEffect, noteQueryFormRead, numberArrayQueryField, pagedQueryStackNextPageCalledWithoutPreviousPage, pagedQueryStackPageBiggerThanTotalPages, pagedQueryStackPreviousPageCalledButAlreadyAtFirstPage, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, parseHttpErrorCodeToMessageDe, parseHttpErrorCodeToMessageEn, parseHttpErrorCodeToTitleDe, parseHttpErrorCodeToTitleEn, parseQueryDevtoolsOverrideTransfer, parseQueryRoute, patchQueryDevtoolsTokenPayload, pathParamsMissingInRouteFunctionError, provideInfinityQueryResponseDelay, provideLegacyPrepareFallback, provideQueryClientForDevtools, provideQueryDevtools, queryArrayComputed, queryBatchAlreadyRunning, queryBatchWithArgsUsed, queryClientFeatureUsedMultipleTimes, queryComputed, queryComputedTillTruthy, queryDevtoolsAbout, queryDevtoolsArmedMocks, queryDevtoolsArmedMocksRestored, queryDevtoolsEntries, queryDevtoolsFaults, queryDevtoolsFaultsRestored, queryDevtoolsFnDetail, queryDevtoolsMockId, queryDevtoolsMocks, queryDevtoolsOverridePersistence, queryDevtoolsRequestPath, queryDevtoolsResponseHistory, queryDevtoolsRestoredOverridesScope, queryDevtoolsSchemaNames, queryDevtoolsSchemaRoutes, queryDevtoolsSchemaState, queryDevtoolsSettings, queryDevtoolsStorage, queryDevtoolsTokenTtls, queryErrorMessage, queryErrorMessages, queryExecute, queryFeatureUsedMultipleTimes, queryField, querySequence, querySequenceAlreadyRunning, queryStackTotalQueriesAndExpectedQueriesMismatch, queryStackWithArgsUsed, queryStackWithResponseUpdateUsed, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, queryStateErrorSignal, queryStateLoadingSignal, queryStateResponseSignal, queryStateSignal, readQueryDevtoolsStore, registerEthleteVersion, registerQueryDevtoolsEntry, registerQueryErrorParser, removeFrom, request, resetExecuteState, resetPageOnError, resolveInvalidationUrl, resolveQueryDevtoolsFault, resolveQueryDevtoolsFaultForAttempt, resolveQueryDevtoolsMock, resolveQueryDevtoolsMockForAttempt, restoredQueryDevtoolsOverrides, runDefaultQueryRetry, runInQueryDevtoolsBatch, runQueryErrorParsers, saveQueryDevtoolsMock, searchQueryField, seedQueryDevtoolsSchemaBody, seedQueryDevtoolsSchemaRoute, serializeBody, serializeQueryDevtoolsOverrideTransfer, setDefaultQueryRetryFn, setQueryDevtoolsAppInfo, setQueryDevtoolsArmedMocksScope, setQueryDevtoolsFault, setQueryDevtoolsFaultResolver, setQueryDevtoolsFaultsScope, setQueryDevtoolsFormLinksFactory, setQueryDevtoolsMockResolver, setQueryDevtoolsOverridePersistence, setQueryDevtoolsOverridesFactory, setQueryDevtoolsOverridesScope, setQueryDevtoolsRegistrar, setQueryDevtoolsResponseHistory, setQueryDevtoolsSchemaLoader, setQueryDevtoolsSettings, setQueryDevtoolsStatsFactory, setQueryDevtoolsTokenPayloadPatcher, setQueryDevtoolsTokenTtl, setupQueryDependencies, setupQueryExecuteState, setupQueryState, shouldAutoExecuteGqlQuery, shouldAutoExecuteQuery, shouldCacheQuery, shouldRetryRequest, silenceMissingWithArgsFeatureErrorUsedButWithArgsPresent, skipPaginationPageParamCalculator, smartDuplicateArrayItem, snapshotQueryDevtoolsHandle, sortQueryField, splitQueryConfig, stringArrayQueryField, stringifyQueryRouteParts, sumQueryDevtoolsStats, suppressNextQueryStackDevtools, switchQueryCollectionState, switchQueryState, symfonyQueryErrorParser, takeUntilResponse, toQuerySignal, toQuerySubject, tokensNotAvailableInsideAuthAndExec, tombstoneOf, transformArrayResponse, transformExecStateToQueryState, transformGql, transformMethod, transformPaginatedResponse, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray, uncacheableRequestHasAllowCacheParam, uncacheableRequestHasCacheKeyParam, unwrapQuerySyncMessage, v2BuildQueryCacheKey, v2ExtractExpiresInSeconds, v2ShouldCacheQuery, v2ShouldRetryRequest, validateWithQuery, validateWithV2Query, withArgs, withArgsQueryFeatureMissingButRouteIsFunction, withAuthenticationQuery, withAutoRefresh, withAutoRefreshUsedInManualQuery, withAutoRefreshUsedOnUnsupportedHttpMethod, withBearerAuthMultiTabSync, withDefaultRetry, withErrorHandling, withEthleteApiErrors, withHtmlErrorParsing, withInactivityLogout, withLogging, withLongPolling, withLongPollingUsedOnUnsupportedHttpMethod, withLongPollingUsedWithPolling, withMultiTabSync, withPageResetOnError, withPersistentAuth, withPolling, withPollingUsedOnUnsupportedHttpMethod, withQueryDevtoolsOverridePersistence, withQueryPersistence, withRefreshQuery, withResponseUpdate, withSuccessHandling, withSymfonyErrors, withTokenExpirationWarning, withTokenRevocation, withTracking, wrapAsObservableSignal, wrapQuerySyncMessage, writeQueryDevtoolsStore };
|
|
15018
15262
|
//# sourceMappingURL=ethlete-query.mjs.map
|