@ethlete/query 6.0.0-next.26 → 6.0.0-next.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
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, 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';
4
+ import { filter, Subject, Subscription, defer, throwError, timer, switchMap, tap, retry, catchError, take, of, merge, firstValueFrom, fromEvent, throttleTime, interval, combineLatest, map, Observable, takeUntil, startWith, pairwise, BehaviorSubject, ReplaySubject, shareReplay, skip, takeWhile, EMPTY, withLatestFrom, debounceTime } from 'rxjs';
5
5
  import { HttpClient, HttpEventType, HttpErrorResponse, HttpHeaders, HttpStatusCode } from '@angular/common/http';
6
6
  import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
7
7
  import { getActiveConsumer, setActiveConsumer } from '@angular/core/primitives/signals';
@@ -3690,6 +3690,9 @@ const createSecureExecuteFactory = (options) => {
3690
3690
  let authQuerySubscription = Subscription.EMPTY;
3691
3691
  let tokenRefreshSubscription = Subscription.EMPTY;
3692
3692
  let tokenWaitSubscription = Subscription.EMPTY;
3693
+ let sessionRestartSubscription = Subscription.EMPTY;
3694
+ let hasExecuted = false;
3695
+ let lastExecuteArgs;
3693
3696
  const reset = () => {
3694
3697
  authQuerySubscription.unsubscribe();
3695
3698
  authQuerySubscription = Subscription.EMPTY;
@@ -3697,6 +3700,8 @@ const createSecureExecuteFactory = (options) => {
3697
3700
  tokenRefreshSubscription = Subscription.EMPTY;
3698
3701
  tokenWaitSubscription.unsubscribe();
3699
3702
  tokenWaitSubscription = Subscription.EMPTY;
3703
+ sessionRestartSubscription.unsubscribe();
3704
+ sessionRestartSubscription = Subscription.EMPTY;
3700
3705
  resetExecuteState({
3701
3706
  executeState,
3702
3707
  executeOptions: { deps: options.deps, state: options.state },
@@ -3705,9 +3710,26 @@ const createSecureExecuteFactory = (options) => {
3705
3710
  // A logout tears down the secure entries in the repository, but the query object holding one keeps
3706
3711
  // its own `response`/`error` signals - so without this a component still mounted after logout goes
3707
3712
  // on rendering the previous user's data until something calls `reset()` by hand.
3713
+ //
3714
+ // Resetting alone leaves it idle for good though: a self-executing query runs once, at creation,
3715
+ // and nothing runs it again - so anything still mounted across a logout has to be re-armed for
3716
+ // the next session. That re-arm waits on the token instead of re-running here: `logout()` clears
3717
+ // `latestExecutedQuery` and `executionState` only *after* emitting this event, so everything read
3718
+ // synchronously still describes the session that just ended.
3708
3719
  options.deps.client.repository.events$
3709
3720
  .pipe(filter((event) => event.type === 'unbind-all-secure'), takeUntilDestroyed(options.deps.destroyRef))
3710
- .subscribe(() => reset());
3721
+ .subscribe(() => {
3722
+ const shouldRestart = hasExecuted && options.autoExecutes;
3723
+ const restartArgs = lastExecuteArgs;
3724
+ reset();
3725
+ if (!shouldRestart)
3726
+ return;
3727
+ sessionRestartSubscription = toObservable(options.authProvider.accessToken, {
3728
+ injector: options.deps.injector,
3729
+ })
3730
+ .pipe(filter(Boolean), take(1), tap(() => exec(restartArgs)))
3731
+ .subscribe();
3732
+ });
3711
3733
  const error = (query) => {
3712
3734
  const state = options.state;
3713
3735
  state.error.set(query.error());
@@ -3768,18 +3790,29 @@ const createSecureExecuteFactory = (options) => {
3768
3790
  args: executeArgs?.args ?? options.state.args(),
3769
3791
  options: executeArgs?.options,
3770
3792
  };
3793
+ hasExecuted = true;
3794
+ lastExecuteArgs = execArgsWithDefaults;
3771
3795
  authQuerySubscription.unsubscribe();
3772
3796
  authQuerySubscription = Subscription.EMPTY;
3773
3797
  tokenRefreshSubscription.unsubscribe();
3774
3798
  tokenRefreshSubscription = Subscription.EMPTY;
3775
3799
  tokenWaitSubscription.unsubscribe();
3776
3800
  tokenWaitSubscription = Subscription.EMPTY;
3801
+ sessionRestartSubscription.unsubscribe();
3802
+ sessionRestartSubscription = Subscription.EMPTY;
3777
3803
  tokenRefreshSubscription = options.authProvider.afterTokenRefresh$
3778
3804
  .pipe(filter(() => {
3779
3805
  const currentError = options.state.error();
3780
3806
  return currentError?.code === 401;
3781
3807
  }), take(1), tap(() => exec(execArgsWithDefaults)))
3782
3808
  .subscribe();
3809
+ // `setTokens()` seeds an auth session from outside the query registry (an SSO/OIDC callback, a
3810
+ // native shell) - no query ever runs for `latestExecutedQuery` to report, so a successful token
3811
+ // seed is treated as an auth query that already resolved.
3812
+ if (options.authProvider.executionState()?.type === 'tokenSeed') {
3813
+ authAndExecWhenTokenReady(execArgsWithDefaults);
3814
+ return;
3815
+ }
3783
3816
  const latestQuery = options.authProvider.latestExecutedQuery();
3784
3817
  const authQuery = latestQuery?.snapshot;
3785
3818
  // This might happen if a secure query gets executed while the auth query has just been created.
@@ -3787,10 +3820,9 @@ const createSecureExecuteFactory = (options) => {
3787
3820
  const isAuthQueryFreshlyExecuted = authQuery?.lastTimeExecutedAt() === null;
3788
3821
  if (!authQuery || authQuery.loading() || isAuthQueryFreshlyExecuted) {
3789
3822
  options.state.loading.set({ executeTime: Date.now(), progress: null });
3790
- authQuerySubscription = toObservable(options.authProvider.latestExecutedQuery, {
3823
+ const latestExecutedQuery$ = toObservable(options.authProvider.latestExecutedQuery, {
3791
3824
  injector: options.deps.injector,
3792
- })
3793
- .pipe(switchMap((latestQuery) => {
3825
+ }).pipe(switchMap((latestQuery) => {
3794
3826
  if (!latestQuery)
3795
3827
  return of(null);
3796
3828
  const query = latestQuery.snapshot;
@@ -3804,8 +3836,14 @@ const createSecureExecuteFactory = (options) => {
3804
3836
  authAndExecWhenTokenReady(execArgsWithDefaults);
3805
3837
  }
3806
3838
  }));
3807
- }))
3808
- .subscribe();
3839
+ }));
3840
+ // A `setTokens()` call that lands while this is already waiting (e.g. the SSO redirect
3841
+ // resolves after this secure query mounted) never touches `latestExecutedQuery` either -
3842
+ // wake up on `executionState` becoming a token seed too.
3843
+ const tokenSeed$ = toObservable(options.authProvider.executionState, {
3844
+ injector: options.deps.injector,
3845
+ }).pipe(filter((state) => state?.type === 'tokenSeed'), take(1), tap(() => authAndExecWhenTokenReady(execArgsWithDefaults)));
3846
+ authQuerySubscription = merge(latestExecutedQuery$, tokenSeed$).subscribe();
3809
3847
  }
3810
3848
  else if (authQuery.response()) {
3811
3849
  authAndExecWhenTokenReady(execArgsWithDefaults);
@@ -3828,6 +3866,7 @@ const createSecureExecuteFn = (executeOptions) => {
3828
3866
  authProvider,
3829
3867
  deps: executeOptions.deps,
3830
3868
  state: executeOptions.state,
3869
+ autoExecutes: shouldAutoExecuteQuery(executeOptions.creatorInternals.method) && !executeOptions.queryConfig.onlyManualExecution,
3831
3870
  transformAuthAndExec: (executeArgs, _tokens, headers, executeState) => {
3832
3871
  const { options: runOptions } = executeArgs ?? {};
3833
3872
  const updatedArgs = { ...(executeArgs?.args ?? {}), headers };
@@ -6260,6 +6299,8 @@ const createSecureGqlExecuteFn = (executeOptions) => {
6260
6299
  authProvider,
6261
6300
  deps: executeOptions.deps,
6262
6301
  state: executeOptions.state,
6302
+ autoExecutes: shouldAutoExecuteGqlQuery(executeOptions.creatorInternals.method) &&
6303
+ !executeOptions.queryConfig.onlyManualExecution,
6263
6304
  transformAuthAndExec: (executeArgs, _tokens, headers, executeState) => {
6264
6305
  const { args, options: runOptions } = executeArgs ?? {};
6265
6306
  const query = transformGql(executeOptions.creatorInternals.query);
@@ -11086,12 +11127,11 @@ const nextQueryFormDevtoolsId = (name) => {
11086
11127
  return `query-form|${name}#${seq}`;
11087
11128
  };
11088
11129
  /**
11089
- * A signals-first query form: binds on-screen controls to typed fields, keeps a
11090
- * debounced committed value, syncs to the URL query params, and resets dependent
11091
- * fields via the `isResetBy` graph - all as signals.
11130
+ * Define a {@link QueryFormSignals}. Call `.observe()` to start syncing with the
11131
+ * URL. Must be called in an injection context.
11092
11132
  *
11093
11133
  * @example
11094
- * const qf = createQueryForm({
11134
+ * const qf = defineQueryForm({
11095
11135
  * fields: {
11096
11136
  * search: searchQueryField(),
11097
11137
  * sort: sortQueryField(),
@@ -11100,191 +11140,131 @@ const nextQueryFormDevtoolsId = (name) => {
11100
11140
  * }).observe();
11101
11141
  * // template: <input etInput [formField]="qf.fields.search" />
11102
11142
  */
11103
- class QueryFormSignals {
11104
- constructor(config) {
11105
- this.router = inject(Router);
11106
- this.route = inject(ActivatedRoute);
11107
- this.injector = inject(Injector);
11108
- this.queryParamChanges = injectQueryParamChanges();
11109
- this.previous = signal(null, /* @ts-ignore */
11110
- ...(ngDevMode ? [{ debugName: "previous" }] : /* istanbul ignore next */ []));
11111
- this.observing = signal(false, /* @ts-ignore */
11112
- ...(ngDevMode ? [{ debugName: "observing" }] : /* istanbul ignore next */ []));
11113
- this.pendingTimer = null;
11114
- this.commitPending = signal(false, /* @ts-ignore */
11115
- ...(ngDevMode ? [{ debugName: "commitPending" }] : /* istanbul ignore next */ []));
11116
- this.skipNextResets = false;
11117
- assertInInjectionContext(QueryFormSignals);
11118
- this._fields = config.fields;
11119
- this.prefix = config.queryParamPrefix;
11120
- this.defaults = buildDefaults(config.fields);
11121
- this.defaultValue = clone(this.defaults);
11122
- const initial = clone(this.defaults);
11123
- this.model = signal(initial, /* @ts-ignore */
11124
- ...(ngDevMode ? [{ debugName: "model" }] : /* istanbul ignore next */ []));
11125
- this.committed = signal(clone(initial), /* @ts-ignore */
11126
- ...(ngDevMode ? [{ debugName: "committed" }] : /* istanbul ignore next */ []));
11127
- this.fields = form(this.model);
11128
- const devtoolsName = config.name ?? (typeof this.prefix === 'string' ? this.prefix : 'form');
11129
- const devtoolsId = isQueryDevtoolsEnabled() ? nextQueryFormDevtoolsId(devtoolsName) : null;
11130
- // Reading `value` is how a query's args pick the form up, so the devtools learn which query a form
11131
- // drives by noting the read - see `QueryDevtoolsFormLinksHandle`.
11132
- this.value = devtoolsId
11133
- ? computed(() => {
11134
- noteQueryFormRead(devtoolsId);
11135
- return this.committed();
11136
- })
11137
- : this.committed.asReadonly();
11138
- this.previousValue = this.previous.asReadonly();
11139
- this.changes = computed(() => ({ previousValue: this.previous(), currentValue: this.committed() }), /* @ts-ignore */
11140
- ...(ngDevMode ? [{ debugName: "changes" }] : /* istanbul ignore next */ []));
11141
- this.activeFilterCount = computed(() => computeFilterCount(this._fields, this.committed(), this.defaults), /* @ts-ignore */
11142
- ...(ngDevMode ? [{ debugName: "activeFilterCount" }] : /* istanbul ignore next */ []));
11143
- // React to live control edits: schedule a debounced commit.
11144
- effect(() => {
11145
- const live = this.model();
11146
- untracked(() => this.onLiveChange(live));
11147
- });
11148
- // React to navigation (back/forward, external links): apply URL → form immediately.
11149
- effect(() => {
11150
- const changes = this.queryParamChanges();
11151
- untracked(() => {
11152
- if (!this.observing() || this.observeOptions?.syncOnNavigation === false)
11153
- return;
11154
- this.applyFromUrl(changes);
11155
- });
11156
- });
11157
- const destroyRef = inject(DestroyRef);
11158
- destroyRef.onDestroy(() => this.cleanup());
11159
- if (devtoolsId) {
11160
- destroyRef.onDestroy(registerQueryDevtoolsEntry({
11161
- id: devtoolsId,
11162
- kind: 'query-form',
11163
- handle: this.devtoolsHandle(),
11164
- meta: { name: devtoolsName },
11165
- }));
11166
- }
11167
- }
11168
- observe(options) {
11169
- if (this.observing()) {
11170
- if (isDevMode()) {
11171
- console.warn('QueryFormSignals.observe() was called more than once. Ignoring the extra call.');
11172
- }
11173
- return this;
11143
+ const defineQueryForm = (config) => {
11144
+ assertInInjectionContext(defineQueryForm);
11145
+ const router = inject(Router);
11146
+ const route = inject(ActivatedRoute);
11147
+ const injector = inject(Injector);
11148
+ const destroyRef = inject(DestroyRef);
11149
+ const queryParamChanges = injectQueryParamChanges();
11150
+ const fieldDefs = config.fields;
11151
+ const prefix = config.queryParamPrefix;
11152
+ const defaults = buildDefaults(fieldDefs);
11153
+ const defaultValue = clone(defaults);
11154
+ /** Live field values (updated immediately by bound controls). */
11155
+ const model = signal(clone(defaults), /* @ts-ignore */
11156
+ ...(ngDevMode ? [{ debugName: "model" }] : /* istanbul ignore next */ []));
11157
+ /** The committed (debounced) value that drives `value`, the URL and the filter count. */
11158
+ const committed = signal(clone(defaults), /* @ts-ignore */
11159
+ ...(ngDevMode ? [{ debugName: "committed" }] : /* istanbul ignore next */ []));
11160
+ const previous = signal(null, /* @ts-ignore */
11161
+ ...(ngDevMode ? [{ debugName: "previous" }] : /* istanbul ignore next */ []));
11162
+ const observing = signal(false, /* @ts-ignore */
11163
+ ...(ngDevMode ? [{ debugName: "observing" }] : /* istanbul ignore next */ []));
11164
+ const commitPending = signal(false, /* @ts-ignore */
11165
+ ...(ngDevMode ? [{ debugName: "commitPending" }] : /* istanbul ignore next */ []));
11166
+ let observeOptions;
11167
+ let pendingTimer = null;
11168
+ let skipNextResets = false;
11169
+ const fields = form(model);
11170
+ const activeFilterCount = computed(() => computeFilterCount(fieldDefs, committed(), defaults), /* @ts-ignore */
11171
+ ...(ngDevMode ? [{ debugName: "activeFilterCount" }] : /* istanbul ignore next */ []));
11172
+ const paramKey = (key) => {
11173
+ if (!prefix)
11174
+ return key;
11175
+ return `${typeof prefix === 'string' ? prefix : prefix()}-${key}`;
11176
+ };
11177
+ /** What a field puts in the URL for a given value, or `undefined` when it writes nothing. */
11178
+ const queryParamFor = (key, def, value) => {
11179
+ const isDefault = equal(value, defaults[key]);
11180
+ const writeToUrl = def.appendToUrl !== false;
11181
+ const writeDefault = def.appendDefaultValueToUrl === true;
11182
+ if (!writeToUrl || (isDefault && !writeDefault))
11183
+ return undefined;
11184
+ if (def.valueToQueryParam)
11185
+ return def.valueToQueryParam(value);
11186
+ return value === null ? ET_NULL_VALUE : value;
11187
+ };
11188
+ const deserialize = (def, raw) => {
11189
+ if (def.queryParamToValue)
11190
+ return def.queryParamToValue(raw);
11191
+ if (def.skipAutoTransform)
11192
+ return raw;
11193
+ return autoCoerce(raw, resolveDefault(def));
11194
+ };
11195
+ const clearTimer = () => {
11196
+ if (pendingTimer !== null) {
11197
+ clearTimeout(pendingTimer);
11198
+ pendingTimer = null;
11174
11199
  }
11175
- this.observeOptions = options;
11176
- this.observing.set(true);
11177
- if (options?.syncOnNavigation !== false) {
11178
- this.applyFromUrl(this.route.snapshot.queryParams);
11200
+ commitPending.set(false);
11201
+ };
11202
+ const writeToUrl = (value) => {
11203
+ const queryParams = {};
11204
+ for (const [key, def] of Object.entries(fieldDefs)) {
11205
+ queryParams[paramKey(key)] = queryParamFor(key, def, value[key]);
11179
11206
  }
11180
- // Commit whatever the model holds now (URL-restored or programmatic defaults).
11181
- this.flush();
11182
- return this;
11183
- }
11184
- unobserve() {
11185
- this.cleanup();
11186
- }
11187
- setValue(value, options) {
11188
- if (options?.skipResets)
11189
- this.skipNextResets = true;
11190
- this.model.set(clone(value));
11191
- }
11192
- patchValue(value, options) {
11193
- if (options?.skipResets)
11194
- this.skipNextResets = true;
11195
- this.model.update((cur) => ({ ...cur, ...value }));
11196
- }
11197
- resetFieldToDefault(key, options) {
11198
- if (options?.skipResets)
11199
- this.skipNextResets = true;
11200
- this.model.update((cur) => ({ ...cur, [key]: this.defaults[key] }));
11201
- }
11202
- resetFieldsToDefault(keys, options) {
11203
- if (options?.skipResets)
11204
- this.skipNextResets = true;
11205
- this.model.update((cur) => {
11206
- const next = { ...cur };
11207
- for (const key of keys) {
11208
- next[key] = this.defaults[key];
11209
- }
11210
- return next;
11207
+ queueMicrotask(() => {
11208
+ router.navigate([], {
11209
+ queryParams,
11210
+ queryParamsHandling: 'merge',
11211
+ replaceUrl: observeOptions?.replaceUrl,
11212
+ });
11211
11213
  });
11212
- }
11213
- resetAllFieldsToDefault(options) {
11214
- const skip = new Set((options?.skipFields ?? []).map((key) => key));
11215
- const keys = Object.keys(this._fields).filter((key) => !skip.has(key));
11216
- this.resetFieldsToDefault(keys, options);
11217
- }
11218
- /** Create a detached editor over the same fields, seeded from the current committed value. */
11219
- branch() {
11220
- return createBranch(this._fields, clone(this.committed()), this.injector);
11221
- }
11222
- /**
11223
- * The live view `<et-query-devtools>` renders. Only built while the devtools are installed - it walks
11224
- * every field on every change, which an app without them should not pay for.
11225
- */
11226
- devtoolsHandle() {
11227
- const fields = computed(() => {
11228
- const committed = this.committed();
11229
- const live = this.model();
11230
- return Object.entries(this._fields).map(([key, def]) => {
11231
- const value = committed[key];
11232
- return {
11233
- key,
11234
- paramKey: this.paramKey(key),
11235
- value,
11236
- liveValue: live[key],
11237
- defaultValue: this.defaults[key],
11238
- isDefault: equal(value, this.defaults[key]),
11239
- queryParam: this.queryParamFor(key, def, value),
11240
- debounceMs: def.debounce ?? null,
11241
- isResetBy: def.isResetBy ?? [],
11242
- countsAsFilter: !IGNORED_FILTER_COUNT_FIELDS.includes(key) && !def.skipInFilterCount,
11243
- };
11214
+ };
11215
+ const applyResets = (live, changedKeys) => {
11216
+ const next = { ...live };
11217
+ for (const [key, def] of Object.entries(fieldDefs)) {
11218
+ const resets = def.isResetBy;
11219
+ if (!resets?.length)
11220
+ continue;
11221
+ const triggered = resets.some((resetKey) => {
11222
+ if (!(resetKey in fieldDefs)) {
11223
+ if (isDevMode()) {
11224
+ console.warn(`defineQueryForm: isResetBy references unknown field "${resetKey}". Is it a typo?`);
11225
+ }
11226
+ return false;
11227
+ }
11228
+ return changedKeys.includes(resetKey);
11244
11229
  });
11245
- }, /* @ts-ignore */
11246
- ...(ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []));
11247
- return {
11248
- fields,
11249
- // Not `this.value` - reading that from the panel would link the form to whichever query happens
11250
- // to be building its args at the time.
11251
- value: computed(() => this.committed()),
11252
- previousValue: computed(() => this.previous() ?? null),
11253
- defaultValue: this.defaults,
11254
- activeFilterCount: this.activeFilterCount,
11255
- isAtDefaults: computed(() => equal(this.committed(), this.defaults)),
11256
- isCommitPending: this.commitPending.asReadonly(),
11257
- isObserving: this.observing.asReadonly(),
11258
- resetField: (key) => this.resetFieldToDefault(key),
11259
- resetAll: () => this.resetAllFieldsToDefault(),
11260
- };
11261
- }
11262
- onLiveChange(live) {
11263
- if (!this.observing())
11264
- return;
11265
- if (equal(live, this.committed()))
11230
+ if (!triggered)
11231
+ continue;
11232
+ const fieldDefault = defaults[key];
11233
+ if (!equal(next[key], fieldDefault)) {
11234
+ next[key] = fieldDefault;
11235
+ }
11236
+ }
11237
+ return next;
11238
+ };
11239
+ const flush = () => {
11240
+ clearTimer();
11241
+ const live = model();
11242
+ const prev = committed();
11243
+ if (equal(live, prev)) {
11244
+ skipNextResets = false;
11266
11245
  return;
11267
- const changedKeys = changedKeysBetween(this.committed(), live);
11268
- const debounceMs = this.resolveDebounce(changedKeys, live);
11269
- this.clearTimer();
11270
- if (debounceMs === null) {
11271
- this.flush();
11272
11246
  }
11273
- else {
11274
- this.commitPending.set(true);
11275
- this.pendingTimer = setTimeout(() => {
11276
- this.pendingTimer = null;
11277
- this.flush();
11278
- }, debounceMs);
11247
+ const changedKeys = changedKeysBetween(prev, live);
11248
+ const next = skipNextResets ? { ...live } : applyResets(live, changedKeys);
11249
+ skipNextResets = false;
11250
+ previous.set(clone(prev));
11251
+ committed.set(clone(next));
11252
+ // Reflect any reset overrides back into the bound controls. The effect re-runs
11253
+ // but no-ops because the model now equals the committed value.
11254
+ if (!equal(next, live)) {
11255
+ model.set(clone(next));
11279
11256
  }
11280
- }
11257
+ if (observing() && observeOptions?.writeToQueryParams !== false) {
11258
+ writeToUrl(next);
11259
+ }
11260
+ };
11281
11261
  /** Shortest-debounce-wins; `null` means commit immediately. */
11282
- resolveDebounce(changedKeys, live) {
11262
+ const resolveDebounce = (changedKeys, live) => {
11283
11263
  if (!changedKeys.length)
11284
11264
  return null;
11285
11265
  const times = [];
11286
11266
  for (const key of changedKeys) {
11287
- const def = this._fields[key];
11267
+ const def = fieldDefs[key];
11288
11268
  if (!def)
11289
11269
  return null;
11290
11270
  if (def.disableDebounceIfFalsy && !live[key])
@@ -11294,61 +11274,41 @@ class QueryFormSignals {
11294
11274
  times.push(def.debounce);
11295
11275
  }
11296
11276
  return Math.min(...times);
11297
- }
11298
- flush() {
11299
- this.clearTimer();
11300
- const live = this.model();
11301
- const previous = this.committed();
11302
- if (equal(live, previous)) {
11303
- this.skipNextResets = false;
11277
+ };
11278
+ const onLiveChange = (live) => {
11279
+ if (!observing())
11304
11280
  return;
11281
+ if (equal(live, committed()))
11282
+ return;
11283
+ const changedKeys = changedKeysBetween(committed(), live);
11284
+ const debounceMs = resolveDebounce(changedKeys, live);
11285
+ clearTimer();
11286
+ if (debounceMs === null) {
11287
+ flush();
11305
11288
  }
11306
- const changedKeys = changedKeysBetween(previous, live);
11307
- const next = this.skipNextResets ? { ...live } : this.applyResets(live, changedKeys);
11308
- this.skipNextResets = false;
11309
- this.previous.set(clone(previous));
11310
- this.committed.set(clone(next));
11311
- // Reflect any reset overrides back into the bound controls. The effect re-runs
11312
- // but no-ops because the model now equals the committed value.
11313
- if (!equal(next, live)) {
11314
- this.model.set(clone(next));
11315
- }
11316
- if (this.observing() && this.observeOptions?.writeToQueryParams !== false) {
11317
- this.writeToUrl(next);
11318
- }
11319
- }
11320
- applyResets(live, changedKeys) {
11321
- const next = { ...live };
11322
- for (const [key, def] of Object.entries(this._fields)) {
11323
- const resets = def.isResetBy;
11324
- if (!resets?.length)
11325
- continue;
11326
- const triggered = resets.some((resetKey) => {
11327
- if (!(resetKey in this._fields)) {
11328
- if (isDevMode()) {
11329
- console.warn(`QueryFormSignals: isResetBy references unknown field "${resetKey}". Is it a typo?`);
11330
- }
11331
- return false;
11332
- }
11333
- return changedKeys.includes(resetKey);
11334
- });
11335
- if (!triggered)
11336
- continue;
11337
- const defaultValue = this.defaults[key];
11338
- if (!equal(next[key], defaultValue)) {
11339
- next[key] = defaultValue;
11340
- }
11289
+ else {
11290
+ commitPending.set(true);
11291
+ pendingTimer = setTimeout(() => {
11292
+ pendingTimer = null;
11293
+ flush();
11294
+ }, debounceMs);
11341
11295
  }
11342
- return next;
11343
- }
11344
- applyFromUrl(params) {
11345
- const current = { ...this.committed() };
11296
+ };
11297
+ const commitFromUrl = (next) => {
11298
+ clearTimer();
11299
+ previous.set(clone(committed()));
11300
+ committed.set(clone(next));
11301
+ // Feed the URL value into the live model & bound controls; the effect no-ops (model === committed).
11302
+ model.set(clone(next));
11303
+ };
11304
+ const applyFromUrl = (params) => {
11305
+ const current = { ...committed() };
11346
11306
  let changed = false;
11347
- for (const [key, def] of Object.entries(this._fields)) {
11348
- const raw = params[this.paramKey(key)];
11307
+ for (const [key, def] of Object.entries(fieldDefs)) {
11308
+ const raw = params[paramKey(key)];
11349
11309
  if (raw === undefined)
11350
11310
  continue;
11351
- const value = raw === ET_PROPERTY_REMOVED ? this.defaults[key] : this.deserialize(def, raw);
11311
+ const value = raw === ET_PROPERTY_REMOVED ? defaults[key] : deserialize(def, raw);
11352
11312
  if (!equal(current[key], value)) {
11353
11313
  current[key] = value;
11354
11314
  changed = true;
@@ -11356,80 +11316,149 @@ class QueryFormSignals {
11356
11316
  }
11357
11317
  if (!changed)
11358
11318
  return;
11359
- this.commitFromUrl(current);
11360
- }
11361
- commitFromUrl(next) {
11362
- this.clearTimer();
11363
- this.previous.set(clone(this.committed()));
11364
- this.committed.set(clone(next));
11365
- // Feed the URL value into the live model & bound controls; the effect no-ops (model === committed).
11366
- this.model.set(clone(next));
11367
- }
11368
- deserialize(def, raw) {
11369
- if (def.queryParamToValue)
11370
- return def.queryParamToValue(raw);
11371
- if (def.skipAutoTransform)
11372
- return raw;
11373
- return autoCoerce(raw, resolveDefault(def));
11374
- }
11375
- /** What a field puts in the URL for a given value, or `undefined` when it writes nothing. */
11376
- queryParamFor(key, def, value) {
11377
- const isDefault = equal(value, this.defaults[key]);
11378
- const writeToUrl = def.appendToUrl !== false;
11379
- const writeDefault = def.appendDefaultValueToUrl === true;
11380
- if (!writeToUrl || (isDefault && !writeDefault))
11381
- return undefined;
11382
- if (def.valueToQueryParam)
11383
- return def.valueToQueryParam(value);
11384
- return value === null ? ET_NULL_VALUE : value;
11385
- }
11386
- writeToUrl(value) {
11387
- const queryParams = {};
11388
- for (const [key, def] of Object.entries(this._fields)) {
11389
- queryParams[this.paramKey(key)] = this.queryParamFor(key, def, value[key]);
11390
- }
11391
- queueMicrotask(() => {
11392
- this.router.navigate([], {
11393
- queryParams,
11394
- queryParamsHandling: 'merge',
11395
- replaceUrl: this.observeOptions?.replaceUrl,
11396
- });
11397
- });
11398
- }
11399
- paramKey(key) {
11400
- const prefix = this.prefix;
11401
- if (!prefix)
11402
- return key;
11403
- return `${typeof prefix === 'string' ? prefix : prefix()}-${key}`;
11404
- }
11405
- clearTimer() {
11406
- if (this.pendingTimer !== null) {
11407
- clearTimeout(this.pendingTimer);
11408
- this.pendingTimer = null;
11409
- }
11410
- this.commitPending.set(false);
11411
- }
11412
- cleanup() {
11413
- if (!this.observing())
11319
+ commitFromUrl(current);
11320
+ };
11321
+ const cleanup = () => {
11322
+ if (!observing())
11414
11323
  return;
11415
- this.observing.set(false);
11416
- this.clearTimer();
11417
- if (this.observeOptions?.writeToQueryParams === false)
11324
+ observing.set(false);
11325
+ clearTimer();
11326
+ if (observeOptions?.writeToQueryParams === false)
11418
11327
  return;
11419
11328
  const queryParams = {};
11420
- for (const key of Object.keys(this._fields)) {
11421
- queryParams[this.paramKey(key)] = undefined;
11329
+ for (const key of Object.keys(fieldDefs)) {
11330
+ queryParams[paramKey(key)] = undefined;
11422
11331
  }
11423
11332
  queueMicrotask(() => {
11424
- this.router.navigate([], { queryParams, queryParamsHandling: 'merge', replaceUrl: true });
11333
+ router.navigate([], { queryParams, queryParamsHandling: 'merge', replaceUrl: true });
11425
11334
  });
11335
+ };
11336
+ const setValue = (value, options) => {
11337
+ if (options?.skipResets)
11338
+ skipNextResets = true;
11339
+ model.set(clone(value));
11340
+ };
11341
+ const patchValue = (value, options) => {
11342
+ if (options?.skipResets)
11343
+ skipNextResets = true;
11344
+ model.update((cur) => ({ ...cur, ...value }));
11345
+ };
11346
+ const resetFieldsToDefault = (keys, options) => {
11347
+ if (options?.skipResets)
11348
+ skipNextResets = true;
11349
+ model.update((cur) => {
11350
+ const next = { ...cur };
11351
+ for (const key of keys) {
11352
+ next[key] = defaults[key];
11353
+ }
11354
+ return next;
11355
+ });
11356
+ };
11357
+ const devtoolsName = config.name ?? (typeof prefix === 'string' ? prefix : 'form');
11358
+ const devtoolsId = isQueryDevtoolsEnabled() ? nextQueryFormDevtoolsId(devtoolsName) : null;
11359
+ const queryForm = {
11360
+ fields,
11361
+ // Reading `value` is how a query's args pick the form up, so the devtools learn which query a form
11362
+ // drives by noting the read - see `QueryDevtoolsFormLinksHandle`.
11363
+ value: devtoolsId
11364
+ ? computed(() => {
11365
+ noteQueryFormRead(devtoolsId);
11366
+ return committed();
11367
+ })
11368
+ : committed.asReadonly(),
11369
+ previousValue: previous.asReadonly(),
11370
+ changes: computed(() => ({ previousValue: previous(), currentValue: committed() })),
11371
+ activeFilterCount,
11372
+ defaultValue,
11373
+ observe: (options) => {
11374
+ if (observing()) {
11375
+ if (isDevMode()) {
11376
+ console.warn('defineQueryForm: observe() was called more than once. Ignoring the extra call.');
11377
+ }
11378
+ return queryForm;
11379
+ }
11380
+ observeOptions = options;
11381
+ observing.set(true);
11382
+ if (options?.syncOnNavigation !== false) {
11383
+ applyFromUrl(route.snapshot.queryParams);
11384
+ }
11385
+ // Commit whatever the model holds now (URL-restored or programmatic defaults).
11386
+ flush();
11387
+ return queryForm;
11388
+ },
11389
+ unobserve: () => cleanup(),
11390
+ setValue,
11391
+ patchValue,
11392
+ resetFieldToDefault: (key, options) => resetFieldsToDefault([key], options),
11393
+ resetFieldsToDefault,
11394
+ resetAllFieldsToDefault: (options) => {
11395
+ const skip = new Set((options?.skipFields ?? []).map((key) => key));
11396
+ const keys = Object.keys(fieldDefs).filter((key) => !skip.has(key));
11397
+ resetFieldsToDefault(keys, options);
11398
+ },
11399
+ branch: () => createBranch(fieldDefs, clone(committed()), injector),
11400
+ };
11401
+ // React to live control edits: schedule a debounced commit.
11402
+ effect(() => {
11403
+ const live = model();
11404
+ untracked(() => onLiveChange(live));
11405
+ });
11406
+ // React to navigation (back/forward, external links): apply URL → form immediately.
11407
+ effect(() => {
11408
+ const changes = queryParamChanges();
11409
+ untracked(() => {
11410
+ if (!observing() || observeOptions?.syncOnNavigation === false)
11411
+ return;
11412
+ applyFromUrl(changes);
11413
+ });
11414
+ });
11415
+ destroyRef.onDestroy(() => cleanup());
11416
+ if (devtoolsId) {
11417
+ /**
11418
+ * The live view `<et-query-devtools>` renders. Only built while the devtools are installed - it walks
11419
+ * every field on every change, which an app without them should not pay for.
11420
+ */
11421
+ const handle = {
11422
+ fields: computed(() => {
11423
+ const committedValue = committed();
11424
+ const live = model();
11425
+ return Object.entries(fieldDefs).map(([key, def]) => {
11426
+ const value = committedValue[key];
11427
+ return {
11428
+ key,
11429
+ paramKey: paramKey(key),
11430
+ value,
11431
+ liveValue: live[key],
11432
+ defaultValue: defaults[key],
11433
+ isDefault: equal(value, defaults[key]),
11434
+ queryParam: queryParamFor(key, def, value),
11435
+ debounceMs: def.debounce ?? null,
11436
+ isResetBy: def.isResetBy ?? [],
11437
+ countsAsFilter: !IGNORED_FILTER_COUNT_FIELDS.includes(key) && !def.skipInFilterCount,
11438
+ };
11439
+ });
11440
+ }),
11441
+ // Not `queryForm.value` - reading that from the panel would link the form to whichever query happens
11442
+ // to be building its args at the time.
11443
+ value: computed(() => committed()),
11444
+ previousValue: computed(() => previous() ?? null),
11445
+ defaultValue: defaults,
11446
+ activeFilterCount,
11447
+ isAtDefaults: computed(() => equal(committed(), defaults)),
11448
+ isCommitPending: commitPending.asReadonly(),
11449
+ isObserving: observing.asReadonly(),
11450
+ resetField: (key) => queryForm.resetFieldToDefault(key),
11451
+ resetAll: () => queryForm.resetAllFieldsToDefault(),
11452
+ };
11453
+ destroyRef.onDestroy(registerQueryDevtoolsEntry({
11454
+ id: devtoolsId,
11455
+ kind: 'query-form',
11456
+ handle,
11457
+ meta: { name: devtoolsName },
11458
+ }));
11426
11459
  }
11427
- }
11428
- /**
11429
- * Create a {@link QueryFormSignals}. Call `.observe()` to start syncing with the
11430
- * URL. Must be called in an injection context.
11431
- */
11432
- const createQueryForm = (config) => new QueryFormSignals(config);
11460
+ return queryForm;
11461
+ };
11433
11462
 
11434
11463
  const normalizeConfig = (config) => {
11435
11464
  if (!config)
@@ -11667,5 +11696,5 @@ const createWebSocketClient = (options) => {
11667
11696
  * Generated bundle index. Do not edit.
11668
11697
  */
11669
11698
 
11670
- 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, 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, applyQueryDevtoolsOverrides, applyQueryFeatures, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, booleanArrayQueryField, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, clearQueryDevtoolsFaults, collectLeafPaths, 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, createQueryDevtoolsOverrides, createQueryDevtoolsOverridesRecorder, 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, detectPaginationShape, 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, isDateShapedLeaf, 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, setQueryDevtoolsOverridesFactory, setQueryDevtoolsRegistrar, setQueryDevtoolsStatsFactory, setupQueryDependencies, setupQueryExecuteState, setupQueryState, shouldAutoExecuteGqlQuery, shouldAutoExecuteQuery, shouldCacheQuery, shouldRetryRequest, silenceMissingWithArgsFeatureErrorUsedButWithArgsPresent, skipPaginationPageParamCalculator, smartDuplicateArrayItem, 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 };
11699
+ 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, QueryFeatureType, QueryField, QueryForm, QueryRuntimeErrorCode, QueryShortNamePipe, QueryStore, SERVER_ERROR_KIND, SERVER_VIOLATION_ERROR_KIND, SPEED_BUFFER_TIME_IN_MS, SearchQueryField, SortQueryField, StringArrayQueryField, V2BearerAuthProvider, V2Query, V2QueryClient, V2QueryCreator, addQueryContainerHandling, applyQueryDevtoolsOverrides, applyQueryFeatures, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, booleanArrayQueryField, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, clearQueryDevtoolsFaults, collectLeafPaths, 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, createQueryDevtoolsOverrides, createQueryDevtoolsOverridesRecorder, createQueryDevtoolsStats, createQueryDevtoolsStatsRecorder, createQueryErrorResponse, createQueryFeature, 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, defineQueryForm, describeQueryDevtoolsFeatures, detectContentTypeHeader, detectPaginationShape, 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, isDateShapedLeaf, 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, setQueryDevtoolsOverridesFactory, setQueryDevtoolsRegistrar, setQueryDevtoolsStatsFactory, setupQueryDependencies, setupQueryExecuteState, setupQueryState, shouldAutoExecuteGqlQuery, shouldAutoExecuteQuery, shouldCacheQuery, shouldRetryRequest, silenceMissingWithArgsFeatureErrorUsedButWithArgsPresent, skipPaginationPageParamCalculator, smartDuplicateArrayItem, 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 };
11671
11700
  //# sourceMappingURL=ethlete-query.mjs.map