@ethlete/query 6.0.0-next.23 → 6.0.0-next.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +62 -0
- package/fesm2022/ethlete-query-testing.mjs +46 -1
- package/fesm2022/ethlete-query-testing.mjs.map +1 -1
- package/fesm2022/ethlete-query.mjs +1374 -138
- package/fesm2022/ethlete-query.mjs.map +1 -1
- package/generators/deprecate-legacy-queries/migration.js +77 -0
- package/generators/deprecate-legacy-queries/schema.json +26 -0
- package/generators/generators.json +5 -0
- package/generators/migrate-to-query-v3/legacy-prepare-migration.js +111 -18
- package/generators/migrate-to-query-v3/legacy-query-creator-migration.js +2 -2
- package/generators/migrate-to-query-v3/shared.js +43 -0
- package/package.json +1 -5
- package/types/ethlete-query-testing.d.ts +42 -3
- package/types/ethlete-query.d.ts +1253 -16
|
@@ -1,16 +1,54 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { DestroyRef, InjectionToken, inject, Injector, EnvironmentInjector, ElementRef, ErrorHandler, createEnvironmentInjector, effect, untracked, signal, linkedSignal, computed, runInInjectionContext, isDevMode, PLATFORM_ID, resource, DOCUMENT, makeEnvironmentProviders, assertInInjectionContext, ChangeDetectorRef, ViewContainerRef, TemplateRef, Input, Directive, input, Pipe, ViewEncapsulation, Component, NgZone } from '@angular/core';
|
|
2
|
+
import { DestroyRef, InjectionToken, inject, Injector, EnvironmentInjector, ElementRef, ErrorHandler, createEnvironmentInjector, effect, untracked, signal, linkedSignal, computed, runInInjectionContext, isDevMode, PLATFORM_ID, resource, DOCUMENT, makeEnvironmentProviders, assertInInjectionContext, provideEnvironmentInitializer, ChangeDetectorRef, ViewContainerRef, TemplateRef, Input, Directive, input, Pipe, ViewEncapsulation, Component, NgZone } from '@angular/core';
|
|
3
3
|
import { defineStaticProvider, RuntimeError, clamp, randomId, defineRootProvider, isObject, injectUnsavedChangesCoordinator, injectRoute, getCookie, getDomain, setCookie, deleteCookie, createDestroy, computedTillTruthy, defineProvider, toProvideFn, toInjectFn, nextFrame, injectQueryParams, injectQueryParamChanges, clone, equal, ET_PROPERTY_REMOVED, previousSignalValue } from '@ethlete/core';
|
|
4
|
-
import { filter, Subject, Subscription,
|
|
5
|
-
import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
4
|
+
import { filter, Subject, Subscription, defer, throwError, timer, switchMap, tap, retry, catchError, take, of, firstValueFrom, merge, fromEvent, throttleTime, interval, combineLatest, map, Observable, takeUntil, startWith, pairwise, BehaviorSubject, ReplaySubject, shareReplay, skip, takeWhile, EMPTY, withLatestFrom, debounceTime } from 'rxjs';
|
|
6
5
|
import { HttpClient, HttpEventType, HttpErrorResponse, HttpHeaders, HttpStatusCode } from '@angular/common/http';
|
|
6
|
+
import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
7
7
|
import { getActiveConsumer, setActiveConsumer } from '@angular/core/primitives/signals';
|
|
8
8
|
import { isPlatformBrowser, NgClass, AsyncPipe, JsonPipe } from '@angular/common';
|
|
9
9
|
import { validateAsync, form } from '@angular/forms/signals';
|
|
10
10
|
import * as i1 from '@angular/forms';
|
|
11
11
|
import { FormControl, ReactiveFormsModule, FormGroup } from '@angular/forms';
|
|
12
12
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Turns the features applied at creation into their devtools representation.
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
const describeQueryDevtoolsFeatures = (features) => features?.map((feature) => ({ type: feature.type, details: feature.devtools?.() ?? [] })) ?? [];
|
|
19
|
+
/**
|
|
20
|
+
* Renders a millisecond duration the way feature details spell one out - `500ms`, `1.5s`, `15m`.
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
const formatQueryDevtoolsDuration = (ms) => {
|
|
24
|
+
if (!Number.isFinite(ms))
|
|
25
|
+
return String(ms);
|
|
26
|
+
if (ms < 1000)
|
|
27
|
+
return `${ms}ms`;
|
|
28
|
+
const round = (value, unit) => `${Number(value.toFixed(1))}${unit}`;
|
|
29
|
+
if (ms < 60_000)
|
|
30
|
+
return round(ms / 1000, 's');
|
|
31
|
+
if (ms < 3_600_000)
|
|
32
|
+
return round(ms / 60_000, 'm');
|
|
33
|
+
return round(ms / 3_600_000, 'h');
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* The name of a function passed as `options.<key>`, or `null` when it is an inline lambda. An inline
|
|
37
|
+
* `{ handler: (e) => … }` inherits the name `handler` from the key it is assigned to, which tells the
|
|
38
|
+
* reader nothing - a reference to a declared function does.
|
|
39
|
+
*/
|
|
40
|
+
const queryDevtoolsFnName = (fn, key) => {
|
|
41
|
+
const name = typeof fn === 'function' ? fn.name.replace(/^bound /, '') : '';
|
|
42
|
+
return !name || name === key ? null : name;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* A detail for the function passed as `options.<key>`, omitted when it is an inline lambda.
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
const queryDevtoolsFnDetail = (fn, key) => {
|
|
49
|
+
const name = queryDevtoolsFnName(fn, key);
|
|
50
|
+
return name ? [{ label: key, value: name }] : [];
|
|
51
|
+
};
|
|
14
52
|
|
|
15
53
|
const noop$2 = () => undefined;
|
|
16
54
|
let registrar = null;
|
|
@@ -33,6 +71,85 @@ const isQueryDevtoolsEnabled = () => registrar !== null;
|
|
|
33
71
|
* @internal
|
|
34
72
|
*/
|
|
35
73
|
const registerQueryDevtoolsEntry = (entry) => registrar?.(entry) ?? noop$2;
|
|
74
|
+
let statsFactory = null;
|
|
75
|
+
/**
|
|
76
|
+
* Installs the stats recorder factory. Called by `provideQueryDevtools()`; nothing else may call it.
|
|
77
|
+
* @internal
|
|
78
|
+
*/
|
|
79
|
+
const setQueryDevtoolsStatsFactory = (fn) => {
|
|
80
|
+
statsFactory = fn;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* A stats recorder for one entry, or `null` unless {@link provideQueryDevtools} has been called.
|
|
84
|
+
*
|
|
85
|
+
* Instrumentation sites must go through this instead of importing `createQueryDevtoolsStats`: a static
|
|
86
|
+
* import pins the whole stats module (~1.4 kB) into every bundle that touches a query, and a runtime
|
|
87
|
+
* `isQueryDevtoolsEnabled()` guard at the call site does not undo that. Reached only from the provider,
|
|
88
|
+
* it is dead code in an app without devtools.
|
|
89
|
+
* @internal
|
|
90
|
+
*/
|
|
91
|
+
const createQueryDevtoolsStatsRecorder = () => statsFactory?.() ?? null;
|
|
92
|
+
let formLinksFactory = null;
|
|
93
|
+
/**
|
|
94
|
+
* Installs the form-links recorder factory. Called by `provideQueryDevtools()`; nothing else may call it.
|
|
95
|
+
* @internal
|
|
96
|
+
*/
|
|
97
|
+
const setQueryDevtoolsFormLinksFactory = (fn) => {
|
|
98
|
+
formLinksFactory = fn;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* A form-links recorder for one query, or `null` unless {@link provideQueryDevtools} has been called.
|
|
102
|
+
* Reached only from the provider for the same reason {@link createQueryDevtoolsStatsRecorder} is.
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
105
|
+
const createQueryDevtoolsFormLinksRecorder = () => formLinksFactory?.() ?? null;
|
|
106
|
+
/** The ids of the query forms read by the args build currently running, or `null` outside of one. */
|
|
107
|
+
let formLinkSink = null;
|
|
108
|
+
/**
|
|
109
|
+
* Runs `build` and reports which query forms it read. Nested builds are supported - the outer one
|
|
110
|
+
* resumes collecting once the inner one is done.
|
|
111
|
+
* @internal
|
|
112
|
+
*/
|
|
113
|
+
const collectQueryFormLinks = (build) => {
|
|
114
|
+
const outer = formLinkSink;
|
|
115
|
+
const sink = new Set();
|
|
116
|
+
formLinkSink = sink;
|
|
117
|
+
try {
|
|
118
|
+
return { value: build(), ids: [...sink] };
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
formLinkSink = outer;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Records that a query form's committed value was read. The form calls this from its `value` signal, so
|
|
126
|
+
* a read that happens while a query builds its args is what links the two - no naming convention, and
|
|
127
|
+
* nothing to keep in sync when the args change.
|
|
128
|
+
* @internal
|
|
129
|
+
*/
|
|
130
|
+
const noteQueryFormRead = (id) => {
|
|
131
|
+
formLinkSink?.add(id);
|
|
132
|
+
};
|
|
133
|
+
let faultResolver = null;
|
|
134
|
+
/**
|
|
135
|
+
* Installs the fault resolver. Called by `provideQueryDevtools()`; nothing else may call it.
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
const setQueryDevtoolsFaultResolver = (fn) => {
|
|
139
|
+
faultResolver = fn;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Whether fault injection can do anything at all. Checked before building the wrapper that resolves a
|
|
143
|
+
* fault per attempt, so a request in an app without devtools keeps the pipeline it always had.
|
|
144
|
+
* @internal
|
|
145
|
+
*/
|
|
146
|
+
const isQueryDevtoolsFaultInjectionEnabled = () => faultResolver !== null;
|
|
147
|
+
/**
|
|
148
|
+
* Resolves the fault to apply to one upcoming attempt, or `null` when nothing is armed. Consumes a
|
|
149
|
+
* `failNext` budget, so call it exactly once per attempt.
|
|
150
|
+
* @internal
|
|
151
|
+
*/
|
|
152
|
+
const resolveQueryDevtoolsFault = (target) => faultResolver?.(target) ?? null;
|
|
36
153
|
let suppressStackRegistration = false;
|
|
37
154
|
/**
|
|
38
155
|
* Suppresses devtools registration for the next {@link createQueryStack} call. Used by
|
|
@@ -230,12 +347,15 @@ const invalidStateInsideSecureExecuteFactory = () => {
|
|
|
230
347
|
const circularQueryDependency = () => {
|
|
231
348
|
return new RuntimeError(QueryRuntimeErrorCode.CIRCULAR_QUERY_DEPENDENCY, `Query was executed more than 5 times in less than 100ms. This is usually a sign of a circular dependency.`);
|
|
232
349
|
};
|
|
233
|
-
const legacyPrepareWithoutInjectionContext = (creatorName) => {
|
|
350
|
+
const legacyPrepareWithoutInjectionContext = (creatorName, method = 'prepare') => {
|
|
234
351
|
const label = creatorName ? `"${creatorName}"` : 'A legacy query creator';
|
|
235
|
-
|
|
352
|
+
const example = method === 'prepare'
|
|
353
|
+
? ` search = (term: string) => myQuery.prepare({ queryParams: { term }, injector: this.injector });`
|
|
354
|
+
: ` container = myQuery.${method}(null, { injector: this.injector });`;
|
|
355
|
+
return new RuntimeError(QueryRuntimeErrorCode.LEGACY_PREPARE_WITHOUT_INJECTION_CONTEXT, `${label}.${method}() was called outside of an injection context. Unlike the v2 client, the legacy interop layer needs an injector to build the underlying query.\n\n` +
|
|
236
356
|
`Capture one where a context does exist (field initializer, constructor) and pass it along:\n\n` +
|
|
237
357
|
` private injector = inject(Injector);\n` +
|
|
238
|
-
|
|
358
|
+
`${example}\n\n` +
|
|
239
359
|
`Prefer an injector that outlives the call site. A component injector passed from a callback that can still fire after the component is gone leaves prepare() with a destroyed injector, which returns an inert query instead of executing.`);
|
|
240
360
|
};
|
|
241
361
|
const querySequenceAlreadyRunning = () => {
|
|
@@ -322,7 +442,7 @@ const withArgs = (args) => {
|
|
|
322
442
|
// auto-refresh) always sees the latest value with no pending-effect window. Sentinels are
|
|
323
443
|
// resolved here: CLEAR -> null, `null` ("don't change") -> keep the previous value.
|
|
324
444
|
let previous = null;
|
|
325
|
-
|
|
445
|
+
const resolve = () => {
|
|
326
446
|
const value = args();
|
|
327
447
|
if (value === CLEAR_QUERY_ARGS) {
|
|
328
448
|
previous = null;
|
|
@@ -332,7 +452,12 @@ const withArgs = (args) => {
|
|
|
332
452
|
return previous;
|
|
333
453
|
previous = value;
|
|
334
454
|
return value;
|
|
335
|
-
}
|
|
455
|
+
};
|
|
456
|
+
// Only ever non-null while the devtools are installed. Wrapping the source (rather than reading
|
|
457
|
+
// `state.args` from the outside) is what puts the tracking window around the *evaluation* of the
|
|
458
|
+
// args - a cached read of the computed runs nothing and would record no form at all.
|
|
459
|
+
const formLinks = context.state.subtle.devtoolsFormLinks;
|
|
460
|
+
context.state.subtle.setArgsSource(formLinks ? () => formLinks.track(resolve) : resolve);
|
|
336
461
|
// Trigger (auto-)execution whenever the resolved args change.
|
|
337
462
|
nestedEffect(() => {
|
|
338
463
|
const currArgsNow = context.state.args();
|
|
@@ -362,6 +487,10 @@ const withArgs = (args) => {
|
|
|
362
487
|
const withPolling = (options) => {
|
|
363
488
|
return createQueryFeature({
|
|
364
489
|
type: QueryFeatureType.WITH_POLLING,
|
|
490
|
+
devtools: () => [
|
|
491
|
+
{ label: 'interval', value: formatQueryDevtoolsDuration(options.interval) },
|
|
492
|
+
{ label: 'execute initially', value: options.executeInitially ? 'yes' : 'no' },
|
|
493
|
+
],
|
|
365
494
|
fn: (context) => {
|
|
366
495
|
if (!context.flags.shouldAutoExecuteMethod) {
|
|
367
496
|
throw withPollingUsedOnUnsupportedHttpMethod(context.flags.method);
|
|
@@ -428,6 +557,7 @@ const withPolling = (options) => {
|
|
|
428
557
|
const withLogging = (options) => {
|
|
429
558
|
return createQueryFeature({
|
|
430
559
|
type: QueryFeatureType.WITH_LOGGING,
|
|
560
|
+
devtools: () => queryDevtoolsFnDetail(options.logFn, 'logFn'),
|
|
431
561
|
fn: (context) => {
|
|
432
562
|
context.state.events$.pipe(takeUntilDestroyed(context.deps.destroyRef)).subscribe((event) => {
|
|
433
563
|
options.logFn(event);
|
|
@@ -439,6 +569,7 @@ const withLogging = (options) => {
|
|
|
439
569
|
const withErrorHandling = (options) => {
|
|
440
570
|
return createQueryFeature({
|
|
441
571
|
type: QueryFeatureType.WITH_ERROR_HANDLING,
|
|
572
|
+
devtools: () => queryDevtoolsFnDetail(options.handler, 'handler'),
|
|
442
573
|
fn: (context) => {
|
|
443
574
|
context.state.events$
|
|
444
575
|
.pipe(filter((event) => event.type === 'error'), takeUntilDestroyed(context.deps.destroyRef))
|
|
@@ -452,6 +583,7 @@ const withErrorHandling = (options) => {
|
|
|
452
583
|
const withSuccessHandling = (options) => {
|
|
453
584
|
return createQueryFeature({
|
|
454
585
|
type: QueryFeatureType.WITH_SUCCESS_HANDLING,
|
|
586
|
+
devtools: () => queryDevtoolsFnDetail(options.handler, 'handler'),
|
|
455
587
|
fn: (context) => {
|
|
456
588
|
context.state.events$
|
|
457
589
|
.pipe(filter((event) => event.type === HttpEventType.Response), takeUntilDestroyed(context.deps.destroyRef))
|
|
@@ -469,6 +601,10 @@ const withSuccessHandling = (options) => {
|
|
|
469
601
|
const withAutoRefresh = (options) => {
|
|
470
602
|
return createQueryFeature({
|
|
471
603
|
type: QueryFeatureType.WITH_AUTO_REFRESH,
|
|
604
|
+
devtools: () => [
|
|
605
|
+
{ label: 'signals', value: String(options.onSignalChanges.length) },
|
|
606
|
+
...(options.ignoreOnlyManualExecution ? [{ label: 'ignores manual only', value: 'yes' }] : []),
|
|
607
|
+
],
|
|
472
608
|
fn: (context) => {
|
|
473
609
|
if (!context.flags.shouldAutoExecuteMethod) {
|
|
474
610
|
throw withAutoRefreshUsedOnUnsupportedHttpMethod(context.flags.method);
|
|
@@ -495,6 +631,7 @@ const withAutoRefresh = (options) => {
|
|
|
495
631
|
const withResponseUpdate = (options) => {
|
|
496
632
|
return createQueryFeature({
|
|
497
633
|
type: QueryFeatureType.WITH_RESPONSE_UPDATE,
|
|
634
|
+
devtools: () => queryDevtoolsFnDetail(options.updater, 'updater'),
|
|
498
635
|
fn: (context) => {
|
|
499
636
|
nestedEffect(() => {
|
|
500
637
|
const currentResponse = untracked(() => context.state.response());
|
|
@@ -545,6 +682,11 @@ const withPageResetOnError = (options) => {
|
|
|
545
682
|
const matches = options.when ?? isPageOutOfRangeError;
|
|
546
683
|
return createQueryFeature({
|
|
547
684
|
type: QueryFeatureType.WITH_PAGE_RESET_ON_ERROR,
|
|
685
|
+
devtools: () => [
|
|
686
|
+
{ label: 'resets', value: options.reset ? 'custom callback' : 'page signal' },
|
|
687
|
+
...(options.reset ? [] : [{ label: 'reset to', value: String(options.resetTo ?? 1) }]),
|
|
688
|
+
{ label: 'when', value: options.when ? 'custom' : 'page out of range' },
|
|
689
|
+
],
|
|
548
690
|
fn: (context) => {
|
|
549
691
|
context.state.events$
|
|
550
692
|
.pipe(filter((event) => event.type === 'error'), takeUntilDestroyed(context.deps.destroyRef))
|
|
@@ -624,7 +766,10 @@ const setupQueryState = (options) => {
|
|
|
624
766
|
error: currentError,
|
|
625
767
|
};
|
|
626
768
|
}
|
|
627
|
-
else if (currentResponse) {
|
|
769
|
+
else if (currentResponse !== null || latestHttpEvent()?.type === HttpEventType.Response) {
|
|
770
|
+
// A response event having arrived is what makes the execution a success, not a truthy body: a 204 (or any
|
|
771
|
+
// other empty payload) sets `response` to `null`, which would otherwise be indistinguishable from a query
|
|
772
|
+
// that never ran - leaving `filterSuccess`, `onSuccess` and the success handlers waiting forever.
|
|
628
773
|
return {
|
|
629
774
|
type: 'success',
|
|
630
775
|
response: currentResponse,
|
|
@@ -651,6 +796,8 @@ const setupQueryState = (options) => {
|
|
|
651
796
|
rawResponse,
|
|
652
797
|
bindRequestEvents,
|
|
653
798
|
setArgsSource,
|
|
799
|
+
devtoolsStats: options.devtoolsStats ?? null,
|
|
800
|
+
devtoolsFormLinks: options.devtoolsFormLinks ?? null,
|
|
654
801
|
},
|
|
655
802
|
};
|
|
656
803
|
return state;
|
|
@@ -824,8 +971,12 @@ const createBaseQuery = (options) => {
|
|
|
824
971
|
queryConfig: options.queryConfig,
|
|
825
972
|
});
|
|
826
973
|
return runInInjectionContext(deps.injector, () => {
|
|
974
|
+
const devtoolsStats = createQueryDevtoolsStatsRecorder();
|
|
975
|
+
const devtoolsFormLinks = createQueryDevtoolsFormLinksRecorder();
|
|
827
976
|
const state = setupQueryState({
|
|
828
977
|
transformResponse: options.creator?.transformResponse,
|
|
978
|
+
devtoolsStats,
|
|
979
|
+
devtoolsFormLinks,
|
|
829
980
|
});
|
|
830
981
|
const flags = getQueryFeatureUsage(options);
|
|
831
982
|
const execute = options.executeFactory({
|
|
@@ -844,18 +995,40 @@ const createBaseQuery = (options) => {
|
|
|
844
995
|
applyQueryFeatures(options.features, featureFnContext);
|
|
845
996
|
maybeExecute({ execute, flags });
|
|
846
997
|
const query = createQueryObject({ state, execute, deps });
|
|
847
|
-
|
|
998
|
+
// Only ever non-null while the devtools are installed, so this whole block - the entry and the
|
|
999
|
+
// per-response payload measuring behind it - is dead code in an app without them.
|
|
1000
|
+
if (devtoolsStats) {
|
|
1001
|
+
const statsSubscription = state.events$.subscribe((event) => {
|
|
1002
|
+
if (event.type === 'error') {
|
|
1003
|
+
devtoolsStats.recordError();
|
|
1004
|
+
}
|
|
1005
|
+
else if (event.type === HttpEventType.Response) {
|
|
1006
|
+
devtoolsStats.recordResponse({ headers: event.headers, body: event.body });
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
deps.destroyRef.onDestroy(() => statsSubscription.unsubscribe());
|
|
1010
|
+
// A retry happens inside the request, which is shared by every query hitting the same cache key -
|
|
1011
|
+
// so the recorder reads it off the request instead of being handed down into one. `recordRetry` is
|
|
1012
|
+
// idempotent per attempt, which is what makes reading a signal a safe way to count them.
|
|
1013
|
+
effect(() => {
|
|
1014
|
+
const retry = state.subtle.request()?.subtle.retryState();
|
|
1015
|
+
if (retry)
|
|
1016
|
+
devtoolsStats.recordRetry({ attempt: retry.attempt });
|
|
1017
|
+
});
|
|
848
1018
|
const unregister = registerQueryDevtoolsEntry({
|
|
849
1019
|
kind: 'query',
|
|
850
1020
|
handle: query,
|
|
851
1021
|
clientRef: client,
|
|
1022
|
+
stats: devtoolsStats,
|
|
1023
|
+
formLinks: devtoolsFormLinks ?? undefined,
|
|
852
1024
|
route: options.creatorInternals.route ??
|
|
853
1025
|
options.creator?.route ??
|
|
854
1026
|
null,
|
|
1027
|
+
authProviderRef: options.creatorInternals.authProvider,
|
|
855
1028
|
meta: {
|
|
856
1029
|
clientBaseUrl: deps.client.baseUrl,
|
|
857
1030
|
method: flags.method,
|
|
858
|
-
|
|
1031
|
+
features: describeQueryDevtoolsFeatures(options.features),
|
|
859
1032
|
queryConfig: options.queryConfig,
|
|
860
1033
|
creator: options.creator,
|
|
861
1034
|
repository: deps.client.repository,
|
|
@@ -890,7 +1063,7 @@ const setupQueryExecuteState = () => {
|
|
|
890
1063
|
const queryExecute = (options) => {
|
|
891
1064
|
const { executeOptions, args, executeState, options: runQueryOptions, isSecure } = options;
|
|
892
1065
|
const { deps, state, creator, creatorInternals, queryConfig } = executeOptions;
|
|
893
|
-
const { key, request } = deps.client.repository.request({
|
|
1066
|
+
const { key, request, executed } = deps.client.repository.request({
|
|
894
1067
|
route: creatorInternals.route,
|
|
895
1068
|
method: creatorInternals.method,
|
|
896
1069
|
args,
|
|
@@ -908,6 +1081,7 @@ const queryExecute = (options) => {
|
|
|
908
1081
|
state.lastTriggeredBy.set(runQueryOptions?.triggeredBy ?? null);
|
|
909
1082
|
state.subtle.request.set(request);
|
|
910
1083
|
state.subtle.bindRequestEvents(request);
|
|
1084
|
+
state.subtle.devtoolsStats?.recordExecution({ didRequest: executed, body: args?.body, url: request.url });
|
|
911
1085
|
};
|
|
912
1086
|
const circularQueryDependencyChecker = () => {
|
|
913
1087
|
let lastTriggerTs = 0;
|
|
@@ -1009,6 +1183,10 @@ const createBaseQueryCreator = (config) => {
|
|
|
1009
1183
|
options: { ...config.options, ...additionalOptions },
|
|
1010
1184
|
});
|
|
1011
1185
|
};
|
|
1186
|
+
queryCreator.subtle = {
|
|
1187
|
+
creatorInternals: config.internals,
|
|
1188
|
+
creatorOptions: config.options,
|
|
1189
|
+
};
|
|
1012
1190
|
return queryCreator;
|
|
1013
1191
|
};
|
|
1014
1192
|
|
|
@@ -1341,6 +1519,12 @@ const createHttpRequest = (options) => {
|
|
|
1341
1519
|
...(ngDevMode ? [{ debugName: "lastExecuteTime" }] : /* istanbul ignore next */ []));
|
|
1342
1520
|
const expiresIn = signal(null, /* @ts-ignore */
|
|
1343
1521
|
...(ngDevMode ? [{ debugName: "expiresIn" }] : /* istanbul ignore next */ []));
|
|
1522
|
+
const attempts = signal(1, /* @ts-ignore */
|
|
1523
|
+
...(ngDevMode ? [{ debugName: "attempts" }] : /* istanbul ignore next */ []));
|
|
1524
|
+
const retryState = signal(null, /* @ts-ignore */
|
|
1525
|
+
...(ngDevMode ? [{ debugName: "retryState" }] : /* istanbul ignore next */ []));
|
|
1526
|
+
const lastDurationMs = signal(null, /* @ts-ignore */
|
|
1527
|
+
...(ngDevMode ? [{ debugName: "lastDurationMs" }] : /* istanbul ignore next */ []));
|
|
1344
1528
|
// NOTE: This must be a plain function, not a `computed`. The freshness check compares against
|
|
1345
1529
|
// `Date.now()`, which is not reactive, so a memoized computed would only ever recompute when
|
|
1346
1530
|
// `expiresIn` changes - once it evaluated to `false` (fresh) it would stay `false` forever, even
|
|
@@ -1362,26 +1546,68 @@ const createHttpRequest = (options) => {
|
|
|
1362
1546
|
// client-level one instead of being appended next to it.
|
|
1363
1547
|
return argHeaders.keys().reduce((merged, key) => merged.set(key, argHeaders.getAll(key) ?? []), clientHeaders);
|
|
1364
1548
|
};
|
|
1549
|
+
const send = (headers) => dependencies.httpClient.request(options.method, options.fullPath, {
|
|
1550
|
+
observe: 'events',
|
|
1551
|
+
body: args?.body,
|
|
1552
|
+
reportProgress: clientOptions?.reportProgress,
|
|
1553
|
+
withCredentials: clientOptions?.withCredentials,
|
|
1554
|
+
transferCache: clientOptions?.transferCache,
|
|
1555
|
+
responseType: clientOptions?.responseType || 'json',
|
|
1556
|
+
headers,
|
|
1557
|
+
});
|
|
1558
|
+
/**
|
|
1559
|
+
* Wraps the request in the fault the devtools have armed for this client, if any.
|
|
1560
|
+
*
|
|
1561
|
+
* Inside a `defer` so a fault is resolved per subscription rather than per execution - which is what
|
|
1562
|
+
* makes `retry` re-roll it, so an armed "fail the next two attempts" lets the third one through like a
|
|
1563
|
+
* flaky server would. Injected latency delays the attempt rather than its response, so the loading
|
|
1564
|
+
* state genuinely lasts that long and a retry waits it out too.
|
|
1565
|
+
*
|
|
1566
|
+
* A faulted attempt always goes through `timer`, even at zero latency: no real request can fail in the
|
|
1567
|
+
* same tick it was started in, and settling synchronously inside `execute()` would let an injected
|
|
1568
|
+
* failure land before the caller has finished wiring the request up.
|
|
1569
|
+
*/
|
|
1570
|
+
const sendWithFaults = (headers) => defer(() => {
|
|
1571
|
+
const fault = resolveQueryDevtoolsFault({
|
|
1572
|
+
clientName: options.clientName ?? '',
|
|
1573
|
+
method: options.method,
|
|
1574
|
+
url: options.fullPath,
|
|
1575
|
+
});
|
|
1576
|
+
if (!fault)
|
|
1577
|
+
return send(headers);
|
|
1578
|
+
const { status } = fault;
|
|
1579
|
+
const attempt$ = status === null
|
|
1580
|
+
? send(headers)
|
|
1581
|
+
: throwError(() => new HttpErrorResponse({
|
|
1582
|
+
status,
|
|
1583
|
+
statusText: 'Injected by the query devtools',
|
|
1584
|
+
url: options.fullPath,
|
|
1585
|
+
error: { message: `Injected ${status} (query devtools)` },
|
|
1586
|
+
}));
|
|
1587
|
+
return timer(fault.latencyMs).pipe(switchMap(() => attempt$));
|
|
1588
|
+
});
|
|
1365
1589
|
const createStream = () => {
|
|
1366
1590
|
const headers = resolveHeaders();
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
observe: 'events',
|
|
1370
|
-
body: args?.body,
|
|
1371
|
-
reportProgress: clientOptions?.reportProgress,
|
|
1372
|
-
withCredentials: clientOptions?.withCredentials,
|
|
1373
|
-
transferCache: clientOptions?.transferCache,
|
|
1374
|
-
responseType: clientOptions?.responseType || 'json',
|
|
1375
|
-
headers,
|
|
1376
|
-
})
|
|
1377
|
-
.pipe(tap((event) => updateState(event)), retry({
|
|
1591
|
+
const source$ = isQueryDevtoolsFaultInjectionEnabled() ? sendWithFaults(headers) : send(headers);
|
|
1592
|
+
return source$.pipe(tap((event) => updateState(event)), retry({
|
|
1378
1593
|
delay: (error, retryCount) => {
|
|
1379
1594
|
const retryOptions = { error, retryCount };
|
|
1380
1595
|
const retryResult = options.retryFn?.(retryOptions) || runDefaultQueryRetry(retryOptions);
|
|
1381
1596
|
if (!retryResult.retry) {
|
|
1382
1597
|
return throwError(() => error);
|
|
1383
1598
|
}
|
|
1384
|
-
|
|
1599
|
+
// rxjs counts retries from 1, so the attempt this delay leads up to is one further along.
|
|
1600
|
+
const attempt = retryCount + 1;
|
|
1601
|
+
retryState.set({
|
|
1602
|
+
attempt,
|
|
1603
|
+
delayMs: retryResult.delay,
|
|
1604
|
+
startsAt: Date.now() + retryResult.delay,
|
|
1605
|
+
status: error instanceof HttpErrorResponse ? error.status : 0,
|
|
1606
|
+
});
|
|
1607
|
+
return timer(retryResult.delay).pipe(tap(() => {
|
|
1608
|
+
retryState.set(null);
|
|
1609
|
+
attempts.set(attempt);
|
|
1610
|
+
}));
|
|
1385
1611
|
},
|
|
1386
1612
|
}), catchError((e) => {
|
|
1387
1613
|
updateErrorState(e);
|
|
@@ -1396,12 +1622,15 @@ const createHttpRequest = (options) => {
|
|
|
1396
1622
|
currentStreamSubscription.unsubscribe();
|
|
1397
1623
|
lastExecuteTime.set(Date.now());
|
|
1398
1624
|
lastLoadEventTime.set(lastExecuteTime());
|
|
1625
|
+
lastLoadEventAmount.set(0);
|
|
1399
1626
|
loading.set({
|
|
1400
1627
|
executeTime: lastExecuteTime(),
|
|
1401
1628
|
progress: null,
|
|
1402
1629
|
});
|
|
1403
1630
|
error.set(null);
|
|
1404
1631
|
expiresIn.set(null);
|
|
1632
|
+
attempts.set(1);
|
|
1633
|
+
retryState.set(null);
|
|
1405
1634
|
const stream = createStream();
|
|
1406
1635
|
currentStreamSubscription = stream.subscribe({
|
|
1407
1636
|
error: () => {
|
|
@@ -1414,6 +1643,9 @@ const createHttpRequest = (options) => {
|
|
|
1414
1643
|
const destroy = () => {
|
|
1415
1644
|
const wasActive = !currentStreamSubscription.closed;
|
|
1416
1645
|
currentStreamSubscription.unsubscribe();
|
|
1646
|
+
// A request destroyed mid-backoff never runs the attempt it was waiting for, so leaving the state
|
|
1647
|
+
// set would keep a "retrying in …" readout counting down for a request that is gone.
|
|
1648
|
+
retryState.set(null);
|
|
1417
1649
|
event$.complete();
|
|
1418
1650
|
return wasActive;
|
|
1419
1651
|
};
|
|
@@ -1423,6 +1655,7 @@ const createHttpRequest = (options) => {
|
|
|
1423
1655
|
{
|
|
1424
1656
|
loading.set(null);
|
|
1425
1657
|
response.set(event.body);
|
|
1658
|
+
lastDurationMs.set(Date.now() - lastExecuteTime());
|
|
1426
1659
|
const expiresInSeconds = options.cacheAdapter
|
|
1427
1660
|
? options.cacheAdapter(event.headers)
|
|
1428
1661
|
: extractExpiresInSeconds(event.headers);
|
|
@@ -1451,6 +1684,7 @@ const createHttpRequest = (options) => {
|
|
|
1451
1684
|
const errorRes = createQueryErrorResponse(errorResponse);
|
|
1452
1685
|
error.set(errorRes);
|
|
1453
1686
|
loading.set(null);
|
|
1687
|
+
lastDurationMs.set(Date.now() - lastExecuteTime());
|
|
1454
1688
|
const errorEvent = { type: 'error', error: errorRes };
|
|
1455
1689
|
currentEvent.set(errorEvent);
|
|
1456
1690
|
event$.next(errorEvent);
|
|
@@ -1475,15 +1709,21 @@ const createHttpRequest = (options) => {
|
|
|
1475
1709
|
const elapsedTimeSinceLastEvent = currentTime - lastLoadEventTime();
|
|
1476
1710
|
const elapsedTimeSinceLastExecute = currentTime - lastExecuteTime();
|
|
1477
1711
|
const loadedAmount = event.loaded - lastLoadEventAmount();
|
|
1712
|
+
// An event in the same millisecond as the last one, or one that carries no new bytes, has no rate
|
|
1713
|
+
// to report - dividing by either zero yields Infinity or NaN. Such an event also keeps the
|
|
1714
|
+
// baseline where it is, so the next one measures across the wider window instead of restarting.
|
|
1715
|
+
const isMeasurable = elapsedTimeSinceLastEvent > 0 && loadedAmount > 0;
|
|
1478
1716
|
// We only want to calculate speed and remaining time after 2 seconds of the execution
|
|
1479
1717
|
// This is to avoid showing incorrect speed and remaining time when the request is very fast
|
|
1480
|
-
if (elapsedTimeSinceLastExecute > SPEED_BUFFER_TIME_IN_MS) {
|
|
1481
|
-
const
|
|
1482
|
-
progress.speed =
|
|
1483
|
-
progress.remainingTime = Math.round((event.total - event.loaded) /
|
|
1718
|
+
if (isMeasurable && elapsedTimeSinceLastExecute > SPEED_BUFFER_TIME_IN_MS) {
|
|
1719
|
+
const bytesPerSecond = (loadedAmount / elapsedTimeSinceLastEvent) * 1000;
|
|
1720
|
+
progress.speed = bytesPerSecond;
|
|
1721
|
+
progress.remainingTime = Math.round((event.total - event.loaded) / bytesPerSecond) * 1000;
|
|
1722
|
+
}
|
|
1723
|
+
if (isMeasurable) {
|
|
1724
|
+
lastLoadEventTime.set(currentTime);
|
|
1725
|
+
lastLoadEventAmount.set(event.loaded);
|
|
1484
1726
|
}
|
|
1485
|
-
lastLoadEventTime.set(currentTime);
|
|
1486
|
-
lastLoadEventAmount.set(event.loaded);
|
|
1487
1727
|
loading.set(state);
|
|
1488
1728
|
};
|
|
1489
1729
|
const lastExternalResponseAt = signal(null, /* @ts-ignore */
|
|
@@ -1504,6 +1744,7 @@ const createHttpRequest = (options) => {
|
|
|
1504
1744
|
const httpRequest = {
|
|
1505
1745
|
method: options.method,
|
|
1506
1746
|
url: options.fullPath,
|
|
1747
|
+
args: args ?? null,
|
|
1507
1748
|
execute,
|
|
1508
1749
|
destroy,
|
|
1509
1750
|
loading: loading.asReadonly(),
|
|
@@ -1518,6 +1759,10 @@ const createHttpRequest = (options) => {
|
|
|
1518
1759
|
lastExternalResponseAt: lastExternalResponseAt.asReadonly(),
|
|
1519
1760
|
applyPersistedResponse,
|
|
1520
1761
|
lastPersistedResponseAt: lastPersistedResponseAt.asReadonly(),
|
|
1762
|
+
resolveHeaders,
|
|
1763
|
+
attempts: attempts.asReadonly(),
|
|
1764
|
+
retryState: retryState.asReadonly(),
|
|
1765
|
+
lastDurationMs: lastDurationMs.asReadonly(),
|
|
1521
1766
|
},
|
|
1522
1767
|
};
|
|
1523
1768
|
return httpRequest;
|
|
@@ -1685,7 +1930,7 @@ const createQueryStack = (options) => {
|
|
|
1685
1930
|
kind: 'query-stack',
|
|
1686
1931
|
handle: stack,
|
|
1687
1932
|
meta: {
|
|
1688
|
-
|
|
1933
|
+
features: describeQueryDevtoolsFeatures(features),
|
|
1689
1934
|
},
|
|
1690
1935
|
});
|
|
1691
1936
|
inject(DestroyRef).onDestroy(unregister);
|
|
@@ -1974,7 +2219,7 @@ const createPagedQueryStack = (options) => {
|
|
|
1974
2219
|
kind: 'paged-query-stack',
|
|
1975
2220
|
handle: pagedQuery,
|
|
1976
2221
|
meta: {
|
|
1977
|
-
|
|
2222
|
+
features: describeQueryDevtoolsFeatures(features),
|
|
1978
2223
|
},
|
|
1979
2224
|
});
|
|
1980
2225
|
inject(DestroyRef).onDestroy(unregister);
|
|
@@ -2732,13 +2977,21 @@ const createQuerySyncEngine = (options) => {
|
|
|
2732
2977
|
// An invalidation is something the other tab's app code asked for explicitly, so unlike the
|
|
2733
2978
|
// mutation heuristic it is not something `refreshOnMutation: false` opts out of.
|
|
2734
2979
|
if (message.type === 'invalidate') {
|
|
2735
|
-
repository.refreshInUse(createQueryInvalidationFilter({ url: message.url })
|
|
2980
|
+
repository.refreshInUse(createQueryInvalidationFilter({ url: message.url }), {
|
|
2981
|
+
type: 'invalidation',
|
|
2982
|
+
url: message.url,
|
|
2983
|
+
otherTab: true,
|
|
2984
|
+
});
|
|
2736
2985
|
return;
|
|
2737
2986
|
}
|
|
2738
2987
|
if (!refreshOnMutation)
|
|
2739
2988
|
return;
|
|
2740
2989
|
const mutation = { method: message.method, url: message.url };
|
|
2741
|
-
repository.refreshInUse(mutationFilter ? (request) => mutationFilter(mutation, request) : undefined
|
|
2990
|
+
repository.refreshInUse(mutationFilter ? (request) => mutationFilter(mutation, request) : undefined, {
|
|
2991
|
+
type: 'mutation',
|
|
2992
|
+
url: message.url,
|
|
2993
|
+
otherTab: true,
|
|
2994
|
+
});
|
|
2742
2995
|
};
|
|
2743
2996
|
const postInvalidation = (url) => transport.post({ type: 'invalidate', url });
|
|
2744
2997
|
const eventSubscription = repository.events$.subscribe(broadcast);
|
|
@@ -2853,6 +3106,13 @@ const QueryClientFeatureType = {
|
|
|
2853
3106
|
DEFAULT_RETRY: 'DEFAULT_RETRY',
|
|
2854
3107
|
ETHLETE_API_ERRORS: 'ETHLETE_API_ERRORS',
|
|
2855
3108
|
};
|
|
3109
|
+
const describeRefreshOnMutation = (config) => {
|
|
3110
|
+
if (config === false)
|
|
3111
|
+
return 'no';
|
|
3112
|
+
if (config === true || config === undefined)
|
|
3113
|
+
return 'every query in use';
|
|
3114
|
+
return 'filtered';
|
|
3115
|
+
};
|
|
2856
3116
|
/**
|
|
2857
3117
|
* Coordinates a query client with its own instances in the user's **other tabs**, over a
|
|
2858
3118
|
* `BroadcastChannel` and the Web Locks API. Three things happen once it is on:
|
|
@@ -2893,7 +3153,16 @@ const withMultiTabSync = (config) => ({ clientName, repository, destroyRef, isBr
|
|
|
2893
3153
|
lockManager: createQueryKeyLockManager(`et-query-poll:${channelName}`),
|
|
2894
3154
|
});
|
|
2895
3155
|
destroyRef.onDestroy(sync.destroy);
|
|
2896
|
-
return {
|
|
3156
|
+
return {
|
|
3157
|
+
type: QueryClientFeatureType.MULTI_TAB_SYNC,
|
|
3158
|
+
instance: sync,
|
|
3159
|
+
devtools: () => [
|
|
3160
|
+
{ label: 'channel', value: channelName },
|
|
3161
|
+
{ label: 'share responses', value: syncConfig.syncResponses === false ? 'no' : 'yes' },
|
|
3162
|
+
{ label: 'dedupe polling', value: syncConfig.dedupePolling === false ? 'no' : 'yes' },
|
|
3163
|
+
{ label: 'refresh on mutation', value: describeRefreshOnMutation(syncConfig.refreshOnMutation) },
|
|
3164
|
+
],
|
|
3165
|
+
};
|
|
2897
3166
|
};
|
|
2898
3167
|
/**
|
|
2899
3168
|
* Keeps a query client's successful reads on disk (IndexedDB), so a reload renders the last known
|
|
@@ -2947,7 +3216,19 @@ const withQueryPersistence = (config) => ({ clientName, repository, destroyRef,
|
|
|
2947
3216
|
window.removeEventListener('pagehide', flush);
|
|
2948
3217
|
engine.destroy();
|
|
2949
3218
|
});
|
|
2950
|
-
return {
|
|
3219
|
+
return {
|
|
3220
|
+
type: QueryClientFeatureType.PERSISTENCE,
|
|
3221
|
+
instance: engine,
|
|
3222
|
+
devtools: () => [
|
|
3223
|
+
{ label: 'store', value: persistenceConfig.storageName ?? `et-query-persistence-${clientName}` },
|
|
3224
|
+
{ label: 'version', value: String(persistenceConfig.version ?? 1) },
|
|
3225
|
+
{ label: 'max age', value: formatQueryDevtoolsDuration(persistenceConfig.maxAge ?? 86_400_000) },
|
|
3226
|
+
{ label: 'max entries', value: String(persistenceConfig.maxEntries ?? 50) },
|
|
3227
|
+
{ label: 'write delay', value: formatQueryDevtoolsDuration(persistenceConfig.writeDelay ?? 1000) },
|
|
3228
|
+
...(persistenceConfig.adapter ? [{ label: 'adapter', value: 'custom' }] : []),
|
|
3229
|
+
...queryDevtoolsFnDetail(persistenceConfig.filter, 'filter'),
|
|
3230
|
+
],
|
|
3231
|
+
};
|
|
2951
3232
|
};
|
|
2952
3233
|
/**
|
|
2953
3234
|
* Teaches the error pipeline to read an **HTML error page** - the 502 a proxy answers with, a
|
|
@@ -3104,10 +3385,10 @@ const createQueryRepository = (config) => {
|
|
|
3104
3385
|
isPersistEnabled,
|
|
3105
3386
|
keepUnusedFor,
|
|
3106
3387
|
});
|
|
3107
|
-
|
|
3108
|
-
cacheEntry.request.execute({ allowCache: runQueryOptions?.allowCache })
|
|
3109
|
-
|
|
3110
|
-
return { key: cacheKey, request: cacheEntry.request };
|
|
3388
|
+
const executed = !runQueryOptions?.allowCache || cacheEntry.request.isStale()
|
|
3389
|
+
? cacheEntry.request.execute({ allowCache: runQueryOptions?.allowCache })
|
|
3390
|
+
: false;
|
|
3391
|
+
return { key: cacheKey, request: cacheEntry.request, executed };
|
|
3111
3392
|
}
|
|
3112
3393
|
}
|
|
3113
3394
|
const request = createHttpRequest({
|
|
@@ -3116,11 +3397,12 @@ const createQueryRepository = (config) => {
|
|
|
3116
3397
|
method: options.method,
|
|
3117
3398
|
dependencies: config.dependencies,
|
|
3118
3399
|
clientOptions: creatorOptions,
|
|
3400
|
+
clientName: config.name,
|
|
3119
3401
|
clientHeaders: config.headers,
|
|
3120
3402
|
cacheAdapter: config.cacheAdapter,
|
|
3121
3403
|
retryFn: options.retryFn ?? config.retryFn,
|
|
3122
3404
|
});
|
|
3123
|
-
request.execute();
|
|
3405
|
+
const executed = request.execute();
|
|
3124
3406
|
bind({
|
|
3125
3407
|
key: trackingKey,
|
|
3126
3408
|
consumerDestroyRef: options.consumerDestroyRef,
|
|
@@ -3135,7 +3417,7 @@ const createQueryRepository = (config) => {
|
|
|
3135
3417
|
// on it - hydration from the persisted store - is only ever allowed to fill a gap this request has
|
|
3136
3418
|
// not filled itself.
|
|
3137
3419
|
eventsSubject.next({ type: 'entry-created', key: trackingKey, isCached: shouldCache, isPersistEnabled });
|
|
3138
|
-
return { key: trackingKey, request };
|
|
3420
|
+
return { key: trackingKey, request, executed };
|
|
3139
3421
|
};
|
|
3140
3422
|
/** Tears an entry down for good, whether it currently has consumers or not. */
|
|
3141
3423
|
const destroyEntry = (key, cacheEntry) => {
|
|
@@ -3198,7 +3480,8 @@ const createQueryRepository = (config) => {
|
|
|
3198
3480
|
bumpCacheVersion();
|
|
3199
3481
|
eventsSubject.next({ type: 'unbind-all-secure' });
|
|
3200
3482
|
};
|
|
3201
|
-
const refreshInUse = (filter) => {
|
|
3483
|
+
const refreshInUse = (filter, cause) => {
|
|
3484
|
+
const refreshed = [];
|
|
3202
3485
|
for (const cacheEntry of cache.values()) {
|
|
3203
3486
|
if (cacheEntry.consumers.size === 0)
|
|
3204
3487
|
continue;
|
|
@@ -3209,8 +3492,14 @@ const createQueryRepository = (config) => {
|
|
|
3209
3492
|
continue;
|
|
3210
3493
|
if (filter && !filter(cacheEntry.request))
|
|
3211
3494
|
continue;
|
|
3495
|
+
refreshed.push(cacheEntry.request);
|
|
3212
3496
|
cacheEntry.request.execute({ force: true });
|
|
3213
3497
|
}
|
|
3498
|
+
eventsSubject.next({
|
|
3499
|
+
type: 'queries-refreshed',
|
|
3500
|
+
cause: cause ?? { type: 'refresh', url: null, otherTab: false },
|
|
3501
|
+
requests: refreshed,
|
|
3502
|
+
});
|
|
3214
3503
|
};
|
|
3215
3504
|
const applyExternalResponse = (options) => {
|
|
3216
3505
|
const cacheEntry = cache.get(options.key);
|
|
@@ -3322,6 +3611,7 @@ const createQueryClient = (options) => defineRootProvider(() => {
|
|
|
3322
3611
|
const destroyRef = inject(DestroyRef);
|
|
3323
3612
|
let sync = null;
|
|
3324
3613
|
let persistenceEngine = null;
|
|
3614
|
+
const appliedFeatures = [];
|
|
3325
3615
|
if (options.features?.length) {
|
|
3326
3616
|
const seen = new Set();
|
|
3327
3617
|
for (const featureFn of options.features) {
|
|
@@ -3329,6 +3619,7 @@ const createQueryClient = (options) => defineRootProvider(() => {
|
|
|
3329
3619
|
if (seen.has(feature.type))
|
|
3330
3620
|
throw queryClientFeatureUsedMultipleTimes(feature.type);
|
|
3331
3621
|
seen.add(feature.type);
|
|
3622
|
+
appliedFeatures.push(feature);
|
|
3332
3623
|
if (feature.type === QueryClientFeatureType.MULTI_TAB_SYNC) {
|
|
3333
3624
|
sync = feature.instance;
|
|
3334
3625
|
}
|
|
@@ -3343,7 +3634,11 @@ const createQueryClient = (options) => defineRootProvider(() => {
|
|
|
3343
3634
|
refreshQueriesInUse: () => repository.refreshInUse(),
|
|
3344
3635
|
invalidateQueries: (invalidation) => {
|
|
3345
3636
|
const url = invalidation?.url ? resolveInvalidationUrl(options.baseUrl, invalidation.url) : null;
|
|
3346
|
-
repository.refreshInUse(createQueryInvalidationFilter({ url, filter: invalidation?.filter })
|
|
3637
|
+
repository.refreshInUse(createQueryInvalidationFilter({ url, filter: invalidation?.filter }), {
|
|
3638
|
+
type: 'invalidation',
|
|
3639
|
+
url,
|
|
3640
|
+
otherTab: false,
|
|
3641
|
+
});
|
|
3347
3642
|
// The resolved URL is what travels: the other tabs are the same client, so they would
|
|
3348
3643
|
// resolve it identically, and a message that needs no interpretation cannot drift.
|
|
3349
3644
|
if (invalidation?.otherTabs ?? true)
|
|
@@ -3351,7 +3646,11 @@ const createQueryClient = (options) => defineRootProvider(() => {
|
|
|
3351
3646
|
},
|
|
3352
3647
|
clearPersistedQueries: () => persistenceEngine?.clear() ?? Promise.resolve(),
|
|
3353
3648
|
whenPersistenceReady: persistenceEngine?.whenReady ?? Promise.resolve(),
|
|
3354
|
-
subtle: {
|
|
3649
|
+
subtle: {
|
|
3650
|
+
sync,
|
|
3651
|
+
persistence: persistenceEngine,
|
|
3652
|
+
devtoolsFeatures: isQueryDevtoolsEnabled() ? describeQueryDevtoolsFeatures(appliedFeatures) : [],
|
|
3653
|
+
},
|
|
3355
3654
|
};
|
|
3356
3655
|
return client;
|
|
3357
3656
|
}, {
|
|
@@ -3998,8 +4297,10 @@ const setupBearerQueryRegistry = (builders, injector, latestExecutedQuery, lates
|
|
|
3998
4297
|
};
|
|
3999
4298
|
const setupFeatures = (featureBuilders, context) => {
|
|
4000
4299
|
const features = {};
|
|
4300
|
+
/** The features as applied, in order - what the devtools describe. */
|
|
4301
|
+
const applied = [];
|
|
4001
4302
|
if (!featureBuilders?.length) {
|
|
4002
|
-
return features;
|
|
4303
|
+
return { features, applied };
|
|
4003
4304
|
}
|
|
4004
4305
|
const featureTypes = new Set();
|
|
4005
4306
|
for (const featureSetup of featureBuilders) {
|
|
@@ -4014,9 +4315,25 @@ const setupFeatures = (featureBuilders, context) => {
|
|
|
4014
4315
|
.map((word, index) => (index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)))
|
|
4015
4316
|
.join('');
|
|
4016
4317
|
features[featureName] = feature.instance;
|
|
4318
|
+
applied.push({ type: feature.type, devtools: feature.devtools });
|
|
4017
4319
|
}
|
|
4018
|
-
return features;
|
|
4320
|
+
return { features, applied };
|
|
4019
4321
|
};
|
|
4322
|
+
/**
|
|
4323
|
+
* Describes the provider's queries for the devtools from what their creators were built with, so a
|
|
4324
|
+
* refresh request can be exported before the refresh query has ever run.
|
|
4325
|
+
*/
|
|
4326
|
+
const describeAuthQueries = (builders) => builders.map((builder) => {
|
|
4327
|
+
const internals = builder.config.queryCreator.subtle.creatorInternals;
|
|
4328
|
+
const isRefresh = builder._type === 'tokenRefreshQuery';
|
|
4329
|
+
return {
|
|
4330
|
+
key: builder.key,
|
|
4331
|
+
kind: (isRefresh ? 'token-refresh' : 'auth'),
|
|
4332
|
+
method: internals.method ?? 'POST',
|
|
4333
|
+
route: internals.route,
|
|
4334
|
+
buildArgs: isRefresh ? builder.buildArgs : undefined,
|
|
4335
|
+
};
|
|
4336
|
+
});
|
|
4020
4337
|
const alwaysLeader = () => true;
|
|
4021
4338
|
const runEarlyFeatureSetup = (featureBuilders, context) => {
|
|
4022
4339
|
let isLeaderFn = alwaysLeader;
|
|
@@ -4110,7 +4427,7 @@ const createBearerAuthProviderImpl = (config) => {
|
|
|
4110
4427
|
queries: queries,
|
|
4111
4428
|
executionState,
|
|
4112
4429
|
};
|
|
4113
|
-
const features = setupFeatures(config.features, featureSetupContext);
|
|
4430
|
+
const { features, applied: appliedFeatures } = setupFeatures(config.features, featureSetupContext);
|
|
4114
4431
|
const provider = {
|
|
4115
4432
|
queries,
|
|
4116
4433
|
features: features,
|
|
@@ -4130,11 +4447,13 @@ const createBearerAuthProviderImpl = (config) => {
|
|
|
4130
4447
|
kind: 'auth-provider',
|
|
4131
4448
|
handle: provider,
|
|
4132
4449
|
clientRef: config.queryClientRef,
|
|
4450
|
+
authQueries: describeAuthQueries(config.queries),
|
|
4133
4451
|
meta: {
|
|
4134
4452
|
name: config.name,
|
|
4135
4453
|
clientBaseUrl: queryClient.baseUrl,
|
|
4136
4454
|
repository: queryClient.repository,
|
|
4137
4455
|
client: queryClient,
|
|
4456
|
+
features: describeQueryDevtoolsFeatures(appliedFeatures),
|
|
4138
4457
|
},
|
|
4139
4458
|
});
|
|
4140
4459
|
destroyRef.onDestroy(unregister);
|
|
@@ -4177,6 +4496,7 @@ const withRefreshQuery = (key, config) => {
|
|
|
4177
4496
|
const delay = Math.min(exponentialDelay, maxRetryDelayMs);
|
|
4178
4497
|
return { retry: true, delay };
|
|
4179
4498
|
};
|
|
4499
|
+
const buildArgs = (refreshToken) => ({ body: { token: refreshToken } });
|
|
4180
4500
|
const setup = (context) => {
|
|
4181
4501
|
const expiresInPropertyName = config.expiresInPropertyName ?? 'exp';
|
|
4182
4502
|
const minRefreshInterval = config.minRefreshInterval ?? 30000; // 30 seconds default
|
|
@@ -4192,9 +4512,8 @@ const withRefreshQuery = (key, config) => {
|
|
|
4192
4512
|
if (timeSinceLastRefresh < minRefreshInterval)
|
|
4193
4513
|
return;
|
|
4194
4514
|
lastRefreshTime = now;
|
|
4195
|
-
const refreshArgs = { body: { token: currentRefreshToken } };
|
|
4196
4515
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
4197
|
-
context.queries[key].execute(
|
|
4516
|
+
context.queries[key].execute(buildArgs(currentRefreshToken), {
|
|
4198
4517
|
triggeredBy: triggeredInternally ? 'token-refresh' : undefined,
|
|
4199
4518
|
});
|
|
4200
4519
|
};
|
|
@@ -4277,6 +4596,7 @@ const withRefreshQuery = (key, config) => {
|
|
|
4277
4596
|
queryCreator: config.queryCreator.clone({ retryFn: refreshRetryFn, subtle: { useQueryRepositoryCache: true } }),
|
|
4278
4597
|
},
|
|
4279
4598
|
setup,
|
|
4599
|
+
buildArgs,
|
|
4280
4600
|
};
|
|
4281
4601
|
};
|
|
4282
4602
|
|
|
@@ -4343,6 +4663,11 @@ const withInactivityLogout = (config = {}) => {
|
|
|
4343
4663
|
return {
|
|
4344
4664
|
type: BearerAuthFeatureType.INACTIVITY_LOGOUT,
|
|
4345
4665
|
instance,
|
|
4666
|
+
devtools: () => [
|
|
4667
|
+
{ label: 'timeout', value: formatQueryDevtoolsDuration(inactivityTimeout) },
|
|
4668
|
+
{ label: 'activity events', value: activityEvents.join(', ') },
|
|
4669
|
+
...(config.customActivityCheck ? [{ label: 'custom activity check', value: 'yes' }] : []),
|
|
4670
|
+
],
|
|
4346
4671
|
};
|
|
4347
4672
|
};
|
|
4348
4673
|
};
|
|
@@ -4619,6 +4944,15 @@ const withBearerAuthMultiTabSync = (config = {}) => {
|
|
|
4619
4944
|
const setup = (_context) => ({
|
|
4620
4945
|
type: BearerAuthFeatureType.MULTI_TAB_SYNC,
|
|
4621
4946
|
instance,
|
|
4947
|
+
devtools: () => [
|
|
4948
|
+
{ label: 'channel', value: config.channelName ?? 'ethlete-auth-sync' },
|
|
4949
|
+
{ label: 'tokens', value: config.syncTokens === false ? 'tab local' : 'synced' },
|
|
4950
|
+
{ label: 'logout', value: config.syncLogout === false ? 'tab local' : 'synced' },
|
|
4951
|
+
{
|
|
4952
|
+
label: 'leader election',
|
|
4953
|
+
value: config.leaderElection === false ? 'every tab refreshes' : 'one tab refreshes',
|
|
4954
|
+
},
|
|
4955
|
+
],
|
|
4622
4956
|
});
|
|
4623
4957
|
// The elected leader gates the auth queries' automatic refresh, which is wired up before the
|
|
4624
4958
|
// regular feature setup runs - so this half has to happen earlier than `setup`.
|
|
@@ -4639,6 +4973,16 @@ const withPersistentAuth = (config) => {
|
|
|
4639
4973
|
return {
|
|
4640
4974
|
type: BearerAuthFeatureType.PERSISTENT_AUTH,
|
|
4641
4975
|
instance,
|
|
4976
|
+
devtools: () => [
|
|
4977
|
+
{ label: 'cookie', value: config.cookie?.name ?? 'etAuth' },
|
|
4978
|
+
{ label: 'remembered for', value: `${config.cookie?.expiresInDays ?? 30}d` },
|
|
4979
|
+
{ label: 'same site', value: config.cookie?.sameSite ?? 'lax' },
|
|
4980
|
+
{ label: 'remember me default', value: config.defaultRememberMe ? 'yes' : 'no' },
|
|
4981
|
+
{ label: 'auto login', value: config.autoLogin.queryKey },
|
|
4982
|
+
...(config.autoLogin.excludeRoutes?.length
|
|
4983
|
+
? [{ label: 'excluded routes', value: config.autoLogin.excludeRoutes.join(', ') }]
|
|
4984
|
+
: []),
|
|
4985
|
+
],
|
|
4642
4986
|
};
|
|
4643
4987
|
};
|
|
4644
4988
|
};
|
|
@@ -4745,6 +5089,10 @@ const withTokenExpirationWarning = (config = {}) => {
|
|
|
4745
5089
|
return {
|
|
4746
5090
|
type: BearerAuthFeatureType.TOKEN_EXPIRATION_WARNING,
|
|
4747
5091
|
instance,
|
|
5092
|
+
devtools: () => [
|
|
5093
|
+
{ label: 'warn before', value: formatQueryDevtoolsDuration(warningThreshold) },
|
|
5094
|
+
{ label: 'check every', value: formatQueryDevtoolsDuration(checkInterval) },
|
|
5095
|
+
],
|
|
4748
5096
|
};
|
|
4749
5097
|
};
|
|
4750
5098
|
};
|
|
@@ -4799,6 +5147,10 @@ const withTokenRevocation = (config) => {
|
|
|
4799
5147
|
return {
|
|
4800
5148
|
type: BearerAuthFeatureType.TOKEN_REVOCATION,
|
|
4801
5149
|
instance,
|
|
5150
|
+
devtools: () => [
|
|
5151
|
+
{ label: 'query', value: config.queryKey },
|
|
5152
|
+
{ label: 'on logout', value: revokeOnLogout ? 'yes' : 'no' },
|
|
5153
|
+
],
|
|
4802
5154
|
};
|
|
4803
5155
|
};
|
|
4804
5156
|
};
|
|
@@ -4806,9 +5158,14 @@ const withTokenRevocation = (config) => {
|
|
|
4806
5158
|
const withTracking = (config) => {
|
|
4807
5159
|
return (context) => {
|
|
4808
5160
|
const instance = createTrackingFeature(context, config);
|
|
5161
|
+
const handledEvents = Object.keys(config?.on ?? {});
|
|
4809
5162
|
return {
|
|
4810
5163
|
type: BearerAuthFeatureType.TRACKING,
|
|
4811
5164
|
instance,
|
|
5165
|
+
devtools: () => [
|
|
5166
|
+
{ label: 'internal events', value: config?.trackInternalEvents === false ? 'ignored' : 'tracked' },
|
|
5167
|
+
...(handledEvents.length ? [{ label: 'handlers', value: handledEvents.join(', ') }] : []),
|
|
5168
|
+
],
|
|
4812
5169
|
};
|
|
4813
5170
|
};
|
|
4814
5171
|
};
|
|
@@ -4945,6 +5302,349 @@ const createTrackingFeature = (context, config) => {
|
|
|
4945
5302
|
};
|
|
4946
5303
|
};
|
|
4947
5304
|
|
|
5305
|
+
/** The neutral fault: nothing armed. */
|
|
5306
|
+
const EMPTY_QUERY_DEVTOOLS_FAULT = {
|
|
5307
|
+
latencyMs: 0,
|
|
5308
|
+
failNext: 0,
|
|
5309
|
+
failRate: 0,
|
|
5310
|
+
status: 503,
|
|
5311
|
+
};
|
|
5312
|
+
/**
|
|
5313
|
+
* Statuses worth injecting, and whether the SDK's default retry policy retries them. A picker built from
|
|
5314
|
+
* this cannot arm a 500 and then leave you wondering why no retry fired.
|
|
5315
|
+
* @see runDefaultQueryRetry
|
|
5316
|
+
*/
|
|
5317
|
+
const QUERY_DEVTOOLS_FAULT_STATUSES = [
|
|
5318
|
+
{ status: 0, label: 'Network error', retryable: true },
|
|
5319
|
+
{ status: 400, label: 'Bad Request', retryable: false },
|
|
5320
|
+
{ status: 401, label: 'Unauthorized', retryable: false },
|
|
5321
|
+
{ status: 403, label: 'Forbidden', retryable: false },
|
|
5322
|
+
{ status: 404, label: 'Not Found', retryable: false },
|
|
5323
|
+
{ status: 408, label: 'Request Timeout', retryable: true },
|
|
5324
|
+
{ status: 429, label: 'Too Many Requests', retryable: true },
|
|
5325
|
+
{ status: 500, label: 'Internal Server Error', retryable: false },
|
|
5326
|
+
{ status: 502, label: 'Bad Gateway', retryable: true },
|
|
5327
|
+
{ status: 503, label: 'Service Unavailable', retryable: true },
|
|
5328
|
+
];
|
|
5329
|
+
const faults = /* @__PURE__ */ signal({}, /* @ts-ignore */
|
|
5330
|
+
...(ngDevMode ? [{ debugName: "faults" }] : /* istanbul ignore next */ []));
|
|
5331
|
+
/**
|
|
5332
|
+
* The faults armed per client name, consumed by the `<et-query-devtools>` UI. Clients with nothing armed
|
|
5333
|
+
* are absent rather than present with an {@link EMPTY_QUERY_DEVTOOLS_FAULT}.
|
|
5334
|
+
*/
|
|
5335
|
+
const queryDevtoolsFaults = /* @__PURE__ */ faults.asReadonly();
|
|
5336
|
+
/** Whether anything at all is armed on a fault. */
|
|
5337
|
+
const isQueryDevtoolsFaultArmed = (fault) => fault.latencyMs > 0 || fault.failNext > 0 || fault.failRate > 0;
|
|
5338
|
+
/**
|
|
5339
|
+
* Arms (or updates) the fault of one client. Only the given fields change; the rest keep their current
|
|
5340
|
+
* value. A client whose resulting fault has nothing armed is dropped from {@link queryDevtoolsFaults}.
|
|
5341
|
+
*
|
|
5342
|
+
* Part of the devtools contract consumed by `<et-query-devtools>`; a fault is a debugging tool, not
|
|
5343
|
+
* something an application should arm on itself.
|
|
5344
|
+
*/
|
|
5345
|
+
const setQueryDevtoolsFault = (options) => {
|
|
5346
|
+
const { clientName, patch } = options;
|
|
5347
|
+
faults.update((current) => {
|
|
5348
|
+
const next = { ...(current[clientName] ?? EMPTY_QUERY_DEVTOOLS_FAULT), ...patch };
|
|
5349
|
+
if (!isQueryDevtoolsFaultArmed(next)) {
|
|
5350
|
+
const { [clientName]: _removed, ...rest } = current;
|
|
5351
|
+
return rest;
|
|
5352
|
+
}
|
|
5353
|
+
return { ...current, [clientName]: next };
|
|
5354
|
+
});
|
|
5355
|
+
};
|
|
5356
|
+
/**
|
|
5357
|
+
* Disarms every fault of one client, or of all clients when no name is given.
|
|
5358
|
+
*
|
|
5359
|
+
* @see setQueryDevtoolsFault
|
|
5360
|
+
*/
|
|
5361
|
+
const clearQueryDevtoolsFaults = (clientName) => faults.update((current) => {
|
|
5362
|
+
if (clientName === undefined)
|
|
5363
|
+
return {};
|
|
5364
|
+
const { [clientName]: _removed, ...rest } = current;
|
|
5365
|
+
return rest;
|
|
5366
|
+
});
|
|
5367
|
+
/**
|
|
5368
|
+
* Resolves what to do with one upcoming attempt, consuming a `failNext` budget in the process - so this
|
|
5369
|
+
* must be called once per attempt and never speculatively.
|
|
5370
|
+
*
|
|
5371
|
+
* Installed as the fault resolver by `provideQueryDevtools()`; nothing else may call it.
|
|
5372
|
+
* @internal
|
|
5373
|
+
*/
|
|
5374
|
+
const resolveQueryDevtoolsFaultForAttempt = (target) => {
|
|
5375
|
+
const fault = faults()[target.clientName];
|
|
5376
|
+
if (!fault || !isQueryDevtoolsFaultArmed(fault))
|
|
5377
|
+
return null;
|
|
5378
|
+
let shouldFail = false;
|
|
5379
|
+
if (fault.failNext > 0) {
|
|
5380
|
+
shouldFail = true;
|
|
5381
|
+
setQueryDevtoolsFault({ clientName: target.clientName, patch: { failNext: fault.failNext - 1 } });
|
|
5382
|
+
}
|
|
5383
|
+
else if (fault.failRate > 0) {
|
|
5384
|
+
shouldFail = Math.random() * 100 < fault.failRate;
|
|
5385
|
+
}
|
|
5386
|
+
return {
|
|
5387
|
+
latencyMs: fault.latencyMs,
|
|
5388
|
+
status: shouldFail ? fault.status : null,
|
|
5389
|
+
};
|
|
5390
|
+
};
|
|
5391
|
+
|
|
5392
|
+
/**
|
|
5393
|
+
* Records which query forms feed one query's args, so the devtools can answer "which query does this
|
|
5394
|
+
* form drive?" from the reads themselves rather than from a naming convention.
|
|
5395
|
+
* @internal
|
|
5396
|
+
*/
|
|
5397
|
+
const createQueryDevtoolsFormLinks = () => {
|
|
5398
|
+
const ids = signal([], /* @ts-ignore */
|
|
5399
|
+
...(ngDevMode ? [{ debugName: "ids" }] : /* istanbul ignore next */ []));
|
|
5400
|
+
return {
|
|
5401
|
+
ids: ids.asReadonly(),
|
|
5402
|
+
track: (build) => {
|
|
5403
|
+
const collected = collectQueryFormLinks(build);
|
|
5404
|
+
// Args are built inside a reactive computation, which may not write to a signal - `untracked`
|
|
5405
|
+
// lifts that restriction, and skipping the write unless something is new keeps the panel from
|
|
5406
|
+
// being notified on every evaluation.
|
|
5407
|
+
untracked(() => {
|
|
5408
|
+
const known = ids();
|
|
5409
|
+
const added = collected.ids.filter((id) => !known.includes(id));
|
|
5410
|
+
if (added.length)
|
|
5411
|
+
ids.set([...known, ...added]);
|
|
5412
|
+
});
|
|
5413
|
+
return collected.value;
|
|
5414
|
+
},
|
|
5415
|
+
};
|
|
5416
|
+
};
|
|
5417
|
+
|
|
5418
|
+
const EMPTY_STATS = {
|
|
5419
|
+
executions: 0,
|
|
5420
|
+
requests: 0,
|
|
5421
|
+
responses: 0,
|
|
5422
|
+
errors: 0,
|
|
5423
|
+
retries: 0,
|
|
5424
|
+
receivedBytes: 0,
|
|
5425
|
+
sentBytes: 0,
|
|
5426
|
+
hasEstimatedBytes: false,
|
|
5427
|
+
firstExecutedAt: null,
|
|
5428
|
+
lastResponseAt: null,
|
|
5429
|
+
lastDurationMs: null,
|
|
5430
|
+
totalDurationMs: 0,
|
|
5431
|
+
};
|
|
5432
|
+
const textEncoder = typeof TextEncoder === 'function' ? /* @__PURE__ */ new TextEncoder() : null;
|
|
5433
|
+
const byteLengthOf = (text) => textEncoder?.encode(text).length ?? text.length;
|
|
5434
|
+
const estimateBodySize = (body) => {
|
|
5435
|
+
if (body === null || body === undefined)
|
|
5436
|
+
return 0;
|
|
5437
|
+
if (typeof body === 'string')
|
|
5438
|
+
return byteLengthOf(body);
|
|
5439
|
+
if (typeof Blob !== 'undefined' && body instanceof Blob)
|
|
5440
|
+
return body.size;
|
|
5441
|
+
if (body instanceof ArrayBuffer)
|
|
5442
|
+
return body.byteLength;
|
|
5443
|
+
if (ArrayBuffer.isView(body))
|
|
5444
|
+
return body.byteLength;
|
|
5445
|
+
if (typeof FormData !== 'undefined' && body instanceof FormData)
|
|
5446
|
+
return 0;
|
|
5447
|
+
try {
|
|
5448
|
+
return byteLengthOf(JSON.stringify(body) ?? '');
|
|
5449
|
+
}
|
|
5450
|
+
catch {
|
|
5451
|
+
// A body holding a circular reference or a BigInt has no serialized size to report.
|
|
5452
|
+
return 0;
|
|
5453
|
+
}
|
|
5454
|
+
};
|
|
5455
|
+
/** How many runs a query keeps. Enough to see a stampede or a chain without growing unbounded. */
|
|
5456
|
+
const RUN_HISTORY = 25;
|
|
5457
|
+
/**
|
|
5458
|
+
* How many of those runs keep their response body. Bodies dominate what the buffer retains, and a diff
|
|
5459
|
+
* only ever looks a couple of runs back.
|
|
5460
|
+
*/
|
|
5461
|
+
const RESPONSE_HISTORY = 5;
|
|
5462
|
+
/** The index of the newest run still in flight, or -1 when none is. */
|
|
5463
|
+
const lastPendingRunIndex = (runs) => {
|
|
5464
|
+
for (let index = runs.length - 1; index >= 0; index--) {
|
|
5465
|
+
if (runs[index]?.status === 'pending')
|
|
5466
|
+
return index;
|
|
5467
|
+
}
|
|
5468
|
+
return -1;
|
|
5469
|
+
};
|
|
5470
|
+
/**
|
|
5471
|
+
* Drops the response body of every run past the newest {@link RESPONSE_HISTORY} that hold one. Mutates
|
|
5472
|
+
* the array it is given, which is always one this module just built.
|
|
5473
|
+
*/
|
|
5474
|
+
const trimRetainedResponses = (runs) => {
|
|
5475
|
+
let kept = 0;
|
|
5476
|
+
for (let index = runs.length - 1; index >= 0; index--) {
|
|
5477
|
+
const run = runs[index];
|
|
5478
|
+
if (!run?.hasResponse)
|
|
5479
|
+
continue;
|
|
5480
|
+
if (++kept > RESPONSE_HISTORY)
|
|
5481
|
+
runs[index] = { ...run, response: null, hasResponse: false };
|
|
5482
|
+
}
|
|
5483
|
+
return runs;
|
|
5484
|
+
};
|
|
5485
|
+
/**
|
|
5486
|
+
* The size of a payload in bytes, and whether that size is the one that went over the wire. Only a
|
|
5487
|
+
* `content-length` header is exact; everything else is measured by serializing the body.
|
|
5488
|
+
*
|
|
5489
|
+
* Part of the devtools contract - the panel measures the cache and the event log with it. **Not part of
|
|
5490
|
+
* the general public contract.**
|
|
5491
|
+
*/
|
|
5492
|
+
const measureQueryDevtoolsPayload = (payload) => {
|
|
5493
|
+
const contentLength = Number(payload.headers?.get('content-length'));
|
|
5494
|
+
if (Number.isFinite(contentLength) && contentLength > 0)
|
|
5495
|
+
return { bytes: contentLength, isExact: true };
|
|
5496
|
+
return { bytes: estimateBodySize(payload.body), isExact: false };
|
|
5497
|
+
};
|
|
5498
|
+
/**
|
|
5499
|
+
* Accumulates what a query does, for the devtools panel. Only ever created while
|
|
5500
|
+
* {@link provideQueryDevtools} is installed - measuring a body's size serializes it, which no app
|
|
5501
|
+
* without devtools should pay for.
|
|
5502
|
+
* @internal
|
|
5503
|
+
*/
|
|
5504
|
+
const createQueryDevtoolsStats = () => {
|
|
5505
|
+
const stats = signal(EMPTY_STATS, /* @ts-ignore */
|
|
5506
|
+
...(ngDevMode ? [{ debugName: "stats" }] : /* istanbul ignore next */ []));
|
|
5507
|
+
const runs = signal([], /* @ts-ignore */
|
|
5508
|
+
...(ngDevMode ? [{ debugName: "runs" }] : /* istanbul ignore next */ []));
|
|
5509
|
+
// The baseline the next response's duration is measured against. Deliberately not part of the stats:
|
|
5510
|
+
// a duration is only ever reported once the response it belongs to has arrived.
|
|
5511
|
+
let lastExecutionAt = null;
|
|
5512
|
+
// The URL of the last execution, whether or not it requested - so a response that arrives without a run
|
|
5513
|
+
// of the query's own is still attributed to the URL the query was pointed at.
|
|
5514
|
+
let lastUrl = null;
|
|
5515
|
+
let runCounter = 0;
|
|
5516
|
+
const appendRun = (run, previous) => {
|
|
5517
|
+
const appended = { ...run, index: ++runCounter };
|
|
5518
|
+
runs.set(trimRetainedResponses([...previous, appended].slice(-RUN_HISTORY)));
|
|
5519
|
+
};
|
|
5520
|
+
/**
|
|
5521
|
+
* Ends the newest run still in flight. A response with no run of the query's own waiting for it came
|
|
5522
|
+
* from elsewhere (see {@link QueryDevtoolsRun.didRequest}), so it is recorded as an instant instead.
|
|
5523
|
+
*/
|
|
5524
|
+
const endRun = (end) => {
|
|
5525
|
+
const current = runs();
|
|
5526
|
+
const pending = lastPendingRunIndex(current);
|
|
5527
|
+
if (pending === -1) {
|
|
5528
|
+
appendRun({ ...end, startedAt: end.endedAt, didRequest: false, url: lastUrl, sentBytes: 0, attempts: 0 }, current);
|
|
5529
|
+
return;
|
|
5530
|
+
}
|
|
5531
|
+
runs.set(trimRetainedResponses(current.map((run, index) => (index === pending ? { ...run, ...end } : run))));
|
|
5532
|
+
};
|
|
5533
|
+
const recordExecution = ({ didRequest, body, url }) => {
|
|
5534
|
+
const now = Date.now();
|
|
5535
|
+
const sent = didRequest ? measureQueryDevtoolsPayload({ body }) : null;
|
|
5536
|
+
lastExecutionAt = now;
|
|
5537
|
+
lastUrl = url ?? null;
|
|
5538
|
+
stats.update((current) => ({
|
|
5539
|
+
...current,
|
|
5540
|
+
executions: current.executions + 1,
|
|
5541
|
+
requests: current.requests + (didRequest ? 1 : 0),
|
|
5542
|
+
sentBytes: current.sentBytes + (sent?.bytes ?? 0),
|
|
5543
|
+
hasEstimatedBytes: current.hasEstimatedBytes || (!!sent?.bytes && !sent.isExact),
|
|
5544
|
+
firstExecutedAt: current.firstExecutedAt ?? now,
|
|
5545
|
+
}));
|
|
5546
|
+
// An execution answered from the cache, or one that joined a request already in flight, starts no
|
|
5547
|
+
// run of its own - the response it eventually gets (if any) is what records one.
|
|
5548
|
+
if (!didRequest)
|
|
5549
|
+
return;
|
|
5550
|
+
appendRun({
|
|
5551
|
+
startedAt: now,
|
|
5552
|
+
endedAt: null,
|
|
5553
|
+
status: 'pending',
|
|
5554
|
+
didRequest: true,
|
|
5555
|
+
url: lastUrl,
|
|
5556
|
+
attempts: 1,
|
|
5557
|
+
sentBytes: sent?.bytes ?? 0,
|
|
5558
|
+
receivedBytes: 0,
|
|
5559
|
+
response: null,
|
|
5560
|
+
hasResponse: false,
|
|
5561
|
+
}, runs().map((run) => (run.status === 'pending' ? { ...run, status: 'aborted', endedAt: now } : run)));
|
|
5562
|
+
};
|
|
5563
|
+
const recordResponse = (payload) => {
|
|
5564
|
+
const now = Date.now();
|
|
5565
|
+
const received = measureQueryDevtoolsPayload(payload);
|
|
5566
|
+
const duration = lastExecutionAt === null ? null : now - lastExecutionAt;
|
|
5567
|
+
stats.update((current) => ({
|
|
5568
|
+
...current,
|
|
5569
|
+
responses: current.responses + 1,
|
|
5570
|
+
receivedBytes: current.receivedBytes + received.bytes,
|
|
5571
|
+
hasEstimatedBytes: current.hasEstimatedBytes || (received.bytes > 0 && !received.isExact),
|
|
5572
|
+
lastResponseAt: now,
|
|
5573
|
+
lastDurationMs: duration,
|
|
5574
|
+
totalDurationMs: current.totalDurationMs + (duration ?? 0),
|
|
5575
|
+
}));
|
|
5576
|
+
endRun({
|
|
5577
|
+
endedAt: now,
|
|
5578
|
+
status: 'success',
|
|
5579
|
+
receivedBytes: received.bytes,
|
|
5580
|
+
response: payload.body,
|
|
5581
|
+
hasResponse: true,
|
|
5582
|
+
});
|
|
5583
|
+
};
|
|
5584
|
+
const recordError = () => {
|
|
5585
|
+
stats.update((current) => ({ ...current, errors: current.errors + 1 }));
|
|
5586
|
+
endRun({ endedAt: Date.now(), status: 'error', receivedBytes: 0, response: null, hasResponse: false });
|
|
5587
|
+
};
|
|
5588
|
+
const recordRetry = ({ attempt }) => {
|
|
5589
|
+
const current = runs();
|
|
5590
|
+
const pending = lastPendingRunIndex(current);
|
|
5591
|
+
const run = current[pending];
|
|
5592
|
+
// Nothing in flight means the retry belongs to a request this query is not the one waiting on, and an
|
|
5593
|
+
// attempt already accounted for is the caller reporting the same one twice.
|
|
5594
|
+
if (!run || attempt <= run.attempts)
|
|
5595
|
+
return;
|
|
5596
|
+
stats.update((state) => ({ ...state, retries: state.retries + (attempt - run.attempts) }));
|
|
5597
|
+
runs.set(current.map((entry, index) => (index === pending ? { ...entry, attempts: attempt } : entry)));
|
|
5598
|
+
};
|
|
5599
|
+
const reset = () => {
|
|
5600
|
+
lastExecutionAt = null;
|
|
5601
|
+
lastUrl = null;
|
|
5602
|
+
runCounter = 0;
|
|
5603
|
+
stats.set(EMPTY_STATS);
|
|
5604
|
+
runs.set([]);
|
|
5605
|
+
};
|
|
5606
|
+
return {
|
|
5607
|
+
current: stats.asReadonly(),
|
|
5608
|
+
runs: runs.asReadonly(),
|
|
5609
|
+
reset,
|
|
5610
|
+
recordExecution,
|
|
5611
|
+
recordResponse,
|
|
5612
|
+
recordError,
|
|
5613
|
+
recordRetry,
|
|
5614
|
+
};
|
|
5615
|
+
};
|
|
5616
|
+
/**
|
|
5617
|
+
* Adds up the stats of several entries, for a stack's or a client's total. `lastDurationMs` is taken from
|
|
5618
|
+
* whichever entry responded most recently rather than summed.
|
|
5619
|
+
*/
|
|
5620
|
+
const sumQueryDevtoolsStats = (handles) => {
|
|
5621
|
+
const total = { ...EMPTY_STATS };
|
|
5622
|
+
for (const handle of handles) {
|
|
5623
|
+
if (!handle)
|
|
5624
|
+
continue;
|
|
5625
|
+
const stats = handle.current();
|
|
5626
|
+
total.executions += stats.executions;
|
|
5627
|
+
total.requests += stats.requests;
|
|
5628
|
+
total.responses += stats.responses;
|
|
5629
|
+
total.errors += stats.errors;
|
|
5630
|
+
total.retries += stats.retries;
|
|
5631
|
+
total.receivedBytes += stats.receivedBytes;
|
|
5632
|
+
total.sentBytes += stats.sentBytes;
|
|
5633
|
+
total.totalDurationMs += stats.totalDurationMs;
|
|
5634
|
+
total.hasEstimatedBytes = total.hasEstimatedBytes || stats.hasEstimatedBytes;
|
|
5635
|
+
if (stats.firstExecutedAt !== null &&
|
|
5636
|
+
(total.firstExecutedAt === null || stats.firstExecutedAt < total.firstExecutedAt)) {
|
|
5637
|
+
total.firstExecutedAt = stats.firstExecutedAt;
|
|
5638
|
+
}
|
|
5639
|
+
if (stats.lastResponseAt !== null &&
|
|
5640
|
+
(total.lastResponseAt === null || stats.lastResponseAt > total.lastResponseAt)) {
|
|
5641
|
+
total.lastResponseAt = stats.lastResponseAt;
|
|
5642
|
+
total.lastDurationMs = stats.lastDurationMs;
|
|
5643
|
+
}
|
|
5644
|
+
}
|
|
5645
|
+
return total;
|
|
5646
|
+
};
|
|
5647
|
+
|
|
4948
5648
|
const entries = /* @__PURE__ */ signal([], /* @ts-ignore */
|
|
4949
5649
|
...(ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []));
|
|
4950
5650
|
/**
|
|
@@ -4963,26 +5663,49 @@ const descriptorOf = (entry) => {
|
|
|
4963
5663
|
return `auth-provider|${meta.name ?? ''}`;
|
|
4964
5664
|
if (kind === 'ws-client')
|
|
4965
5665
|
return `ws-client|${meta.name ?? ''}`;
|
|
5666
|
+
if (kind === 'query-form')
|
|
5667
|
+
return `query-form|${meta.name ?? ''}`;
|
|
4966
5668
|
return kind;
|
|
4967
5669
|
};
|
|
4968
5670
|
/**
|
|
4969
|
-
*
|
|
4970
|
-
*
|
|
5671
|
+
* Wraps a path param name where a route function interpolated it. A NUL cannot occur in a route, so
|
|
5672
|
+
* a marked-up route stays unambiguously parseable.
|
|
5673
|
+
*/
|
|
5674
|
+
const PARAM_MARKER = '\u0000';
|
|
5675
|
+
/**
|
|
5676
|
+
* Stands in for the path params object a route function expects, recording every param it reads as
|
|
5677
|
+
* `\0<name>\0` in the returned route. A route that transforms what it reads (`p.id.slice(2)`) still
|
|
5678
|
+
* yields a usable route - the recorded name is transformed along with it.
|
|
5679
|
+
*/
|
|
5680
|
+
const paramRecorder = () => new Proxy({}, {
|
|
5681
|
+
get: (_, prop) => (typeof prop === 'string' ? `${PARAM_MARKER}${prop}${PARAM_MARKER}` : undefined),
|
|
5682
|
+
});
|
|
5683
|
+
/** Splits a recorded route into its literal chunks and the path params interleaved between them. */
|
|
5684
|
+
const parseRecordedRoute = (recorded) => recorded
|
|
5685
|
+
.split(PARAM_MARKER)
|
|
5686
|
+
// Markers are balanced, so every odd chunk is a param name and every even one is literal text.
|
|
5687
|
+
.map((text, index) => ({ text, param: index % 2 === 1 ? text : null }))
|
|
5688
|
+
.filter((part) => part.text !== '');
|
|
5689
|
+
/**
|
|
5690
|
+
* Parses a query creator route into its literal and path-param parts, so the devtools can show which
|
|
5691
|
+
* segments of a route are dynamic and fill them in with the values a query actually used.
|
|
4971
5692
|
* @internal
|
|
4972
5693
|
*/
|
|
4973
|
-
const
|
|
5694
|
+
const parseQueryRoute = (route) => {
|
|
4974
5695
|
if (route === undefined || route === null)
|
|
4975
|
-
return
|
|
5696
|
+
return [];
|
|
4976
5697
|
try {
|
|
4977
5698
|
if (typeof route === 'function') {
|
|
4978
|
-
return route(
|
|
5699
|
+
return parseRecordedRoute(route(paramRecorder()));
|
|
4979
5700
|
}
|
|
4980
|
-
return String(route);
|
|
5701
|
+
return [{ text: String(route), param: null }];
|
|
4981
5702
|
}
|
|
4982
5703
|
catch {
|
|
4983
|
-
return typeof route === 'function' ? '(dynamic route)' : String(route);
|
|
5704
|
+
return [{ text: typeof route === 'function' ? '(dynamic route)' : String(route), param: null }];
|
|
4984
5705
|
}
|
|
4985
5706
|
};
|
|
5707
|
+
/** Renders parsed route parts as a template, e.g. `/team/:teamId/players`. */
|
|
5708
|
+
const stringifyQueryRouteParts = (parts) => parts.map((part) => (part.param ? `:${part.param}` : part.text)).join('');
|
|
4986
5709
|
/**
|
|
4987
5710
|
* Extracts the human readable client name from a query client tuple. The client's DI token is named
|
|
4988
5711
|
* `QueryClient_<name>`, so we strip the prefix to recover the original name.
|
|
@@ -4993,16 +5716,37 @@ const getQueryClientName = (client) => {
|
|
|
4993
5716
|
const desc = token?.toString?.() ?? '';
|
|
4994
5717
|
return desc.replace('InjectionToken ', '').replace('QueryClient_', '') || 'unknown';
|
|
4995
5718
|
};
|
|
5719
|
+
/**
|
|
5720
|
+
* The provider name behind a bearer auth provider definition, recovered from its DI token the way
|
|
5721
|
+
* {@link getQueryClientName} recovers a client's.
|
|
5722
|
+
* @internal
|
|
5723
|
+
*/
|
|
5724
|
+
const getBearerAuthProviderName = (ref) => {
|
|
5725
|
+
const desc = String(ref.token ?? '');
|
|
5726
|
+
return desc.replace('InjectionToken ', '').replace('BearerAuthProvider_', '') || 'unknown';
|
|
5727
|
+
};
|
|
4996
5728
|
/**
|
|
4997
5729
|
* Ids are derived deterministically from a stable descriptor + a per-descriptor sequence number, so
|
|
4998
5730
|
* they survive a page reload (letting the UI restore the selected entry) instead of being random.
|
|
4999
5731
|
*/
|
|
5000
5732
|
const registerEntry = (registration) => {
|
|
5001
5733
|
const meta = { ...registration.meta };
|
|
5002
|
-
if (registration.route !== undefined)
|
|
5003
|
-
meta.
|
|
5734
|
+
if (registration.route !== undefined) {
|
|
5735
|
+
meta.routeParts = parseQueryRoute(registration.route);
|
|
5736
|
+
meta.route = stringifyQueryRouteParts(meta.routeParts);
|
|
5737
|
+
}
|
|
5004
5738
|
if (registration.clientRef)
|
|
5005
5739
|
meta.clientName = getQueryClientName(registration.clientRef);
|
|
5740
|
+
if (registration.authProviderRef) {
|
|
5741
|
+
meta.isSecure = true;
|
|
5742
|
+
meta.authProviderName = getBearerAuthProviderName(registration.authProviderRef);
|
|
5743
|
+
}
|
|
5744
|
+
if (registration.authQueries) {
|
|
5745
|
+
meta.authQueries = registration.authQueries.map((authQuery) => ({
|
|
5746
|
+
...authQuery,
|
|
5747
|
+
route: stringifyQueryRouteParts(parseQueryRoute(authQuery.route)),
|
|
5748
|
+
}));
|
|
5749
|
+
}
|
|
5006
5750
|
let id = registration.id;
|
|
5007
5751
|
if (!id) {
|
|
5008
5752
|
const descriptor = descriptorOf({ kind: registration.kind, meta });
|
|
@@ -5016,6 +5760,8 @@ const registerEntry = (registration) => {
|
|
|
5016
5760
|
handle: registration.handle,
|
|
5017
5761
|
meta,
|
|
5018
5762
|
createdAt: Date.now(),
|
|
5763
|
+
stats: registration.stats,
|
|
5764
|
+
formLinks: registration.formLinks,
|
|
5019
5765
|
};
|
|
5020
5766
|
entries.update((list) => [...list, fullEntry]);
|
|
5021
5767
|
return () => entries.update((list) => list.filter((e) => e.id !== fullEntry.id));
|
|
@@ -5037,6 +5783,9 @@ const registerEntry = (registration) => {
|
|
|
5037
5783
|
*/
|
|
5038
5784
|
const provideQueryDevtools = () => {
|
|
5039
5785
|
setQueryDevtoolsRegistrar(registerEntry);
|
|
5786
|
+
setQueryDevtoolsStatsFactory(createQueryDevtoolsStats);
|
|
5787
|
+
setQueryDevtoolsFormLinksFactory(createQueryDevtoolsFormLinks);
|
|
5788
|
+
setQueryDevtoolsFaultResolver(resolveQueryDevtoolsFaultForAttempt);
|
|
5040
5789
|
if (!isDevMode()) {
|
|
5041
5790
|
console.warn('You are using the Query Devtools in production mode. This increases the size of your bundle and should only be used for development purposes.');
|
|
5042
5791
|
}
|
|
@@ -5246,6 +5995,9 @@ const createGqlMutationViaPost = /* @__PURE__ */ createGqlCreatorTemplate('MUTAT
|
|
|
5246
5995
|
/** A query creator that creates a secure GQL mutation where the payload is sent via POST (body) */
|
|
5247
5996
|
const createSecureGqlMutationViaPost = /* @__PURE__ */ createSecureGqlCreatorTemplate('MUTATE', 'POST');
|
|
5248
5997
|
|
|
5998
|
+
/**
|
|
5999
|
+
* @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.
|
|
6000
|
+
*/
|
|
5249
6001
|
class CustomHeaderAuthProvider {
|
|
5250
6002
|
constructor(_config) {
|
|
5251
6003
|
this._config = _config;
|
|
@@ -5258,6 +6010,9 @@ class CustomHeaderAuthProvider {
|
|
|
5258
6010
|
}
|
|
5259
6011
|
}
|
|
5260
6012
|
|
|
6013
|
+
/**
|
|
6014
|
+
* @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.
|
|
6015
|
+
*/
|
|
5261
6016
|
class BasicAuthProvider {
|
|
5262
6017
|
constructor(_config) {
|
|
5263
6018
|
this._config = _config;
|
|
@@ -5273,7 +6028,13 @@ class BasicAuthProvider {
|
|
|
5273
6028
|
}
|
|
5274
6029
|
}
|
|
5275
6030
|
|
|
6031
|
+
/**
|
|
6032
|
+
* @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.
|
|
6033
|
+
*/
|
|
5276
6034
|
const isRequestError = (error) => error instanceof Object && 'status' in error && 'statusText' in error && 'url' in error;
|
|
6035
|
+
/**
|
|
6036
|
+
* @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.
|
|
6037
|
+
*/
|
|
5277
6038
|
const v2ExtractExpiresInSeconds = (headers) => {
|
|
5278
6039
|
const cacheControl = headers['cache-control'];
|
|
5279
6040
|
const age = headers['age'];
|
|
@@ -5319,6 +6080,9 @@ const v2ExtractExpiresInSeconds = (headers) => {
|
|
|
5319
6080
|
}
|
|
5320
6081
|
return expiresIn;
|
|
5321
6082
|
};
|
|
6083
|
+
/**
|
|
6084
|
+
* @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.
|
|
6085
|
+
*/
|
|
5322
6086
|
const serializeBody = (body) => {
|
|
5323
6087
|
if (body === null || body === undefined) {
|
|
5324
6088
|
return null;
|
|
@@ -5336,6 +6100,9 @@ const serializeBody = (body) => {
|
|
|
5336
6100
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5337
6101
|
return body.toString();
|
|
5338
6102
|
};
|
|
6103
|
+
/**
|
|
6104
|
+
* @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.
|
|
6105
|
+
*/
|
|
5339
6106
|
const transformMethod = (config) => {
|
|
5340
6107
|
if (config.method === 'GQL_QUERY' || config.method === 'GQL_MUTATE') {
|
|
5341
6108
|
if (!config.transferVia) {
|
|
@@ -5345,6 +6112,9 @@ const transformMethod = (config) => {
|
|
|
5345
6112
|
}
|
|
5346
6113
|
return config.method;
|
|
5347
6114
|
};
|
|
6115
|
+
/**
|
|
6116
|
+
* @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.
|
|
6117
|
+
*/
|
|
5348
6118
|
const detectContentTypeHeader = (body) => {
|
|
5349
6119
|
// An empty body has no content type.
|
|
5350
6120
|
if (body === null) {
|
|
@@ -5375,14 +6145,23 @@ const detectContentTypeHeader = (body) => {
|
|
|
5375
6145
|
// No type could be inferred.
|
|
5376
6146
|
return null;
|
|
5377
6147
|
};
|
|
6148
|
+
/**
|
|
6149
|
+
* @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.
|
|
6150
|
+
*/
|
|
5378
6151
|
const hasHeader = (headers, header) => {
|
|
5379
6152
|
return Object.keys(headers).some((key) => key.toLowerCase() === header.toLowerCase());
|
|
5380
6153
|
};
|
|
6154
|
+
/**
|
|
6155
|
+
* @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.
|
|
6156
|
+
*/
|
|
5381
6157
|
const forEachHeader = (headers, callback) => {
|
|
5382
6158
|
Object.entries(headers).forEach(([key, value]) => {
|
|
5383
6159
|
callback(key, value);
|
|
5384
6160
|
});
|
|
5385
6161
|
};
|
|
6162
|
+
/**
|
|
6163
|
+
* @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.
|
|
6164
|
+
*/
|
|
5386
6165
|
const parseAllXhrResponseHeaders = (xhr) => {
|
|
5387
6166
|
const headers = xhr.getAllResponseHeaders();
|
|
5388
6167
|
const parsedHeaders = {};
|
|
@@ -5397,6 +6176,9 @@ const parseAllXhrResponseHeaders = (xhr) => {
|
|
|
5397
6176
|
}
|
|
5398
6177
|
return parsedHeaders;
|
|
5399
6178
|
};
|
|
6179
|
+
/**
|
|
6180
|
+
* @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.
|
|
6181
|
+
*/
|
|
5400
6182
|
const getResponseUrl = (xhr) => {
|
|
5401
6183
|
if ('responseURL' in xhr && xhr.responseURL) {
|
|
5402
6184
|
return xhr.responseURL;
|
|
@@ -5406,6 +6188,9 @@ const getResponseUrl = (xhr) => {
|
|
|
5406
6188
|
}
|
|
5407
6189
|
return null;
|
|
5408
6190
|
};
|
|
6191
|
+
/**
|
|
6192
|
+
* @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.
|
|
6193
|
+
*/
|
|
5409
6194
|
const v2ShouldRetryRequest = (config) => {
|
|
5410
6195
|
const defaultRetryDelay = 1000 + 1000 * config.currentRetryCount;
|
|
5411
6196
|
if (config.currentRetryCount > 3) {
|
|
@@ -5448,6 +6233,9 @@ const v2ShouldRetryRequest = (config) => {
|
|
|
5448
6233
|
};
|
|
5449
6234
|
|
|
5450
6235
|
const XSSI_PREFIX = /^\)\]\}',?\n/;
|
|
6236
|
+
/**
|
|
6237
|
+
* @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.
|
|
6238
|
+
*/
|
|
5451
6239
|
const request = (config) => {
|
|
5452
6240
|
const headers = config.headers || {};
|
|
5453
6241
|
const responseType = config.responseType || 'json';
|
|
@@ -5653,11 +6441,16 @@ const request = (config) => {
|
|
|
5653
6441
|
});
|
|
5654
6442
|
};
|
|
5655
6443
|
|
|
6444
|
+
/**
|
|
6445
|
+
* @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.
|
|
6446
|
+
*/
|
|
5656
6447
|
const addQueryContainerHandling = (obs, valueFn, config) => {
|
|
5657
|
-
|
|
6448
|
+
if (!config?.injector) {
|
|
6449
|
+
assertInInjectionContext(addQueryContainerHandling);
|
|
6450
|
+
}
|
|
5658
6451
|
const { abortPrevious, abortOnDestroy, stopPreviousPolling } = config ?? {};
|
|
5659
|
-
const injector = inject(Injector);
|
|
5660
|
-
const destroy$ = createDestroy();
|
|
6452
|
+
const injector = config?.injector ?? inject(Injector);
|
|
6453
|
+
const destroy$ = runInInjectionContext(injector, () => createDestroy());
|
|
5661
6454
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5662
6455
|
const tNode = injector._tNode;
|
|
5663
6456
|
const componentId = tNode?.index ?? -1;
|
|
@@ -5722,12 +6515,18 @@ const addQueryContainerHandling = (obs, valueFn, config) => {
|
|
|
5722
6515
|
}
|
|
5723
6516
|
});
|
|
5724
6517
|
};
|
|
6518
|
+
/**
|
|
6519
|
+
* @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.
|
|
6520
|
+
*/
|
|
5725
6521
|
function toQuerySignal(source, options) {
|
|
5726
6522
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5727
6523
|
const s = toSignal(source, options);
|
|
5728
6524
|
addQueryContainerHandling(source, () => s(), options);
|
|
5729
6525
|
return s;
|
|
5730
6526
|
}
|
|
6527
|
+
/**
|
|
6528
|
+
* @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.
|
|
6529
|
+
*/
|
|
5731
6530
|
function effectComputed(computation, injector) {
|
|
5732
6531
|
let initialData = null;
|
|
5733
6532
|
try {
|
|
@@ -5746,11 +6545,14 @@ function effectComputed(computation, injector) {
|
|
|
5746
6545
|
return;
|
|
5747
6546
|
lastResult.set(data);
|
|
5748
6547
|
});
|
|
5749
|
-
});
|
|
6548
|
+
}, { injector });
|
|
5750
6549
|
return lastResult.asReadonly();
|
|
5751
6550
|
}
|
|
6551
|
+
/**
|
|
6552
|
+
* @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.
|
|
6553
|
+
*/
|
|
5752
6554
|
function queryComputed(computation, options) {
|
|
5753
|
-
const injector = inject(Injector);
|
|
6555
|
+
const injector = options?.injector ?? inject(Injector);
|
|
5754
6556
|
const c = effectComputed(computation, injector);
|
|
5755
6557
|
const obs = toObservable(c, options);
|
|
5756
6558
|
addQueryContainerHandling(obs, () => c(), options);
|
|
@@ -5759,26 +6561,37 @@ function queryComputed(computation, options) {
|
|
|
5759
6561
|
/**
|
|
5760
6562
|
* Creates a signal that will only be reactive until the first query is created.
|
|
5761
6563
|
* All subsequent changes inside the computation will be ignored.
|
|
6564
|
+
*
|
|
6565
|
+
* @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.
|
|
5762
6566
|
*/
|
|
5763
6567
|
function queryComputedTillTruthy(computation, options) {
|
|
5764
|
-
const injector = inject(Injector);
|
|
6568
|
+
const injector = options?.injector ?? inject(Injector);
|
|
5765
6569
|
const c = computedTillTruthy(effectComputed(computation, injector));
|
|
5766
6570
|
const obs = toObservable(c, options);
|
|
5767
6571
|
addQueryContainerHandling(obs, () => c(), options);
|
|
5768
6572
|
return c;
|
|
5769
6573
|
}
|
|
6574
|
+
/**
|
|
6575
|
+
* @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.
|
|
6576
|
+
*/
|
|
5770
6577
|
function queryArrayComputed(computation, options) {
|
|
5771
|
-
const injector = inject(Injector);
|
|
6578
|
+
const injector = options?.injector ?? inject(Injector);
|
|
5772
6579
|
const c = effectComputed(computation, injector);
|
|
5773
6580
|
const obs = toObservable(c, options);
|
|
5774
6581
|
addQueryContainerHandling(obs, () => c(), options);
|
|
5775
6582
|
return c;
|
|
5776
6583
|
}
|
|
6584
|
+
/**
|
|
6585
|
+
* @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.
|
|
6586
|
+
*/
|
|
5777
6587
|
function toQuerySubject(source, options) {
|
|
5778
6588
|
const obs = toObservable(source, options);
|
|
5779
6589
|
addQueryContainerHandling(obs, () => source(), options);
|
|
5780
6590
|
return obs;
|
|
5781
6591
|
}
|
|
6592
|
+
/**
|
|
6593
|
+
* @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.
|
|
6594
|
+
*/
|
|
5782
6595
|
function queryStateSignal(source, options) {
|
|
5783
6596
|
const { cacheResponse } = options ?? {};
|
|
5784
6597
|
const roSignal = toSignal(toObservable(source).pipe(switchMap((q) => extractQuery(q)?.state$ ?? of(null)), switchMap((state) => {
|
|
@@ -5793,6 +6606,9 @@ function queryStateSignal(source, options) {
|
|
|
5793
6606
|
...(ngDevMode ? [{ debugName: "rwSignal" }] : /* istanbul ignore next */ []));
|
|
5794
6607
|
return rwSignal;
|
|
5795
6608
|
}
|
|
6609
|
+
/**
|
|
6610
|
+
* @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.
|
|
6611
|
+
*/
|
|
5796
6612
|
function queryStateResponseSignal(source, options) {
|
|
5797
6613
|
const s = queryStateSignal(source, options);
|
|
5798
6614
|
const dataSignal = computed(() => {
|
|
@@ -5805,6 +6621,9 @@ function queryStateResponseSignal(source, options) {
|
|
|
5805
6621
|
};
|
|
5806
6622
|
return dataSignal;
|
|
5807
6623
|
}
|
|
6624
|
+
/**
|
|
6625
|
+
* @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.
|
|
6626
|
+
*/
|
|
5808
6627
|
function queryStateErrorSignal(source) {
|
|
5809
6628
|
const s = queryStateSignal(source);
|
|
5810
6629
|
return computed(() => {
|
|
@@ -5812,6 +6631,9 @@ function queryStateErrorSignal(source) {
|
|
|
5812
6631
|
return isQueryStateFailure(state) ? state.error : null;
|
|
5813
6632
|
});
|
|
5814
6633
|
}
|
|
6634
|
+
/**
|
|
6635
|
+
* @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.
|
|
6636
|
+
*/
|
|
5815
6637
|
function queryStateLoadingSignal(source) {
|
|
5816
6638
|
const s = queryStateSignal(source);
|
|
5817
6639
|
return computed(() => {
|
|
@@ -5820,6 +6642,9 @@ function queryStateLoadingSignal(source) {
|
|
|
5820
6642
|
});
|
|
5821
6643
|
}
|
|
5822
6644
|
|
|
6645
|
+
/**
|
|
6646
|
+
* @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.
|
|
6647
|
+
*/
|
|
5823
6648
|
const deepFreeze = (object) => {
|
|
5824
6649
|
// check if object is actually an object or frozen
|
|
5825
6650
|
if (!object || typeof object !== 'object' || Object.isFrozen(object)) {
|
|
@@ -5842,9 +6667,14 @@ const deepFreeze = (object) => {
|
|
|
5842
6667
|
* **This function always returns null.**
|
|
5843
6668
|
* @see https://github.com/microsoft/TypeScript/issues/26242
|
|
5844
6669
|
* @returns null
|
|
6670
|
+
*
|
|
6671
|
+
* @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.
|
|
5845
6672
|
*/
|
|
5846
6673
|
const def = () => null;
|
|
5847
6674
|
|
|
6675
|
+
/**
|
|
6676
|
+
* @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.
|
|
6677
|
+
*/
|
|
5848
6678
|
class V2QueryCreator {
|
|
5849
6679
|
constructor(_queryConfig, _client, _store) {
|
|
5850
6680
|
this._queryConfig = _queryConfig;
|
|
@@ -5891,6 +6721,9 @@ class V2QueryCreator {
|
|
|
5891
6721
|
}
|
|
5892
6722
|
}
|
|
5893
6723
|
|
|
6724
|
+
/**
|
|
6725
|
+
* @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.
|
|
6726
|
+
*/
|
|
5894
6727
|
class QueryStore {
|
|
5895
6728
|
constructor(_config) {
|
|
5896
6729
|
this._config = _config;
|
|
@@ -6034,6 +6867,9 @@ class QueryStore {
|
|
|
6034
6867
|
}
|
|
6035
6868
|
}
|
|
6036
6869
|
|
|
6870
|
+
/**
|
|
6871
|
+
* @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.
|
|
6872
|
+
*/
|
|
6037
6873
|
class V2QueryClient {
|
|
6038
6874
|
constructor(_clientConfig) {
|
|
6039
6875
|
this._clientConfig = _clientConfig;
|
|
@@ -6111,9 +6947,15 @@ class V2QueryClient {
|
|
|
6111
6947
|
}
|
|
6112
6948
|
}
|
|
6113
6949
|
|
|
6950
|
+
/**
|
|
6951
|
+
* @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.
|
|
6952
|
+
*/
|
|
6114
6953
|
const v2ShouldCacheQuery = (method) => {
|
|
6115
6954
|
return method === 'GET' || method === 'OPTIONS' || method === 'HEAD' || method === 'GQL_QUERY';
|
|
6116
6955
|
};
|
|
6956
|
+
/**
|
|
6957
|
+
* @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.
|
|
6958
|
+
*/
|
|
6117
6959
|
const v2BuildQueryCacheKey = (route, args) => {
|
|
6118
6960
|
const variables = JSON.stringify(args?.variables || {})
|
|
6119
6961
|
// replace all curly braces with empty string
|
|
@@ -6131,6 +6973,64 @@ const v2BuildQueryCacheKey = (route, args) => {
|
|
|
6131
6973
|
return hash.toString();
|
|
6132
6974
|
};
|
|
6133
6975
|
|
|
6976
|
+
let fallbackInjector = null;
|
|
6977
|
+
/**
|
|
6978
|
+
* The stashed root injector, or `null` when the fallback was never provided (or was provided on the
|
|
6979
|
+
* server, where stashing is refused).
|
|
6980
|
+
*
|
|
6981
|
+
* @internal
|
|
6982
|
+
*/
|
|
6983
|
+
const legacyPrepareFallbackInjector = () => fallbackInjector;
|
|
6984
|
+
/**
|
|
6985
|
+
* Lets `prepare()` fall back to the application's root injector when it is called outside any injection
|
|
6986
|
+
* context, instead of throwing `ET950`.
|
|
6987
|
+
*
|
|
6988
|
+
* Opt-in, and **browser only**. Two things degrade when the fallback is used, both matching v2, which had
|
|
6989
|
+
* no injector to scope to at all:
|
|
6990
|
+
*
|
|
6991
|
+
* - **The query's lifetime becomes the application's.** Nothing tears it down when a component dies, so
|
|
6992
|
+
* cleanup rests entirely on a query container or `config: { destroyOnResponse: true }`.
|
|
6993
|
+
* - **The devtools lose the host element**, so "inspect" cannot jump to the component. Already the case
|
|
6994
|
+
* for any query created from a root or environment injector.
|
|
6995
|
+
*
|
|
6996
|
+
* It refuses to stash anything on the server: a module-global injector would be shared across concurrent
|
|
6997
|
+
* requests, which is data bleed rather than a leak. Server-side renders keep throwing `ET950`, so a call
|
|
6998
|
+
* site that only works in the browser fails loudly where it matters.
|
|
6999
|
+
*
|
|
7000
|
+
* Prefer passing `injector` at the call site - it keeps the query scoped to whatever created it. Reach for
|
|
7001
|
+
* this when a migration has too many call sites to thread by hand.
|
|
7002
|
+
*
|
|
7003
|
+
* @example
|
|
7004
|
+
* ```ts
|
|
7005
|
+
* bootstrapApplication(AppComponent, {
|
|
7006
|
+
* providers: [provideLegacyPrepareFallback()],
|
|
7007
|
+
* });
|
|
7008
|
+
* ```
|
|
7009
|
+
*
|
|
7010
|
+
* @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.
|
|
7011
|
+
*/
|
|
7012
|
+
const provideLegacyPrepareFallback = () => makeEnvironmentProviders([
|
|
7013
|
+
provideEnvironmentInitializer(() => {
|
|
7014
|
+
if (!isPlatformBrowser(inject(PLATFORM_ID))) {
|
|
7015
|
+
if (isDevMode()) {
|
|
7016
|
+
console.warn('provideLegacyPrepareFallback() does nothing on the server: a module-global injector would be shared ' +
|
|
7017
|
+
'between concurrent requests. prepare() calls without an injection context keep throwing ET950 there.');
|
|
7018
|
+
}
|
|
7019
|
+
return;
|
|
7020
|
+
}
|
|
7021
|
+
const injector = inject(EnvironmentInjector);
|
|
7022
|
+
fallbackInjector = injector;
|
|
7023
|
+
inject(DestroyRef).onDestroy(() => {
|
|
7024
|
+
if (fallbackInjector === injector) {
|
|
7025
|
+
fallbackInjector = null;
|
|
7026
|
+
}
|
|
7027
|
+
});
|
|
7028
|
+
}),
|
|
7029
|
+
]);
|
|
7030
|
+
|
|
7031
|
+
/**
|
|
7032
|
+
* @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.
|
|
7033
|
+
*/
|
|
6134
7034
|
const transformExecStateToQueryState = (execState) => {
|
|
6135
7035
|
const meta = { id: -1, triggeredVia: 'program' };
|
|
6136
7036
|
switch (execState?.type) {
|
|
@@ -6182,6 +7082,9 @@ const transformExecStateToQueryState = (execState) => {
|
|
|
6182
7082
|
}
|
|
6183
7083
|
}
|
|
6184
7084
|
};
|
|
7085
|
+
/**
|
|
7086
|
+
* @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.
|
|
7087
|
+
*/
|
|
6185
7088
|
const isLegacyQuery = (query) => {
|
|
6186
7089
|
if (!query || typeof query !== 'object' || Array.isArray(query)) {
|
|
6187
7090
|
return false;
|
|
@@ -6191,6 +7094,9 @@ const isLegacyQuery = (query) => {
|
|
|
6191
7094
|
}
|
|
6192
7095
|
return true;
|
|
6193
7096
|
};
|
|
7097
|
+
/**
|
|
7098
|
+
* @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.
|
|
7099
|
+
*/
|
|
6194
7100
|
class LegacyQuery {
|
|
6195
7101
|
constructor(newQuery, _arguments, entity,
|
|
6196
7102
|
/**
|
|
@@ -6199,11 +7105,19 @@ class LegacyQuery {
|
|
|
6199
7105
|
*
|
|
6200
7106
|
* @internal
|
|
6201
7107
|
*/
|
|
6202
|
-
_isInert = false
|
|
7108
|
+
_isInert = false,
|
|
7109
|
+
/**
|
|
7110
|
+
* Whether the underlying request is cacheable. Resolved by the creator, which is the only place that
|
|
7111
|
+
* knows the method before the first execution.
|
|
7112
|
+
*
|
|
7113
|
+
* @internal
|
|
7114
|
+
*/
|
|
7115
|
+
_canBeCached = false) {
|
|
6203
7116
|
this.newQuery = newQuery;
|
|
6204
7117
|
this._arguments = _arguments;
|
|
6205
7118
|
this.entity = entity;
|
|
6206
7119
|
this._isInert = _isInert;
|
|
7120
|
+
this._canBeCached = _canBeCached;
|
|
6207
7121
|
/**
|
|
6208
7122
|
* @internal
|
|
6209
7123
|
*/
|
|
@@ -6238,17 +7152,22 @@ class LegacyQuery {
|
|
|
6238
7152
|
}
|
|
6239
7153
|
this.state$ = toObservable(this.newQuery.executionState, { injector: this.newQuery.subtle.injector }).pipe(map((execState) => transformExecStateToQueryState(execState)), switchMap((s) => this._transformState(s)), shareReplay({ bufferSize: 1, refCount: true }));
|
|
6240
7154
|
this.storeSyncEffect = effect(() => {
|
|
6241
|
-
|
|
7155
|
+
// Gated on the execution state, not on the response being non-null: the effect runs once on
|
|
7156
|
+
// creation, and `response()` is null until the first one arrives - `id`/`set` are typed
|
|
7157
|
+
// non-nullable, so an unguarded write feeds `null` through them on every `prepare()`. A plain
|
|
7158
|
+
// null-check would be wrong the other way: a 204 is a success whose body is legitimately null.
|
|
7159
|
+
const execState = this.newQuery.executionState();
|
|
6242
7160
|
untracked(() => {
|
|
6243
|
-
if (this.entity?.set)
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
7161
|
+
if (execState?.type !== 'success' || !this.entity?.set)
|
|
7162
|
+
return;
|
|
7163
|
+
const res = execState.response;
|
|
7164
|
+
const id = this.entity.id({ args: this._arguments, response: res });
|
|
7165
|
+
this.entity.set({
|
|
7166
|
+
args: this._arguments,
|
|
7167
|
+
response: res,
|
|
7168
|
+
id,
|
|
7169
|
+
store: this.entity.store,
|
|
7170
|
+
});
|
|
6252
7171
|
});
|
|
6253
7172
|
}, /* @ts-ignore */
|
|
6254
7173
|
...(ngDevMode ? [{ debugName: "storeSyncEffect" }] : /* istanbul ignore next */ []));
|
|
@@ -6292,7 +7211,7 @@ class LegacyQuery {
|
|
|
6292
7211
|
return null;
|
|
6293
7212
|
}
|
|
6294
7213
|
get canBeCached() {
|
|
6295
|
-
return
|
|
7214
|
+
return this._canBeCached;
|
|
6296
7215
|
}
|
|
6297
7216
|
get _isInMockMode() {
|
|
6298
7217
|
return false;
|
|
@@ -6484,32 +7403,61 @@ const isInjectorUsable = (injector) => {
|
|
|
6484
7403
|
return false;
|
|
6485
7404
|
}
|
|
6486
7405
|
};
|
|
7406
|
+
/**
|
|
7407
|
+
* Angular's NG0203, thrown by `inject()` outside an injection context. Matched on the code rather than
|
|
7408
|
+
* the message: production builds strip the message, and NG0205 ("Injector has already been destroyed")
|
|
7409
|
+
* comes out of the same `inject()` call for a different reason entirely.
|
|
7410
|
+
*/
|
|
7411
|
+
const isMissingInjectionContextError = (error) => typeof error === 'object' && error !== null && Math.abs(Number(error.code)) === 203;
|
|
7412
|
+
/**
|
|
7413
|
+
* What the creator was built with, for diagnostics - `GET /person`. Lets an unnamed wrapper still point
|
|
7414
|
+
* at an endpoint instead of "a legacy query creator". A route function cannot be described this way, but
|
|
7415
|
+
* those wrappers come from the generator, which always emits a `name`.
|
|
7416
|
+
*/
|
|
7417
|
+
const describeCreator = (creator) => {
|
|
7418
|
+
const { method, route } = creator.subtle.creatorInternals;
|
|
7419
|
+
if (typeof route !== 'string')
|
|
7420
|
+
return undefined;
|
|
7421
|
+
return typeof method === 'string' ? `${method} ${route}` : route;
|
|
7422
|
+
};
|
|
7423
|
+
/**
|
|
7424
|
+
* Mirrors the cacheability decision the query repository makes per request: cacheable HTTP methods and
|
|
7425
|
+
* GraphQL queries, unless the creator opted in or out explicitly. The legacy container helpers branch on
|
|
7426
|
+
* `canBeCached` for their default cleanup, so a wrapper has to answer before the first execution.
|
|
7427
|
+
*/
|
|
7428
|
+
const canCreatorBeCached = (creator) => {
|
|
7429
|
+
const { method } = creator.subtle.creatorInternals;
|
|
7430
|
+
const explicit = creator.subtle.creatorOptions?.subtle
|
|
7431
|
+
?.useQueryRepositoryCache;
|
|
7432
|
+
if (explicit !== undefined)
|
|
7433
|
+
return explicit;
|
|
7434
|
+
if (method === 'QUERY')
|
|
7435
|
+
return true;
|
|
7436
|
+
if (method === 'MUTATE')
|
|
7437
|
+
return false;
|
|
7438
|
+
return typeof method === 'string' && shouldCacheQuery(method);
|
|
7439
|
+
};
|
|
7440
|
+
/**
|
|
7441
|
+
* @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.
|
|
7442
|
+
*/
|
|
6487
7443
|
class LegacyQueryCreator {
|
|
6488
7444
|
constructor(options) {
|
|
6489
7445
|
this.options = options;
|
|
6490
7446
|
this.prepare = (args) => {
|
|
6491
|
-
|
|
6492
|
-
// Angular's raw NG0203 names neither the query nor the call site, which makes those a bisection
|
|
6493
|
-
// exercise - replace it with an error that does.
|
|
6494
|
-
const injector = args?.injector ??
|
|
6495
|
-
(() => {
|
|
6496
|
-
try {
|
|
6497
|
-
return inject(Injector);
|
|
6498
|
-
}
|
|
6499
|
-
catch {
|
|
6500
|
-
throw legacyPrepareWithoutInjectionContext(this.options.name);
|
|
6501
|
-
}
|
|
6502
|
-
})();
|
|
7447
|
+
const injector = args?.injector ?? this.resolveAmbientInjector('prepare');
|
|
6503
7448
|
let headers = new HttpHeaders();
|
|
6504
7449
|
if (args?.headers) {
|
|
6505
|
-
Object.entries(args.headers)
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
7450
|
+
for (const [key, value] of Object.entries(args.headers)) {
|
|
7451
|
+
// Only an absent value is skipped - an empty string is a header the caller asked to send.
|
|
7452
|
+
if (value === undefined || value === null)
|
|
7453
|
+
continue;
|
|
7454
|
+
headers = headers.set(key, value);
|
|
7455
|
+
}
|
|
6510
7456
|
}
|
|
6511
7457
|
const queryArgs = {
|
|
6512
|
-
|
|
7458
|
+
// Presence, not truthiness: `0`, `''` and `false` are bodies, and dropping them silently sends a
|
|
7459
|
+
// different request than the call site asked for.
|
|
7460
|
+
...(args?.body !== undefined ? { body: args.body } : {}),
|
|
6513
7461
|
...(args?.pathParams ? { pathParams: args.pathParams } : {}),
|
|
6514
7462
|
...(args?.queryParams ? { queryParams: args.queryParams } : {}),
|
|
6515
7463
|
headers,
|
|
@@ -6520,10 +7468,10 @@ class LegacyQueryCreator {
|
|
|
6520
7468
|
// yields a query that does nothing instead of an NG0205 raised from the view's cleanup phase.
|
|
6521
7469
|
if (!isInjectorUsable(injector)) {
|
|
6522
7470
|
if (isDevMode()) {
|
|
6523
|
-
console.warn(`${this.
|
|
7471
|
+
console.warn(`${this.label ? `"${this.label}"` : 'A legacy query'}.prepare() was called with a destroyed injector, so an inert query was returned. ` +
|
|
6524
7472
|
`This usually means a callback outlived the component whose injector it captured - guard the call site with DestroyRef.onDestroy, or pass an injector that outlives it.`);
|
|
6525
7473
|
}
|
|
6526
|
-
return new LegacyQuery(createInertQuery(), queryArgs, this.options.entity, true);
|
|
7474
|
+
return new LegacyQuery(createInertQuery(), queryArgs, this.options.entity, true, this.canBeCached);
|
|
6527
7475
|
}
|
|
6528
7476
|
return runInInjectionContext(injector, () => {
|
|
6529
7477
|
return untracked(() => {
|
|
@@ -6534,33 +7482,71 @@ class LegacyQueryCreator {
|
|
|
6534
7482
|
// `LegacyQuery.execute()` forwards v2's `skipCache` as `allowCache` for every method, cacheable or not.
|
|
6535
7483
|
silenceUncacheableAllowCacheError: true,
|
|
6536
7484
|
});
|
|
6537
|
-
const legacyQuery = new LegacyQuery(newQuery, queryArgs, this.options.entity);
|
|
7485
|
+
const legacyQuery = new LegacyQuery(newQuery, queryArgs, this.options.entity, false, this.canBeCached);
|
|
6538
7486
|
if (args?.config?.destroyOnResponse) {
|
|
6539
|
-
|
|
6540
|
-
|
|
7487
|
+
// Owned by the query's own injector, not the caller's. Call sites are told to pass an injector
|
|
7488
|
+
// that outlives them, so they hand over a root or environment one - and an effect that only
|
|
7489
|
+
// tears itself down on a terminal state then outlives an aborted or never-executed query for
|
|
7490
|
+
// the lifetime of the app. Tied to the query, it dies with the thing it exists to destroy.
|
|
7491
|
+
effect(() => {
|
|
7492
|
+
const type = newQuery.executionState()?.type;
|
|
7493
|
+
if (type === 'success' || type === 'failure') {
|
|
6541
7494
|
legacyQuery.destroy();
|
|
6542
|
-
destroyEffect.destroy();
|
|
6543
7495
|
}
|
|
6544
|
-
},
|
|
6545
|
-
...(ngDevMode ? [{ debugName: "destroyEffect" }] : /* istanbul ignore next */ []));
|
|
7496
|
+
}, { injector: newQuery.subtle.injector });
|
|
6546
7497
|
}
|
|
6547
7498
|
return legacyQuery;
|
|
6548
7499
|
});
|
|
6549
7500
|
});
|
|
6550
7501
|
};
|
|
6551
7502
|
this.createSubject = (initialValue, config) => {
|
|
7503
|
+
const injector = config?.injector ?? this.resolveAmbientInjector('createSubject');
|
|
6552
7504
|
const subject = new BehaviorSubject(initialValue ?? null);
|
|
6553
|
-
addQueryContainerHandling(subject, () => subject.getValue(), config);
|
|
7505
|
+
addQueryContainerHandling(subject, () => subject.getValue(), { ...config, injector });
|
|
6554
7506
|
return subject;
|
|
6555
7507
|
};
|
|
6556
7508
|
this.createSignal = (initialValue, config) => {
|
|
7509
|
+
const injector = config?.injector ?? this.resolveAmbientInjector('createSignal');
|
|
6557
7510
|
const _signal = signal(initialValue ?? null, /* @ts-ignore */
|
|
6558
7511
|
...(ngDevMode ? [{ debugName: "_signal" }] : /* istanbul ignore next */ []));
|
|
6559
|
-
addQueryContainerHandling(toObservable(_signal), () => _signal(), config);
|
|
7512
|
+
addQueryContainerHandling(toObservable(_signal, { injector }), () => _signal(), { ...config, injector });
|
|
6560
7513
|
return _signal;
|
|
6561
7514
|
};
|
|
6562
7515
|
this.behaviorSubject = this.createSubject;
|
|
6563
7516
|
}
|
|
7517
|
+
/**
|
|
7518
|
+
* Whether the underlying request is cacheable, which is what the legacy container helpers use to decide
|
|
7519
|
+
* their default cleanup. Resolved from the creator, so it answers before the first execution.
|
|
7520
|
+
*/
|
|
7521
|
+
get canBeCached() {
|
|
7522
|
+
return canCreatorBeCached(this.options.creator);
|
|
7523
|
+
}
|
|
7524
|
+
get label() {
|
|
7525
|
+
return this.options.name ?? describeCreator(this.options.creator);
|
|
7526
|
+
}
|
|
7527
|
+
/**
|
|
7528
|
+
* v2 needed no injection context, so plenty of call sites are plain callbacks. Angular's raw NG0203
|
|
7529
|
+
* names neither the query nor the call site, which makes those a bisection exercise - replace it with
|
|
7530
|
+
* an error that does, and let every other DI failure (NG0205 from an injector mid-teardown, a missing
|
|
7531
|
+
* provider) through untouched.
|
|
7532
|
+
*/
|
|
7533
|
+
resolveAmbientInjector(method) {
|
|
7534
|
+
try {
|
|
7535
|
+
return inject(Injector);
|
|
7536
|
+
}
|
|
7537
|
+
catch (error) {
|
|
7538
|
+
if (!isMissingInjectionContextError(error)) {
|
|
7539
|
+
throw error;
|
|
7540
|
+
}
|
|
7541
|
+
const fallback = legacyPrepareFallbackInjector();
|
|
7542
|
+
// A stale stash (the app injector is gone) is no injector at all - handing it over would build a
|
|
7543
|
+
// query that silently never runs.
|
|
7544
|
+
if (fallback && isInjectorUsable(fallback)) {
|
|
7545
|
+
return fallback;
|
|
7546
|
+
}
|
|
7547
|
+
throw legacyPrepareWithoutInjectionContext(this.label, method);
|
|
7548
|
+
}
|
|
7549
|
+
}
|
|
6564
7550
|
}
|
|
6565
7551
|
/**
|
|
6566
7552
|
* Creates a legacy query creator.
|
|
@@ -6568,32 +7554,49 @@ class LegacyQueryCreator {
|
|
|
6568
7554
|
* **NOTE**: This is a temporary solution to support legacy queries. It will be removed in the future.
|
|
6569
7555
|
*
|
|
6570
7556
|
* **DO NOT TURN NEW QUERY CREATORS INTO LEGACY ONES MANUALLY. THIS IS ONLY NEEDED FOR MIGRATION PURPOSES.**
|
|
7557
|
+
*
|
|
7558
|
+
* @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.
|
|
6571
7559
|
*/
|
|
6572
7560
|
const createLegacyQueryCreator = (options) => {
|
|
6573
7561
|
return new LegacyQueryCreator(options);
|
|
6574
7562
|
};
|
|
6575
7563
|
|
|
6576
7564
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
7565
|
+
/**
|
|
7566
|
+
* @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.
|
|
7567
|
+
*/
|
|
6577
7568
|
function filterSuccess() {
|
|
6578
7569
|
return function (source) {
|
|
6579
7570
|
return source.pipe(filter((value) => isQueryStateSuccess(value)));
|
|
6580
7571
|
};
|
|
6581
7572
|
}
|
|
7573
|
+
/**
|
|
7574
|
+
* @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.
|
|
7575
|
+
*/
|
|
6582
7576
|
function ignoreAutoRefresh() {
|
|
6583
7577
|
return function (source) {
|
|
6584
7578
|
return source.pipe(filter((value) => !isAutoRefresh(value)));
|
|
6585
7579
|
};
|
|
6586
7580
|
}
|
|
7581
|
+
/**
|
|
7582
|
+
* @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.
|
|
7583
|
+
*/
|
|
6587
7584
|
function filterFailure() {
|
|
6588
7585
|
return function (source) {
|
|
6589
7586
|
return source.pipe(filter((value) => isQueryStateFailure(value)));
|
|
6590
7587
|
};
|
|
6591
7588
|
}
|
|
7589
|
+
/**
|
|
7590
|
+
* @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.
|
|
7591
|
+
*/
|
|
6592
7592
|
function filterQueryStates(allowedStates) {
|
|
6593
7593
|
return function (source) {
|
|
6594
7594
|
return source.pipe(filter((value) => value && allowedStates.includes(value.type)));
|
|
6595
7595
|
};
|
|
6596
7596
|
}
|
|
7597
|
+
/**
|
|
7598
|
+
* @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.
|
|
7599
|
+
*/
|
|
6597
7600
|
function takeUntilResponse(config) {
|
|
6598
7601
|
return function (source) {
|
|
6599
7602
|
return source.pipe(takeWhile((value) => {
|
|
@@ -6604,21 +7607,33 @@ function takeUntilResponse(config) {
|
|
|
6604
7607
|
}, true));
|
|
6605
7608
|
};
|
|
6606
7609
|
}
|
|
7610
|
+
/**
|
|
7611
|
+
* @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.
|
|
7612
|
+
*/
|
|
6607
7613
|
function filterNull() {
|
|
6608
7614
|
return function (source) {
|
|
6609
7615
|
return source.pipe(filter((value) => value !== null));
|
|
6610
7616
|
};
|
|
6611
7617
|
}
|
|
7618
|
+
/**
|
|
7619
|
+
* @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.
|
|
7620
|
+
*/
|
|
6612
7621
|
function switchQueryState() {
|
|
6613
7622
|
return function (source) {
|
|
6614
7623
|
return source.pipe(switchMap((value) => value?.state$ ?? of(null)));
|
|
6615
7624
|
};
|
|
6616
7625
|
}
|
|
7626
|
+
/**
|
|
7627
|
+
* @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.
|
|
7628
|
+
*/
|
|
6617
7629
|
function switchQueryCollectionState() {
|
|
6618
7630
|
return function (source) {
|
|
6619
7631
|
return source.pipe(switchMap((value) => value?.query.state$ ?? of(null)));
|
|
6620
7632
|
};
|
|
6621
7633
|
}
|
|
7634
|
+
/**
|
|
7635
|
+
* @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.
|
|
7636
|
+
*/
|
|
6622
7637
|
const resetPageOnError = (config) => (source) => {
|
|
6623
7638
|
const { queryForm, pageControlKey = 'page' } = config;
|
|
6624
7639
|
if (isDevMode() && !queryForm.form.controls[pageControlKey]) {
|
|
@@ -6647,12 +7662,33 @@ const resetPageOnError = (config) => (source) => {
|
|
|
6647
7662
|
}), takeUntilResponse());
|
|
6648
7663
|
}));
|
|
6649
7664
|
};
|
|
7665
|
+
/**
|
|
7666
|
+
* @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.
|
|
7667
|
+
*/
|
|
6650
7668
|
const isQueryStateLoading = (state) => state?.type === "LOADING" /* QueryStateType.Loading */;
|
|
7669
|
+
/**
|
|
7670
|
+
* @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.
|
|
7671
|
+
*/
|
|
6651
7672
|
const isQueryStateSuccess = (state) => state?.type === "SUCCESS" /* QueryStateType.Success */;
|
|
7673
|
+
/**
|
|
7674
|
+
* @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.
|
|
7675
|
+
*/
|
|
6652
7676
|
const isQueryStateFailure = (state) => state?.type === "FAILURE" /* QueryStateType.Failure */;
|
|
7677
|
+
/**
|
|
7678
|
+
* @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.
|
|
7679
|
+
*/
|
|
6653
7680
|
const isQueryStateCancelled = (state) => state?.type === "CANCELLED" /* QueryStateType.Cancelled */;
|
|
7681
|
+
/**
|
|
7682
|
+
* @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.
|
|
7683
|
+
*/
|
|
6654
7684
|
const isQueryStatePrepared = (state) => state?.type === "PREPARED" /* QueryStateType.Prepared */;
|
|
7685
|
+
/**
|
|
7686
|
+
* @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.
|
|
7687
|
+
*/
|
|
6655
7688
|
const isAutoRefresh = (state) => state?.meta.triggeredVia === 'auto';
|
|
7689
|
+
/**
|
|
7690
|
+
* @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.
|
|
7691
|
+
*/
|
|
6656
7692
|
const mergeHeaders = (...headers) => {
|
|
6657
7693
|
return headers.reduce((acc, headers) => {
|
|
6658
7694
|
if (!headers) {
|
|
@@ -6664,6 +7700,9 @@ const mergeHeaders = (...headers) => {
|
|
|
6664
7700
|
};
|
|
6665
7701
|
}, {});
|
|
6666
7702
|
};
|
|
7703
|
+
/**
|
|
7704
|
+
* @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.
|
|
7705
|
+
*/
|
|
6667
7706
|
const isGqlQueryConfig = (config) => {
|
|
6668
7707
|
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
6669
7708
|
return false;
|
|
@@ -6673,6 +7712,9 @@ const isGqlQueryConfig = (config) => {
|
|
|
6673
7712
|
}
|
|
6674
7713
|
return true;
|
|
6675
7714
|
};
|
|
7715
|
+
/**
|
|
7716
|
+
* @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.
|
|
7717
|
+
*/
|
|
6676
7718
|
const isQuery = (query) => {
|
|
6677
7719
|
if (!query || typeof query !== 'object' || Array.isArray(query)) {
|
|
6678
7720
|
return false;
|
|
@@ -6682,6 +7724,9 @@ const isQuery = (query) => {
|
|
|
6682
7724
|
}
|
|
6683
7725
|
return true;
|
|
6684
7726
|
};
|
|
7727
|
+
/**
|
|
7728
|
+
* @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.
|
|
7729
|
+
*/
|
|
6685
7730
|
const isQueryCollection = (query) => {
|
|
6686
7731
|
if (!query || typeof query !== 'object' || Array.isArray(query)) {
|
|
6687
7732
|
return false;
|
|
@@ -6691,9 +7736,15 @@ const isQueryCollection = (query) => {
|
|
|
6691
7736
|
}
|
|
6692
7737
|
return true;
|
|
6693
7738
|
};
|
|
7739
|
+
/**
|
|
7740
|
+
* @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.
|
|
7741
|
+
*/
|
|
6694
7742
|
const createQueryCollection = (
|
|
6695
7743
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6696
7744
|
queryMap) => new BehaviorSubject(null);
|
|
7745
|
+
/**
|
|
7746
|
+
* @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.
|
|
7747
|
+
*/
|
|
6697
7748
|
const createQueryCollectionSubject = (
|
|
6698
7749
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6699
7750
|
queryMap, config) => {
|
|
@@ -6702,6 +7753,9 @@ queryMap, config) => {
|
|
|
6702
7753
|
addQueryContainerHandling(subject.pipe(map((s) => s?.query ?? null)), () => subject.getValue()?.query ?? null, config);
|
|
6703
7754
|
return subject;
|
|
6704
7755
|
};
|
|
7756
|
+
/**
|
|
7757
|
+
* @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.
|
|
7758
|
+
*/
|
|
6705
7759
|
const createQueryCollectionSignal = (
|
|
6706
7760
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6707
7761
|
queryMap, config) => {
|
|
@@ -6711,7 +7765,13 @@ queryMap, config) => {
|
|
|
6711
7765
|
addQueryContainerHandling(toObservable(_signal).pipe(map((s) => s?.query ?? null)), () => _signal()?.query ?? null, config);
|
|
6712
7766
|
return _signal;
|
|
6713
7767
|
};
|
|
7768
|
+
/**
|
|
7769
|
+
* @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.
|
|
7770
|
+
*/
|
|
6714
7771
|
const extractQuery = (v) => (isQuery(v) ? v : isLegacyQuery(v) ? v : v?.query) ?? null;
|
|
7772
|
+
/**
|
|
7773
|
+
* @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.
|
|
7774
|
+
*/
|
|
6715
7775
|
const getDefaultHeaders = (headers, method) => {
|
|
6716
7776
|
if (!headers) {
|
|
6717
7777
|
return {};
|
|
@@ -6721,6 +7781,9 @@ const getDefaultHeaders = (headers, method) => {
|
|
|
6721
7781
|
}
|
|
6722
7782
|
return headers;
|
|
6723
7783
|
};
|
|
7784
|
+
/**
|
|
7785
|
+
* @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.
|
|
7786
|
+
*/
|
|
6724
7787
|
const castQueryCreatorTypes = (config) => {
|
|
6725
7788
|
if (config.args?.pathParams) {
|
|
6726
7789
|
console.error(config);
|
|
@@ -6728,6 +7791,9 @@ const castQueryCreatorTypes = (config) => {
|
|
|
6728
7791
|
}
|
|
6729
7792
|
return config.creator;
|
|
6730
7793
|
};
|
|
7794
|
+
/**
|
|
7795
|
+
* @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.
|
|
7796
|
+
*/
|
|
6731
7797
|
const computeQueryMethod = (config) => {
|
|
6732
7798
|
let method;
|
|
6733
7799
|
if (isGqlQueryConfig(config.config)) {
|
|
@@ -6739,6 +7805,9 @@ const computeQueryMethod = (config) => {
|
|
|
6739
7805
|
}
|
|
6740
7806
|
return method;
|
|
6741
7807
|
};
|
|
7808
|
+
/**
|
|
7809
|
+
* @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.
|
|
7810
|
+
*/
|
|
6742
7811
|
const computeQueryBody = (config) => {
|
|
6743
7812
|
let body;
|
|
6744
7813
|
if (config.method === 'GET' ||
|
|
@@ -6759,6 +7828,9 @@ const computeQueryBody = (config) => {
|
|
|
6759
7828
|
}
|
|
6760
7829
|
return body;
|
|
6761
7830
|
};
|
|
7831
|
+
/**
|
|
7832
|
+
* @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.
|
|
7833
|
+
*/
|
|
6762
7834
|
const computeQueryAuthHeader = (config) => {
|
|
6763
7835
|
let authHeader = null;
|
|
6764
7836
|
if (config.config.secure) {
|
|
@@ -6774,11 +7846,17 @@ const computeQueryAuthHeader = (config) => {
|
|
|
6774
7846
|
}
|
|
6775
7847
|
return authHeader;
|
|
6776
7848
|
};
|
|
7849
|
+
/**
|
|
7850
|
+
* @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.
|
|
7851
|
+
*/
|
|
6777
7852
|
const computeQueryHeaders = (config) => {
|
|
6778
7853
|
const authHeader = computeQueryAuthHeader(config);
|
|
6779
7854
|
const mergedHeaders = mergeHeaders(getDefaultHeaders(config.client.config.request?.headers, config.config.method), authHeader, config.args?.headers) || undefined;
|
|
6780
7855
|
return mergedHeaders;
|
|
6781
7856
|
};
|
|
7857
|
+
/**
|
|
7858
|
+
* @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.
|
|
7859
|
+
*/
|
|
6782
7860
|
const computeQueryQueryParams = (config) => {
|
|
6783
7861
|
if (isGqlQueryConfig(config.config) &&
|
|
6784
7862
|
(config.config.transferVia === 'GET' ||
|
|
@@ -6793,6 +7871,9 @@ const computeQueryQueryParams = (config) => {
|
|
|
6793
7871
|
}
|
|
6794
7872
|
return config.args?.queryParams;
|
|
6795
7873
|
};
|
|
7874
|
+
/**
|
|
7875
|
+
* @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.
|
|
7876
|
+
*/
|
|
6796
7877
|
const paginatedEntityValueUpdater = (findFn) => ({ response, rawResponse, entity }) => {
|
|
6797
7878
|
const indexOfEntityRaw = rawResponse.items.findIndex((item) => findFn(item, entity));
|
|
6798
7879
|
const indexOfEntity = response.items.findIndex((item) => findFn(item, entity));
|
|
@@ -6818,6 +7899,9 @@ const paginatedEntityValueUpdater = (findFn) => ({ response, rawResponse, entity
|
|
|
6818
7899
|
};
|
|
6819
7900
|
|
|
6820
7901
|
let _nextQueryId = 0;
|
|
7902
|
+
/**
|
|
7903
|
+
* @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.
|
|
7904
|
+
*/
|
|
6821
7905
|
class V2Query {
|
|
6822
7906
|
constructor(_client,
|
|
6823
7907
|
/**
|
|
@@ -7249,10 +8333,22 @@ class V2Query {
|
|
|
7249
8333
|
}
|
|
7250
8334
|
}
|
|
7251
8335
|
|
|
8336
|
+
/**
|
|
8337
|
+
* @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.
|
|
8338
|
+
*/
|
|
7252
8339
|
const isBasicAuthProvider = (authProvider) => authProvider instanceof BasicAuthProvider;
|
|
8340
|
+
/**
|
|
8341
|
+
* @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.
|
|
8342
|
+
*/
|
|
7253
8343
|
const isBearerAuthProvider = (authProvider) => authProvider instanceof V2BearerAuthProvider;
|
|
8344
|
+
/**
|
|
8345
|
+
* @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.
|
|
8346
|
+
*/
|
|
7254
8347
|
const isCustomHeaderAuthProvider = (authProvider) => authProvider instanceof CustomHeaderAuthProvider;
|
|
7255
8348
|
|
|
8349
|
+
/**
|
|
8350
|
+
* @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.
|
|
8351
|
+
*/
|
|
7256
8352
|
class V2BearerAuthProvider {
|
|
7257
8353
|
constructor(_config) {
|
|
7258
8354
|
this._config = _config;
|
|
@@ -7431,9 +8527,18 @@ const INFINITY_QUERY_RESPONSE_DELAY_DEF = /* @__PURE__ */ defineProvider(() => {
|
|
|
7431
8527
|
enabled$,
|
|
7432
8528
|
};
|
|
7433
8529
|
}, { name: 'Infinity Query Response Delay' });
|
|
8530
|
+
/**
|
|
8531
|
+
* @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.
|
|
8532
|
+
*/
|
|
7434
8533
|
const provideInfinityQueryResponseDelay = /* @__PURE__ */ toProvideFn(INFINITY_QUERY_RESPONSE_DELAY_DEF);
|
|
8534
|
+
/**
|
|
8535
|
+
* @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.
|
|
8536
|
+
*/
|
|
7435
8537
|
const injectInfinityQueryResponseDelay = /* @__PURE__ */ toInjectFn(INFINITY_QUERY_RESPONSE_DELAY_DEF);
|
|
7436
8538
|
|
|
8539
|
+
/**
|
|
8540
|
+
* @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.
|
|
8541
|
+
*/
|
|
7437
8542
|
class InfinityQuery {
|
|
7438
8543
|
constructor(_config, _destroy$) {
|
|
7439
8544
|
this._config = _config;
|
|
@@ -7604,11 +8709,23 @@ class InfinityQuery {
|
|
|
7604
8709
|
}
|
|
7605
8710
|
}
|
|
7606
8711
|
|
|
8712
|
+
/**
|
|
8713
|
+
* @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.
|
|
8714
|
+
*/
|
|
7607
8715
|
const createInfinityQueryConfig = (config) => config;
|
|
8716
|
+
/**
|
|
8717
|
+
* @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.
|
|
8718
|
+
*/
|
|
7608
8719
|
const skipPaginationPageParamCalculator = ({ page, itemsPerPage }) => itemsPerPage * (page - 1);
|
|
7609
8720
|
|
|
7610
8721
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
8722
|
+
/**
|
|
8723
|
+
* @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.
|
|
8724
|
+
*/
|
|
7611
8725
|
const INFINITY_QUERY_TOKEN = new InjectionToken('INFINITY_QUERY_TOKEN');
|
|
8726
|
+
/**
|
|
8727
|
+
* @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.
|
|
8728
|
+
*/
|
|
7612
8729
|
class InfinityQueryDirective {
|
|
7613
8730
|
// TODO: Skipped for migration because:
|
|
7614
8731
|
// Accessor inputs cannot be migrated as they are too complex.
|
|
@@ -7757,6 +8874,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
7757
8874
|
args: ['etInfinityQuery']
|
|
7758
8875
|
}] } });
|
|
7759
8876
|
|
|
8877
|
+
/**
|
|
8878
|
+
* @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.
|
|
8879
|
+
*/
|
|
7760
8880
|
class InfinityQueryTriggerDirective {
|
|
7761
8881
|
constructor() {
|
|
7762
8882
|
this.elementRef = inject(ElementRef);
|
|
@@ -7812,6 +8932,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
7812
8932
|
}]
|
|
7813
8933
|
}], propDecorators: { scrollContainerSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollContainerSelector", required: false }] }], infinityQueryOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "infinityQueryOverride", required: false }] }] } });
|
|
7814
8934
|
|
|
8935
|
+
/**
|
|
8936
|
+
* @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.
|
|
8937
|
+
*/
|
|
7815
8938
|
class QueryDirective {
|
|
7816
8939
|
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7817
8940
|
return true;
|
|
@@ -7901,6 +9024,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
7901
9024
|
}]
|
|
7902
9025
|
}], ctorParameters: () => [], propDecorators: { query: [{ type: i0.Input, args: [{ isSignal: true, alias: "etQuery", required: true }] }], cache: [{ type: i0.Input, args: [{ isSignal: true, alias: "etQueryCache", required: false }] }] } });
|
|
7903
9026
|
|
|
9027
|
+
/**
|
|
9028
|
+
* @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.
|
|
9029
|
+
*/
|
|
7904
9030
|
class QueryShortNamePipe {
|
|
7905
9031
|
transform(value) {
|
|
7906
9032
|
const route = value._routeWithParams;
|
|
@@ -7923,7 +9049,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
7923
9049
|
args: [{ name: 'queryShortName' }]
|
|
7924
9050
|
}] });
|
|
7925
9051
|
|
|
9052
|
+
/**
|
|
9053
|
+
* @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.
|
|
9054
|
+
*/
|
|
7926
9055
|
const QUERY_CLIENT_DEVTOOLS_TOKEN = new InjectionToken('QUERY_CLIENT_DEVTOOLS_TOKEN');
|
|
9056
|
+
/**
|
|
9057
|
+
* @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.
|
|
9058
|
+
*/
|
|
7927
9059
|
const provideQueryClientForDevtools = (queryClient) => {
|
|
7928
9060
|
if (!isDevMode()) {
|
|
7929
9061
|
console.warn('You are using the Query Devtools in production mode. This increases the size of your bundle and should only be used for development purposes.');
|
|
@@ -7935,6 +9067,9 @@ const provideQueryClientForDevtools = (queryClient) => {
|
|
|
7935
9067
|
};
|
|
7936
9068
|
};
|
|
7937
9069
|
|
|
9070
|
+
/**
|
|
9071
|
+
* @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.
|
|
9072
|
+
*/
|
|
7938
9073
|
class QueryDevtoolsComponent {
|
|
7939
9074
|
constructor() {
|
|
7940
9075
|
this.cdr = inject(ChangeDetectorRef);
|
|
@@ -8244,6 +9379,9 @@ class EntityStoreError extends Error {
|
|
|
8244
9379
|
function flatten(arr) {
|
|
8245
9380
|
return arr.reduce((acc, val) => acc.concat(val), []);
|
|
8246
9381
|
}
|
|
9382
|
+
/**
|
|
9383
|
+
* @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.
|
|
9384
|
+
*/
|
|
8247
9385
|
class EntityStore {
|
|
8248
9386
|
constructor(_config) {
|
|
8249
9387
|
this._config = _config;
|
|
@@ -8360,12 +9498,17 @@ class EntityStore {
|
|
|
8360
9498
|
}
|
|
8361
9499
|
}
|
|
8362
9500
|
|
|
9501
|
+
/**
|
|
9502
|
+
* @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.
|
|
9503
|
+
*/
|
|
8363
9504
|
function mapToPaginated(response) {
|
|
8364
9505
|
return map((items) => ({ ...response, items }));
|
|
8365
9506
|
}
|
|
8366
9507
|
// FIXME: This breaks if SubStoreType is an array
|
|
8367
9508
|
/**
|
|
8368
9509
|
* Use an other store to represent a property of the current entity.
|
|
9510
|
+
*
|
|
9511
|
+
* @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.
|
|
8369
9512
|
*/
|
|
8370
9513
|
const insertFrom = (store, { for: key, id }) => switchMap((value) => {
|
|
8371
9514
|
if (!value)
|
|
@@ -8380,6 +9523,8 @@ const insertFrom = (store, { for: key, id }) => switchMap((value) => {
|
|
|
8380
9523
|
});
|
|
8381
9524
|
/**
|
|
8382
9525
|
* Remove entities from a store based on a where function.
|
|
9526
|
+
*
|
|
9527
|
+
* @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.
|
|
8383
9528
|
*/
|
|
8384
9529
|
const removeFrom = (store, { where, id }) => {
|
|
8385
9530
|
store
|
|
@@ -8388,9 +9533,21 @@ const removeFrom = (store, { where, id }) => {
|
|
|
8388
9533
|
.subscribe();
|
|
8389
9534
|
};
|
|
8390
9535
|
|
|
9536
|
+
/**
|
|
9537
|
+
* @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.
|
|
9538
|
+
*/
|
|
8391
9539
|
const queryStateAlreadyHasKeyError = (data) => new QueryError('004', 'The query state already contains the provided key', data);
|
|
9540
|
+
/**
|
|
9541
|
+
* @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.
|
|
9542
|
+
*/
|
|
8392
9543
|
const queryStateDoesNotContainKeyError = (data) => new QueryError('005', 'The query state does not contain the provided key', data);
|
|
9544
|
+
/**
|
|
9545
|
+
* @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.
|
|
9546
|
+
*/
|
|
8393
9547
|
const queryStateCannotTransformError = (data) => new QueryError('006', 'The query state cannot be transformed because it is not loading', data);
|
|
9548
|
+
/**
|
|
9549
|
+
* @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.
|
|
9550
|
+
*/
|
|
8394
9551
|
const invalidBodyError = (data) => new QueryError('007', 'The body is not valid or upsupported', data);
|
|
8395
9552
|
|
|
8396
9553
|
/**
|
|
@@ -8415,6 +9572,8 @@ const invalidBodyError = (data) => new QueryError('007', 'The body is not valid
|
|
|
8415
9572
|
* });
|
|
8416
9573
|
* });
|
|
8417
9574
|
* ```
|
|
9575
|
+
*
|
|
9576
|
+
* @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.
|
|
8418
9577
|
*/
|
|
8419
9578
|
const validateWithV2Query = (path, config) => {
|
|
8420
9579
|
applyQueryAsyncValidator(path, {
|
|
@@ -9556,6 +10715,16 @@ const createBranch = (fields, initial, injector) => {
|
|
|
9556
10715
|
resetAllFieldsToDefault: () => model.set(clone(defaults)),
|
|
9557
10716
|
};
|
|
9558
10717
|
};
|
|
10718
|
+
/**
|
|
10719
|
+
* Per-name sequence behind the devtools id of a form, mirroring the registry's own scheme so the
|
|
10720
|
+
* panel can restore the selected form after a reload.
|
|
10721
|
+
*/
|
|
10722
|
+
const devtoolsIdCounters = /* @__PURE__ */ new Map();
|
|
10723
|
+
const nextQueryFormDevtoolsId = (name) => {
|
|
10724
|
+
const seq = devtoolsIdCounters.get(name) ?? 0;
|
|
10725
|
+
devtoolsIdCounters.set(name, seq + 1);
|
|
10726
|
+
return `query-form|${name}#${seq}`;
|
|
10727
|
+
};
|
|
9559
10728
|
/**
|
|
9560
10729
|
* A signals-first query form: binds on-screen controls to typed fields, keeps a
|
|
9561
10730
|
* debounced committed value, syncs to the URL query params, and resets dependent
|
|
@@ -9582,6 +10751,8 @@ class QueryFormSignals {
|
|
|
9582
10751
|
this.observing = signal(false, /* @ts-ignore */
|
|
9583
10752
|
...(ngDevMode ? [{ debugName: "observing" }] : /* istanbul ignore next */ []));
|
|
9584
10753
|
this.pendingTimer = null;
|
|
10754
|
+
this.commitPending = signal(false, /* @ts-ignore */
|
|
10755
|
+
...(ngDevMode ? [{ debugName: "commitPending" }] : /* istanbul ignore next */ []));
|
|
9585
10756
|
this.skipNextResets = false;
|
|
9586
10757
|
assertInInjectionContext(QueryFormSignals);
|
|
9587
10758
|
this._fields = config.fields;
|
|
@@ -9594,7 +10765,16 @@ class QueryFormSignals {
|
|
|
9594
10765
|
this.committed = signal(clone(initial), /* @ts-ignore */
|
|
9595
10766
|
...(ngDevMode ? [{ debugName: "committed" }] : /* istanbul ignore next */ []));
|
|
9596
10767
|
this.fields = form(this.model);
|
|
9597
|
-
this.
|
|
10768
|
+
const devtoolsName = config.name ?? (typeof this.prefix === 'string' ? this.prefix : 'form');
|
|
10769
|
+
const devtoolsId = isQueryDevtoolsEnabled() ? nextQueryFormDevtoolsId(devtoolsName) : null;
|
|
10770
|
+
// Reading `value` is how a query's args pick the form up, so the devtools learn which query a form
|
|
10771
|
+
// drives by noting the read - see `QueryDevtoolsFormLinksHandle`.
|
|
10772
|
+
this.value = devtoolsId
|
|
10773
|
+
? computed(() => {
|
|
10774
|
+
noteQueryFormRead(devtoolsId);
|
|
10775
|
+
return this.committed();
|
|
10776
|
+
})
|
|
10777
|
+
: this.committed.asReadonly();
|
|
9598
10778
|
this.previousValue = this.previous.asReadonly();
|
|
9599
10779
|
this.changes = computed(() => ({ previousValue: this.previous(), currentValue: this.committed() }), /* @ts-ignore */
|
|
9600
10780
|
...(ngDevMode ? [{ debugName: "changes" }] : /* istanbul ignore next */ []));
|
|
@@ -9614,7 +10794,16 @@ class QueryFormSignals {
|
|
|
9614
10794
|
this.applyFromUrl(changes);
|
|
9615
10795
|
});
|
|
9616
10796
|
});
|
|
9617
|
-
inject(DestroyRef)
|
|
10797
|
+
const destroyRef = inject(DestroyRef);
|
|
10798
|
+
destroyRef.onDestroy(() => this.cleanup());
|
|
10799
|
+
if (devtoolsId) {
|
|
10800
|
+
destroyRef.onDestroy(registerQueryDevtoolsEntry({
|
|
10801
|
+
id: devtoolsId,
|
|
10802
|
+
kind: 'query-form',
|
|
10803
|
+
handle: this.devtoolsHandle(),
|
|
10804
|
+
meta: { name: devtoolsName },
|
|
10805
|
+
}));
|
|
10806
|
+
}
|
|
9618
10807
|
}
|
|
9619
10808
|
observe(options) {
|
|
9620
10809
|
if (this.observing()) {
|
|
@@ -9670,6 +10859,46 @@ class QueryFormSignals {
|
|
|
9670
10859
|
branch() {
|
|
9671
10860
|
return createBranch(this._fields, clone(this.committed()), this.injector);
|
|
9672
10861
|
}
|
|
10862
|
+
/**
|
|
10863
|
+
* The live view `<et-query-devtools>` renders. Only built while the devtools are installed - it walks
|
|
10864
|
+
* every field on every change, which an app without them should not pay for.
|
|
10865
|
+
*/
|
|
10866
|
+
devtoolsHandle() {
|
|
10867
|
+
const fields = computed(() => {
|
|
10868
|
+
const committed = this.committed();
|
|
10869
|
+
const live = this.model();
|
|
10870
|
+
return Object.entries(this._fields).map(([key, def]) => {
|
|
10871
|
+
const value = committed[key];
|
|
10872
|
+
return {
|
|
10873
|
+
key,
|
|
10874
|
+
paramKey: this.paramKey(key),
|
|
10875
|
+
value,
|
|
10876
|
+
liveValue: live[key],
|
|
10877
|
+
defaultValue: this.defaults[key],
|
|
10878
|
+
isDefault: equal(value, this.defaults[key]),
|
|
10879
|
+
queryParam: this.queryParamFor(key, def, value),
|
|
10880
|
+
debounceMs: def.debounce ?? null,
|
|
10881
|
+
isResetBy: def.isResetBy ?? [],
|
|
10882
|
+
countsAsFilter: !IGNORED_FILTER_COUNT_FIELDS.includes(key) && !def.skipInFilterCount,
|
|
10883
|
+
};
|
|
10884
|
+
});
|
|
10885
|
+
}, /* @ts-ignore */
|
|
10886
|
+
...(ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []));
|
|
10887
|
+
return {
|
|
10888
|
+
fields,
|
|
10889
|
+
// Not `this.value` - reading that from the panel would link the form to whichever query happens
|
|
10890
|
+
// to be building its args at the time.
|
|
10891
|
+
value: computed(() => this.committed()),
|
|
10892
|
+
previousValue: computed(() => this.previous() ?? null),
|
|
10893
|
+
defaultValue: this.defaults,
|
|
10894
|
+
activeFilterCount: this.activeFilterCount,
|
|
10895
|
+
isAtDefaults: computed(() => equal(this.committed(), this.defaults)),
|
|
10896
|
+
isCommitPending: this.commitPending.asReadonly(),
|
|
10897
|
+
isObserving: this.observing.asReadonly(),
|
|
10898
|
+
resetField: (key) => this.resetFieldToDefault(key),
|
|
10899
|
+
resetAll: () => this.resetAllFieldsToDefault(),
|
|
10900
|
+
};
|
|
10901
|
+
}
|
|
9673
10902
|
onLiveChange(live) {
|
|
9674
10903
|
if (!this.observing())
|
|
9675
10904
|
return;
|
|
@@ -9682,6 +10911,7 @@ class QueryFormSignals {
|
|
|
9682
10911
|
this.flush();
|
|
9683
10912
|
}
|
|
9684
10913
|
else {
|
|
10914
|
+
this.commitPending.set(true);
|
|
9685
10915
|
this.pendingTimer = setTimeout(() => {
|
|
9686
10916
|
this.pendingTimer = null;
|
|
9687
10917
|
this.flush();
|
|
@@ -9782,23 +11012,21 @@ class QueryFormSignals {
|
|
|
9782
11012
|
return raw;
|
|
9783
11013
|
return autoCoerce(raw, resolveDefault(def));
|
|
9784
11014
|
}
|
|
11015
|
+
/** What a field puts in the URL for a given value, or `undefined` when it writes nothing. */
|
|
11016
|
+
queryParamFor(key, def, value) {
|
|
11017
|
+
const isDefault = equal(value, this.defaults[key]);
|
|
11018
|
+
const writeToUrl = def.appendToUrl !== false;
|
|
11019
|
+
const writeDefault = def.appendDefaultValueToUrl === true;
|
|
11020
|
+
if (!writeToUrl || (isDefault && !writeDefault))
|
|
11021
|
+
return undefined;
|
|
11022
|
+
if (def.valueToQueryParam)
|
|
11023
|
+
return def.valueToQueryParam(value);
|
|
11024
|
+
return value === null ? ET_NULL_VALUE : value;
|
|
11025
|
+
}
|
|
9785
11026
|
writeToUrl(value) {
|
|
9786
11027
|
const queryParams = {};
|
|
9787
11028
|
for (const [key, def] of Object.entries(this._fields)) {
|
|
9788
|
-
|
|
9789
|
-
const fieldValue = value[key];
|
|
9790
|
-
const isDefault = equal(fieldValue, this.defaults[key]);
|
|
9791
|
-
const writeToUrl = def.appendToUrl !== false;
|
|
9792
|
-
const writeDefault = def.appendDefaultValueToUrl === true;
|
|
9793
|
-
if (!writeToUrl || (isDefault && !writeDefault)) {
|
|
9794
|
-
queryParams[paramKey] = undefined;
|
|
9795
|
-
}
|
|
9796
|
-
else if (def.valueToQueryParam) {
|
|
9797
|
-
queryParams[paramKey] = def.valueToQueryParam(fieldValue);
|
|
9798
|
-
}
|
|
9799
|
-
else {
|
|
9800
|
-
queryParams[paramKey] = fieldValue === null ? ET_NULL_VALUE : fieldValue;
|
|
9801
|
-
}
|
|
11029
|
+
queryParams[this.paramKey(key)] = this.queryParamFor(key, def, value[key]);
|
|
9802
11030
|
}
|
|
9803
11031
|
queueMicrotask(() => {
|
|
9804
11032
|
this.router.navigate([], {
|
|
@@ -9819,6 +11047,7 @@ class QueryFormSignals {
|
|
|
9819
11047
|
clearTimeout(this.pendingTimer);
|
|
9820
11048
|
this.pendingTimer = null;
|
|
9821
11049
|
}
|
|
11050
|
+
this.commitPending.set(false);
|
|
9822
11051
|
}
|
|
9823
11052
|
cleanup() {
|
|
9824
11053
|
if (!this.observing())
|
|
@@ -9929,7 +11158,7 @@ const messageMalformed = () => {
|
|
|
9929
11158
|
const MAX_DEVTOOLS_MESSAGES = 100;
|
|
9930
11159
|
const createWebSocketClient = (options) => {
|
|
9931
11160
|
return defineRootProvider(() => {
|
|
9932
|
-
const socket = io(options.url, {
|
|
11161
|
+
const socket = options.io(options.url, {
|
|
9933
11162
|
withCredentials: true,
|
|
9934
11163
|
autoConnect: false,
|
|
9935
11164
|
transports: options.transports,
|
|
@@ -9948,13 +11177,28 @@ const createWebSocketClient = (options) => {
|
|
|
9948
11177
|
if (devtoolsEnabled)
|
|
9949
11178
|
devtoolsRooms.set([...rooms.keys()]);
|
|
9950
11179
|
};
|
|
11180
|
+
const recordDevtoolsMessage = (message) => {
|
|
11181
|
+
if (!devtoolsEnabled)
|
|
11182
|
+
return;
|
|
11183
|
+
devtoolsMessages.update((log) => [{ ...message, id: devtoolsMessageId++, timestamp: Date.now() }, ...log].slice(0, MAX_DEVTOOLS_MESSAGES));
|
|
11184
|
+
};
|
|
11185
|
+
/** Every outgoing message goes through here, so the devtools log covers both directions. */
|
|
11186
|
+
const emit = (message) => {
|
|
11187
|
+
socket.emit(message.event, message.data);
|
|
11188
|
+
recordDevtoolsMessage({
|
|
11189
|
+
room: message.room ?? '',
|
|
11190
|
+
event: message.event,
|
|
11191
|
+
data: message.data,
|
|
11192
|
+
direction: 'out',
|
|
11193
|
+
});
|
|
11194
|
+
};
|
|
9951
11195
|
const joinRoom = (room) => {
|
|
9952
11196
|
const roomFn = typeof room === 'function' ? room : () => room;
|
|
9953
11197
|
const pre = previousSignalValue(computed(() => roomFn()));
|
|
9954
11198
|
const roomData = signal(null, /* @ts-ignore */
|
|
9955
11199
|
...(ngDevMode ? [{ debugName: "roomData" }] : /* istanbul ignore next */ []));
|
|
9956
11200
|
const join = (name) => {
|
|
9957
|
-
|
|
11201
|
+
emit({ event: 'join-room', data: name, room: name });
|
|
9958
11202
|
const existingRoom = rooms.get(name);
|
|
9959
11203
|
if (existingRoom)
|
|
9960
11204
|
return existingRoom;
|
|
@@ -9999,7 +11243,7 @@ const createWebSocketClient = (options) => {
|
|
|
9999
11243
|
if (isDevMode())
|
|
10000
11244
|
throw roomNotJoined(room);
|
|
10001
11245
|
}
|
|
10002
|
-
|
|
11246
|
+
emit({ event: 'leave-room', data: room, room });
|
|
10003
11247
|
rooms.delete(room);
|
|
10004
11248
|
syncDevtoolsRooms();
|
|
10005
11249
|
};
|
|
@@ -10007,7 +11251,7 @@ const createWebSocketClient = (options) => {
|
|
|
10007
11251
|
socket.on('connect', () => {
|
|
10008
11252
|
isConnected.set(true);
|
|
10009
11253
|
for (const room of rooms.keys()) {
|
|
10010
|
-
|
|
11254
|
+
emit({ event: 'join-room', data: room, room });
|
|
10011
11255
|
}
|
|
10012
11256
|
});
|
|
10013
11257
|
socket.on('disconnect', () => isConnected.set(false));
|
|
@@ -10016,16 +11260,7 @@ const createWebSocketClient = (options) => {
|
|
|
10016
11260
|
socket.onAny((data) => {
|
|
10017
11261
|
try {
|
|
10018
11262
|
const json = JSON.parse(data);
|
|
10019
|
-
|
|
10020
|
-
const message = {
|
|
10021
|
-
id: devtoolsMessageId++,
|
|
10022
|
-
timestamp: Date.now(),
|
|
10023
|
-
room: json.room,
|
|
10024
|
-
event: json.event,
|
|
10025
|
-
data: json.data,
|
|
10026
|
-
};
|
|
10027
|
-
devtoolsMessages.update((log) => [message, ...log].slice(0, MAX_DEVTOOLS_MESSAGES));
|
|
10028
|
-
}
|
|
11263
|
+
recordDevtoolsMessage({ room: json.room, event: json.event, data: json.data, direction: 'in' });
|
|
10029
11264
|
const room = rooms.get(json.room);
|
|
10030
11265
|
if (room)
|
|
10031
11266
|
room.latestMessage.set(json);
|
|
@@ -10053,6 +11288,7 @@ const createWebSocketClient = (options) => {
|
|
|
10053
11288
|
connected: isConnected.asReadonly(),
|
|
10054
11289
|
rooms: devtoolsRooms.asReadonly(),
|
|
10055
11290
|
messages: devtoolsMessages.asReadonly(),
|
|
11291
|
+
emit,
|
|
10056
11292
|
};
|
|
10057
11293
|
const unregister = registerQueryDevtoolsEntry({
|
|
10058
11294
|
kind: 'ws-client',
|
|
@@ -10071,5 +11307,5 @@ const createWebSocketClient = (options) => {
|
|
|
10071
11307
|
* Generated bundle index. Do not edit.
|
|
10072
11308
|
*/
|
|
10073
11309
|
|
|
10074
|
-
export { BasicAuthProvider, BearerAuthFeatureType, BooleanArrayQueryField, CLEAR_QUERY_ARGS, 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, EntityStore, IGNORED_FILTER_COUNT_FIELDS, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, LegacyQuery, LegacyQueryCreator, MAX_UNUSED_ENTRIES, NumberArrayQueryField, ParseHttpErrorCodeToMessageDePipe, ParseHttpErrorCodeToMessageEnPipe, ParseHttpErrorCodeToTitleDePipe, ParseHttpErrorCodeToTitleEnPipe, QUERY_CLIENT_DEVTOOLS_TOKEN, QUERY_PERSISTENCE_STORE_VERSION, QUERY_SYNC_PROTOCOL_VERSION, QueryClientFeatureType, QueryDevtoolsComponent, QueryDirective, QueryError, QueryFeatureType, QueryField, QueryForm, QueryFormSignals, QueryRuntimeErrorCode, QueryShortNamePipe, QueryStore, SERVER_ERROR_KIND, SERVER_VIOLATION_ERROR_KIND, SPEED_BUFFER_TIME_IN_MS, SearchQueryField, SortQueryField, StringArrayQueryField, V2BearerAuthProvider, V2Query, V2QueryClient, V2QueryCreator, addQueryContainerHandling, applyQueryFeatures, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, booleanArrayQueryField, buildErrorMessage, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, consumeSuppressQueryStackDevtools, contentfulGqlLikePaginationAdapter, createBaseQuery, createBaseQueryCreator, createBearerAuthProvider, createDeleteQuery, createExecuteFn, createGetQuery, createGqlExecuteFn, createGqlMutationViaGet, createGqlMutationViaPost, createGqlQuery, createGqlQueryCreator, createGqlQueryViaGet, createGqlQueryViaPost, createHttpRequest, createIndexedDbQueryPersistenceAdapter, createInfinityQueryConfig, createLegacyQueryCreator, createNoopQueryPersistenceAdapter, createPagedQueryStack, createPatchQuery, createPersistentAuthFeature, createPostQuery, createPutQuery, createQuery, createQueryClient, createQueryCollection, createQueryCollectionSignal, createQueryCollectionSubject, createQueryContext, createQueryCreator, createQueryErrorResponse, createQueryFeature, createQueryForm, createQueryInvalidationFilter, createQueryKeyLockManager, createQueryObject, createQueryPersistenceEngine, createQueryRepository, createQuerySnapshotFn, createQueryStack, createQuerySyncEngine, createQuerySyncTransport, createSecureDeleteQuery, createSecureExecuteFactory, createSecureExecuteFn, createSecureGetQuery, createSecureGqlExecuteFn, createSecureGqlMutationViaGet, createSecureGqlMutationViaPost, createSecureGqlQuery, createSecureGqlQueryCreator, createSecureGqlQueryViaGet, createSecureGqlQueryViaPost, createSecurePatchQuery, createSecurePostQuery, createSecurePutQuery, createSecureQuery, createSecureQueryCreator, createTrackingFeature, createWebSocketClient, dateArrayQueryField, dateQueryField, decryptBearer, deepFreeze, def, detectContentTypeHeader, dynLikePaginationAdapter, effectComputed, emptyQueryArgs, ethletePaginationAdapter, executeUntilSettled, extractExpiresInSeconds, extractFormViolations, extractHtmlErrorMessage, extractQuery, fakePaginationAdapter, filterFailure, filterNull, filterQueryStates, filterSuccess, forEachHeader, getDefaultHeaders, getQueryClientName, getQueryFeatureUsage, getResponseUrl, ggLikePaginationAdapter, gql, gqlDataPropertyMissingInResponse, hasHeader, htmlErrorPayload, htmlQueryErrorParser, ignoreAutoRefresh, injectInfinityQueryResponseDelay, injectQueryContext, insertFrom, invalidBaseRouteError, invalidBodyError, invalidRouteError, invalidStateInsideSecureExecuteFactory, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isClassValidatorError, isCreateGqlQueryOptions, isCustomHeaderAuthProvider, isEmptyString, isGqlQueryConfig, isHtmlErrorPayload, isLegacyQuery, isNaN$1 as isNaN, isPageOutOfRangeError, isQuery, isQueryCollection, isQueryDevtoolsEnabled, isQueryErrorResponse, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyFormViolationListError, isSymfonyListError, isSymfonyPagerfantaOutOfRangeError, isUnderInvalidatedUrl, legacyPrepareWithoutInjectionContext, mapToPaginated, mapViolationsToFormErrors, maybeExecute, mergeHeaders, nestedEffect, numberArrayQueryField, pagedQueryStackNextPageCalledWithoutPreviousPage, pagedQueryStackPageBiggerThanTotalPages, pagedQueryStackPreviousPageCalledButAlreadyAtFirstPage, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, parseHttpErrorCodeToMessageDe, parseHttpErrorCodeToMessageEn, parseHttpErrorCodeToTitleDe, parseHttpErrorCodeToTitleEn, pathParamsMissingInRouteFunctionError, provideInfinityQueryResponseDelay, provideQueryClientForDevtools, provideQueryDevtools, queryArrayComputed, queryClientFeatureUsedMultipleTimes, queryComputed, queryComputedTillTruthy, queryDevtoolsEntries, queryErrorMessage, queryErrorMessages, queryExecute, queryFeatureUsedMultipleTimes, queryField, querySequence, querySequenceAlreadyRunning, queryStackTotalQueriesAndExpectedQueriesMismatch, queryStackWithArgsUsed, queryStackWithResponseUpdateUsed, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, queryStateErrorSignal, queryStateLoadingSignal, queryStateResponseSignal, queryStateSignal, registerQueryDevtoolsEntry, registerQueryErrorParser, removeFrom, request, resetExecuteState, resetPageOnError, resolveInvalidationUrl, runDefaultQueryRetry, runQueryErrorParsers, searchQueryField, serializeBody, setDefaultQueryRetryFn, setQueryDevtoolsRegistrar, setupQueryDependencies, setupQueryExecuteState, setupQueryState, shouldAutoExecuteGqlQuery, shouldAutoExecuteQuery, shouldCacheQuery, shouldRetryRequest, silenceMissingWithArgsFeatureErrorUsedButWithArgsPresent, skipPaginationPageParamCalculator, sortQueryField, splitQueryConfig, stringArrayQueryField,
|
|
11310
|
+
export { BasicAuthProvider, BearerAuthFeatureType, BooleanArrayQueryField, CLEAR_QUERY_ARGS, 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_UNUSED_ENTRIES, NumberArrayQueryField, ParseHttpErrorCodeToMessageDePipe, ParseHttpErrorCodeToMessageEnPipe, ParseHttpErrorCodeToTitleDePipe, ParseHttpErrorCodeToTitleEnPipe, QUERY_CLIENT_DEVTOOLS_TOKEN, QUERY_DEVTOOLS_FAULT_STATUSES, QUERY_PERSISTENCE_STORE_VERSION, QUERY_SYNC_PROTOCOL_VERSION, QueryClientFeatureType, QueryDevtoolsComponent, QueryDirective, QueryError, QueryFeatureType, QueryField, QueryForm, QueryFormSignals, QueryRuntimeErrorCode, QueryShortNamePipe, QueryStore, SERVER_ERROR_KIND, SERVER_VIOLATION_ERROR_KIND, SPEED_BUFFER_TIME_IN_MS, SearchQueryField, SortQueryField, StringArrayQueryField, V2BearerAuthProvider, V2Query, V2QueryClient, V2QueryCreator, addQueryContainerHandling, applyQueryFeatures, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, booleanArrayQueryField, buildErrorMessage, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, clearQueryDevtoolsFaults, collectQueryFormLinks, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, consumeSuppressQueryStackDevtools, contentfulGqlLikePaginationAdapter, createBaseQuery, createBaseQueryCreator, createBearerAuthProvider, createDeleteQuery, createExecuteFn, createGetQuery, createGqlExecuteFn, createGqlMutationViaGet, createGqlMutationViaPost, createGqlQuery, createGqlQueryCreator, createGqlQueryViaGet, createGqlQueryViaPost, createHttpRequest, createIndexedDbQueryPersistenceAdapter, createInfinityQueryConfig, createLegacyQueryCreator, createNoopQueryPersistenceAdapter, createPagedQueryStack, createPatchQuery, createPersistentAuthFeature, createPostQuery, createPutQuery, createQuery, createQueryClient, createQueryCollection, createQueryCollectionSignal, createQueryCollectionSubject, createQueryContext, createQueryCreator, createQueryDevtoolsFormLinks, createQueryDevtoolsFormLinksRecorder, createQueryDevtoolsStats, createQueryDevtoolsStatsRecorder, createQueryErrorResponse, createQueryFeature, createQueryForm, createQueryInvalidationFilter, createQueryKeyLockManager, createQueryObject, createQueryPersistenceEngine, createQueryRepository, createQuerySnapshotFn, createQueryStack, createQuerySyncEngine, createQuerySyncTransport, createSecureDeleteQuery, createSecureExecuteFactory, createSecureExecuteFn, createSecureGetQuery, createSecureGqlExecuteFn, createSecureGqlMutationViaGet, createSecureGqlMutationViaPost, createSecureGqlQuery, createSecureGqlQueryCreator, createSecureGqlQueryViaGet, createSecureGqlQueryViaPost, createSecurePatchQuery, createSecurePostQuery, createSecurePutQuery, createSecureQuery, createSecureQueryCreator, createTrackingFeature, createWebSocketClient, dateArrayQueryField, dateQueryField, decryptBearer, deepFreeze, def, describeQueryDevtoolsFeatures, detectContentTypeHeader, dynLikePaginationAdapter, effectComputed, emptyQueryArgs, ethletePaginationAdapter, executeUntilSettled, extractExpiresInSeconds, extractFormViolations, extractHtmlErrorMessage, extractQuery, fakePaginationAdapter, filterFailure, filterNull, filterQueryStates, filterSuccess, forEachHeader, formatQueryDevtoolsDuration, getBearerAuthProviderName, getDefaultHeaders, getQueryClientName, getQueryFeatureUsage, getResponseUrl, ggLikePaginationAdapter, gql, gqlDataPropertyMissingInResponse, hasHeader, htmlErrorPayload, htmlQueryErrorParser, ignoreAutoRefresh, injectInfinityQueryResponseDelay, injectQueryContext, insertFrom, invalidBaseRouteError, invalidBodyError, invalidRouteError, invalidStateInsideSecureExecuteFactory, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isClassValidatorError, isCreateGqlQueryOptions, isCustomHeaderAuthProvider, isEmptyString, isGqlQueryConfig, isHtmlErrorPayload, isLegacyQuery, isNaN$1 as isNaN, isPageOutOfRangeError, isQuery, isQueryCollection, isQueryDevtoolsEnabled, isQueryDevtoolsFaultArmed, isQueryDevtoolsFaultInjectionEnabled, isQueryErrorResponse, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyFormViolationListError, isSymfonyListError, isSymfonyPagerfantaOutOfRangeError, isUnderInvalidatedUrl, legacyPrepareFallbackInjector, legacyPrepareWithoutInjectionContext, mapToPaginated, mapViolationsToFormErrors, maybeExecute, measureQueryDevtoolsPayload, mergeHeaders, nestedEffect, noteQueryFormRead, numberArrayQueryField, pagedQueryStackNextPageCalledWithoutPreviousPage, pagedQueryStackPageBiggerThanTotalPages, pagedQueryStackPreviousPageCalledButAlreadyAtFirstPage, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, parseHttpErrorCodeToMessageDe, parseHttpErrorCodeToMessageEn, parseHttpErrorCodeToTitleDe, parseHttpErrorCodeToTitleEn, parseQueryRoute, pathParamsMissingInRouteFunctionError, provideInfinityQueryResponseDelay, provideLegacyPrepareFallback, provideQueryClientForDevtools, provideQueryDevtools, queryArrayComputed, queryClientFeatureUsedMultipleTimes, queryComputed, queryComputedTillTruthy, queryDevtoolsEntries, queryDevtoolsFaults, queryDevtoolsFnDetail, queryErrorMessage, queryErrorMessages, queryExecute, queryFeatureUsedMultipleTimes, queryField, querySequence, querySequenceAlreadyRunning, queryStackTotalQueriesAndExpectedQueriesMismatch, queryStackWithArgsUsed, queryStackWithResponseUpdateUsed, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, queryStateErrorSignal, queryStateLoadingSignal, queryStateResponseSignal, queryStateSignal, registerQueryDevtoolsEntry, registerQueryErrorParser, removeFrom, request, resetExecuteState, resetPageOnError, resolveInvalidationUrl, resolveQueryDevtoolsFault, resolveQueryDevtoolsFaultForAttempt, runDefaultQueryRetry, runQueryErrorParsers, searchQueryField, serializeBody, setDefaultQueryRetryFn, setQueryDevtoolsFault, setQueryDevtoolsFaultResolver, setQueryDevtoolsFormLinksFactory, setQueryDevtoolsRegistrar, setQueryDevtoolsStatsFactory, setupQueryDependencies, setupQueryExecuteState, setupQueryState, shouldAutoExecuteGqlQuery, shouldAutoExecuteQuery, shouldCacheQuery, shouldRetryRequest, silenceMissingWithArgsFeatureErrorUsedButWithArgsPresent, skipPaginationPageParamCalculator, sortQueryField, splitQueryConfig, stringArrayQueryField, stringifyQueryRouteParts, sumQueryDevtoolsStats, suppressNextQueryStackDevtools, switchQueryCollectionState, switchQueryState, symfonyQueryErrorParser, takeUntilResponse, toQuerySignal, toQuerySubject, tokensNotAvailableInsideAuthAndExec, 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, withMultiTabSync, withPageResetOnError, withPersistentAuth, withPolling, withPollingUsedOnUnsupportedHttpMethod, withQueryPersistence, withRefreshQuery, withResponseUpdate, withSuccessHandling, withSymfonyErrors, withTokenExpirationWarning, withTokenRevocation, withTracking, wrapAsObservableSignal, wrapQuerySyncMessage };
|
|
10075
11311
|
//# sourceMappingURL=ethlete-query.mjs.map
|