@ethlete/query 6.0.0-next.36 → 6.0.0-next.38

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.
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { inject, computed, DestroyRef, InjectionToken, Injector, EnvironmentInjector, ElementRef, ErrorHandler, createEnvironmentInjector, effect, untracked, signal, linkedSignal, runInInjectionContext, isDevMode, PLATFORM_ID, resource, DOCUMENT, VERSION, makeEnvironmentProviders, assertInInjectionContext, provideEnvironmentInitializer, ChangeDetectorRef, ViewContainerRef, TemplateRef, Input, Directive, input, Pipe, ViewEncapsulation, Component, NgZone } from '@angular/core';
3
3
  import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
4
4
  import { UrlTree, Router, RedirectCommand, ActivatedRoute } from '@angular/router';
5
- import { filter, take, map, defer, from, Subject, Subscription, throwError, of, timer, switchMap, tap, retry, catchError, merge, EMPTY, takeWhile, firstValueFrom, concatMap, fromEvent, throttleTime, interval, combineLatest, Observable, takeUntil, startWith, pairwise, BehaviorSubject, ReplaySubject, shareReplay, skip, withLatestFrom, debounceTime } from 'rxjs';
5
+ import { filter, take, map, defer, from, Subject, Subscription, throwError, of, timer, switchMap, tap, retry, catchError, EMPTY, takeUntil, finalize, mergeMap, toArray, merge, takeWhile, firstValueFrom, concatMap, fromEvent, throttleTime, interval, combineLatest, Observable, startWith, pairwise, BehaviorSubject, ReplaySubject, shareReplay, skip, withLatestFrom, debounceTime } from 'rxjs';
6
6
  import { defineStaticProvider, RuntimeError, clamp, randomId, defineRootProvider, isObject, injectUnsavedChangesCoordinator, injectRoute, getCookie, getDomain, deleteCookie, setCookie, CORE_VERSION, createDestroy, computedTillTruthy, defineProvider, toProvideFn, toInjectFn, nextFrame, injectQueryParams, injectQueryParamChanges, clone, equal, ET_PROPERTY_REMOVED, previousSignalValue } from '@ethlete/core';
7
7
  import { HttpClient, HttpEventType, HttpErrorResponse, HttpResponse, HttpHeaders, HttpStatusCode } from '@angular/common/http';
8
8
  import { getActiveConsumer, setActiveConsumer } from '@angular/core/primitives/signals';
@@ -283,6 +283,26 @@ const setQueryDevtoolsTokenPayloadPatcher = (fn) => {
283
283
  * @internal
284
284
  */
285
285
  const patchQueryDevtoolsTokenPayload = (options) => (tokenPayloadPatcher ? tokenPayloadPatcher(options) : options.payload);
286
+ /** The batch item being created right now, or `null` outside one. */
287
+ let batchOwner = null;
288
+ /**
289
+ * Runs `create` with every query it creates attributed to `owner`'s batch and item. The attribution has
290
+ * to be ambient: a batch's item query is built by the query creator the caller handed it, which takes no
291
+ * devtools argument - so there is nothing to thread the owner through. Nested runs restore the outer one.
292
+ * @internal
293
+ */
294
+ const runInQueryDevtoolsBatch = (owner, create) => {
295
+ const outer = batchOwner;
296
+ batchOwner = owner;
297
+ try {
298
+ return create();
299
+ }
300
+ finally {
301
+ batchOwner = outer;
302
+ }
303
+ };
304
+ /** The batch item a query being created belongs to, or `null` for one created outside a batch. @internal */
305
+ const currentQueryDevtoolsBatch = () => batchOwner;
286
306
  let suppressStackRegistration = false;
287
307
  /**
288
308
  * Suppresses devtools registration for the next {@link createQueryStack} call. Used by
@@ -409,6 +429,9 @@ const QueryRuntimeErrorCode = {
409
429
  CIRCULAR_QUERY_DEPENDENCY: 800,
410
430
  // Query Sequence
411
431
  QUERY_SEQUENCE_ALREADY_RUNNING: 900,
432
+ // Query Batch
433
+ QUERY_BATCH_ALREADY_RUNNING: 910,
434
+ QUERY_BATCH_WITH_ARGS_USED: 911,
412
435
  // Legacy interop
413
436
  LEGACY_PREPARE_WITHOUT_INJECTION_CONTEXT: 950,
414
437
  LEGACY_QUERY_STATE_ALREADY_HAS_KEY: 951,
@@ -507,6 +530,12 @@ const legacyPrepareWithoutInjectionContext = (creatorName, method = 'prepare') =
507
530
  const querySequenceAlreadyRunning = () => {
508
531
  return new RuntimeError(QueryRuntimeErrorCode.QUERY_SEQUENCE_ALREADY_RUNNING, `run() was called on a query sequence that is already running. Wait for the current run to settle before starting another.`);
509
532
  };
533
+ const queryBatchAlreadyRunning = () => {
534
+ return new RuntimeError(QueryRuntimeErrorCode.QUERY_BATCH_ALREADY_RUNNING, `run() or retryFailed() was called on a query batch that is already running. Await the current run, or call cancel() first.`);
535
+ };
536
+ const queryBatchWithArgsUsed = () => {
537
+ return new RuntimeError(QueryRuntimeErrorCode.QUERY_BATCH_WITH_ARGS_USED, `The "withArgs()" feature cannot be used inside a query batch. Each item's args come from the batch's "args" option.`);
538
+ };
510
539
 
511
540
  const isClassValidatorError = (error) => {
512
541
  return typeof error === 'object' && error !== null && 'statusCode' in error && 'message' in error && 'error' in error;
@@ -1204,6 +1233,7 @@ const createBaseQuery = (options) => {
1204
1233
  queryConfig: options.queryConfig,
1205
1234
  });
1206
1235
  return runInInjectionContext(deps.injector, () => {
1236
+ const batchOwner = currentQueryDevtoolsBatch();
1207
1237
  const devtoolsStats = createQueryDevtoolsStatsRecorder();
1208
1238
  const devtoolsFormLinks = createQueryDevtoolsFormLinksRecorder();
1209
1239
  const devtoolsOverrides = createQueryDevtoolsOverridesRecorder();
@@ -1271,6 +1301,8 @@ const createBaseQuery = (options) => {
1271
1301
  client: deps.client,
1272
1302
  element: deps.hostElement,
1273
1303
  gqlQuery: options.creatorInternals.query,
1304
+ batch: batchOwner?.batch,
1305
+ batchItemIndex: batchOwner?.index,
1274
1306
  },
1275
1307
  });
1276
1308
  deps.destroyRef.onDestroy(unregister);
@@ -2924,6 +2956,259 @@ const createIndexedDbQueryPersistenceAdapter = (options) => {
2924
2956
  return { loadIndex, read, write, remove, clear, isSupported: true };
2925
2957
  };
2926
2958
 
2959
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2960
+ /**
2961
+ * Runs the same mutation over a list of items - the bulk edit / bulk delete shape - with a bounded
2962
+ * number of requests in flight and a per-item outcome.
2963
+ *
2964
+ * Where a query stack fans a reactive read out over many arg sets and keeps every query alive, a
2965
+ * batch is imperative and disposable: it is triggered by a button, it tolerates a partial failure,
2966
+ * and it destroys each query as soon as that item settles.
2967
+ *
2968
+ * Call it from an injection context; the host's destruction stops an in-flight run.
2969
+ *
2970
+ * @example
2971
+ * ```ts
2972
+ * protected archivePosts = createQueryBatch({
2973
+ * queryCreator: patchPost,
2974
+ * args: (post: Post) => ({ pathParams: { id: post.id }, body: { archived: true } }),
2975
+ * concurrency: 6,
2976
+ * });
2977
+ *
2978
+ * archiveSelected() {
2979
+ * this.archivePosts
2980
+ * .run(this.selection())
2981
+ * .pipe(tap((result) => result.ok || this.toast.error(`${result.failed.length} failed`)))
2982
+ * .subscribe();
2983
+ * }
2984
+ * ```
2985
+ *
2986
+ * ```html
2987
+ * <button et-button [loading]="archivePosts.running()" [progress]="archivePosts.progress()">Archive</button>
2988
+ * @if (archivePosts.failed()) {
2989
+ * <button (click)="retry()">Retry {{ archivePosts.failed() }} failed</button>
2990
+ * }
2991
+ * ```
2992
+ */
2993
+ const createQueryBatch = (options) => {
2994
+ const { queryCreator, args: mapArgs, stopOnError, allowCache, onItemSettled, features = [] } = options;
2995
+ const concurrency = Math.max(1, Math.floor(options.concurrency ?? 4));
2996
+ if (features.some((f) => f.type === QueryFeatureType.WITH_ARGS)) {
2997
+ throw queryBatchWithArgsUsed();
2998
+ }
2999
+ const injector = inject(Injector);
3000
+ const destroyRef = inject(DestroyRef);
3001
+ const devtoolsHandle = isQueryDevtoolsEnabled()
3002
+ ? { current: null }
3003
+ : undefined;
3004
+ const status = signal('idle', /* @ts-ignore */
3005
+ ...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
3006
+ const running = signal(false, /* @ts-ignore */
3007
+ ...(ngDevMode ? [{ debugName: "running" }] : /* istanbul ignore next */ []));
3008
+ const total = signal(0, /* @ts-ignore */
3009
+ ...(ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []));
3010
+ const inFlight = signal(0, /* @ts-ignore */
3011
+ ...(ngDevMode ? [{ debugName: "inFlight" }] : /* istanbul ignore next */ []));
3012
+ const results = signal([], /* @ts-ignore */
3013
+ ...(ngDevMode ? [{ debugName: "results" }] : /* istanbul ignore next */ []));
3014
+ const runStartedAt = signal(null, /* @ts-ignore */
3015
+ ...(ngDevMode ? [{ debugName: "runStartedAt" }] : /* istanbul ignore next */ []));
3016
+ const lastSettleAt = signal(null, /* @ts-ignore */
3017
+ ...(ngDevMode ? [{ debugName: "lastSettleAt" }] : /* istanbul ignore next */ []));
3018
+ const completedBeforeRun = signal(0, /* @ts-ignore */
3019
+ ...(ngDevMode ? [{ debugName: "completedBeforeRun" }] : /* istanbul ignore next */ []));
3020
+ let settled = [];
3021
+ let cancelRequested = false;
3022
+ let hostDestroyed = false;
3023
+ const hostDestroyed$ = new Subject();
3024
+ destroyRef.onDestroy(() => {
3025
+ hostDestroyed = true;
3026
+ cancelRequested = true;
3027
+ hostDestroyed$.next();
3028
+ hostDestroyed$.complete();
3029
+ });
3030
+ const publish = () => results.set(settled.filter((r) => !!r));
3031
+ const record = (result) => {
3032
+ settled[result.index] = result;
3033
+ lastSettleAt.set(Date.now());
3034
+ publish();
3035
+ onItemSettled?.(result);
3036
+ };
3037
+ const countOf = (of) => computed(() => results().filter((r) => r.status === of).length);
3038
+ const completed = computed(() => results().length, /* @ts-ignore */
3039
+ ...(ngDevMode ? [{ debugName: "completed" }] : /* istanbul ignore next */ []));
3040
+ const failedResults = computed(() => results().filter((r) => r.status === 'error'), /* @ts-ignore */
3041
+ ...(ngDevMode ? [{ debugName: "failedResults" }] : /* istanbul ignore next */ []));
3042
+ // Measured from the run's start rather than between the last two settles: items land in waves of
3043
+ // `concurrency`, so an instantaneous rate swings between zero and a burst.
3044
+ const itemsPerSecond = computed(() => {
3045
+ const startedAt = runStartedAt();
3046
+ const measuredAt = lastSettleAt();
3047
+ if (startedAt === null || measuredAt === null)
3048
+ return null;
3049
+ const elapsedMs = measuredAt - startedAt;
3050
+ const settledInRun = completed() - completedBeforeRun();
3051
+ // One settled item says nothing about a run of `concurrency` parallel ones, and a run shorter
3052
+ // than the buffer extrapolates a whole batch out of its own warm-up.
3053
+ if (elapsedMs < SPEED_BUFFER_TIME_IN_MS || settledInRun < Math.min(concurrency, total()))
3054
+ return null;
3055
+ return (settledInRun / elapsedMs) * 1000;
3056
+ }, /* @ts-ignore */
3057
+ ...(ngDevMode ? [{ debugName: "itemsPerSecond" }] : /* istanbul ignore next */ []));
3058
+ const remainingTime = computed(() => {
3059
+ const rate = itemsPerSecond();
3060
+ const outstanding = total() - completed();
3061
+ if (rate === null || rate <= 0 || outstanding <= 0)
3062
+ return null;
3063
+ return Math.round((outstanding / rate) * 1000);
3064
+ }, /* @ts-ignore */
3065
+ ...(ngDevMode ? [{ debugName: "remainingTime" }] : /* istanbul ignore next */ []));
3066
+ const runEntry = (entry) => defer(() => {
3067
+ if (cancelRequested) {
3068
+ record({ status: 'cancelled', index: entry.index, item: entry.item });
3069
+ return EMPTY;
3070
+ }
3071
+ const args = mapArgs(entry.item, entry.index);
3072
+ if (args === null) {
3073
+ record({ status: 'skipped', index: entry.index, item: entry.item });
3074
+ return EMPTY;
3075
+ }
3076
+ // The args reach the query through `execute()`, never `withArgs()`, so a function route has to
3077
+ // be told the missing feature is intentional or creating the query throws ET100.
3078
+ const create = () => queryCreator({ silenceMissingWithArgsFeatureError: true }, ...features);
3079
+ const query = runInInjectionContext(injector, () => devtoolsHandle ? runInQueryDevtoolsBatch({ batch: devtoolsHandle, index: entry.index }, create) : create());
3080
+ inFlight.update((count) => count + 1);
3081
+ query.execute({ args, options: { allowCache } });
3082
+ const snapshot = query.createSnapshot();
3083
+ return snapshot.isAlive.asObservable().pipe(filter((isAlive) => !isAlive), take(1),
3084
+ // A destroyed host tears the query down without ever settling it, so the run would hang.
3085
+ takeUntil(hostDestroyed$), tap(() => {
3086
+ const error = snapshot.error();
3087
+ if (error) {
3088
+ record({ status: 'error', index: entry.index, item: entry.item, args, error });
3089
+ if (stopOnError)
3090
+ cancelRequested = true;
3091
+ return;
3092
+ }
3093
+ record({
3094
+ status: 'success',
3095
+ index: entry.index,
3096
+ item: entry.item,
3097
+ args,
3098
+ response: snapshot.response(),
3099
+ });
3100
+ }), finalize(() => {
3101
+ inFlight.update((count) => count - 1);
3102
+ // The host's destruction already tore the query's injector down; destroying it again throws.
3103
+ if (!hostDestroyed)
3104
+ query.subtle.destroy();
3105
+ }));
3106
+ });
3107
+ const settleRun = (entries) => {
3108
+ const stoppedEarly = cancelRequested;
3109
+ for (const entry of entries) {
3110
+ settled[entry.index] ??= { status: 'cancelled', index: entry.index, item: entry.item };
3111
+ }
3112
+ publish();
3113
+ running.set(false);
3114
+ const all = results();
3115
+ const succeeded = all.filter((r) => r.status === 'success');
3116
+ const failed = all.filter((r) => r.status === 'error');
3117
+ const skipped = all.filter((r) => r.status === 'skipped');
3118
+ const notAttempted = all.filter((r) => r.status === 'cancelled');
3119
+ if (failed.length === 0)
3120
+ status.set(notAttempted.length === 0 ? 'success' : 'cancelled');
3121
+ else
3122
+ status.set(succeeded.length === 0 ? 'error' : 'partial');
3123
+ return {
3124
+ ok: failed.length === 0 && notAttempted.length === 0,
3125
+ cancelled: stoppedEarly,
3126
+ results: all,
3127
+ succeeded,
3128
+ failed,
3129
+ skipped,
3130
+ notAttempted,
3131
+ };
3132
+ };
3133
+ const runEntries = (collect) => defer(() => {
3134
+ if (running())
3135
+ throw queryBatchAlreadyRunning();
3136
+ const entries = collect();
3137
+ cancelRequested = false;
3138
+ running.set(true);
3139
+ status.set('running');
3140
+ publish();
3141
+ // After `publish()`: a retry clears its entries first, so this reads the count the retried
3142
+ // items are measured against, not the one from before they were dropped.
3143
+ completedBeforeRun.set(completed());
3144
+ runStartedAt.set(Date.now());
3145
+ lastSettleAt.set(null);
3146
+ return from(entries).pipe(mergeMap((entry) => runEntry(entry), concurrency), toArray(), map(() => settleRun(entries)));
3147
+ });
3148
+ const run = (items) => runEntries(() => {
3149
+ settled = new Array(items.length);
3150
+ total.set(items.length);
3151
+ return items.map((item, index) => ({ item, index }));
3152
+ });
3153
+ const retryFailed = () => runEntries(() => {
3154
+ const entries = results()
3155
+ .filter((r) => r.status === 'error' || r.status === 'cancelled')
3156
+ .map((r) => ({ item: r.item, index: r.index }));
3157
+ for (const entry of entries) {
3158
+ settled[entry.index] = undefined;
3159
+ }
3160
+ return entries;
3161
+ });
3162
+ const batch = {
3163
+ status: status.asReadonly(),
3164
+ running: running.asReadonly(),
3165
+ total: total.asReadonly(),
3166
+ completed,
3167
+ inFlight: inFlight.asReadonly(),
3168
+ succeeded: countOf('success'),
3169
+ failed: countOf('error'),
3170
+ skipped: countOf('skipped'),
3171
+ progress: computed(() => {
3172
+ const count = total();
3173
+ return count === 0 ? 0 : (completed() / count) * 100;
3174
+ }),
3175
+ itemsPerSecond,
3176
+ remainingTime,
3177
+ results: results.asReadonly(),
3178
+ errors: computed(() => failedResults().map((r) => r.error)),
3179
+ failedItems: computed(() => failedResults().map((r) => r.item)),
3180
+ run,
3181
+ retryFailed,
3182
+ cancel: () => {
3183
+ cancelRequested = true;
3184
+ },
3185
+ reset: () => {
3186
+ if (running())
3187
+ return;
3188
+ settled = [];
3189
+ total.set(0);
3190
+ results.set([]);
3191
+ status.set('idle');
3192
+ runStartedAt.set(null);
3193
+ lastSettleAt.set(null);
3194
+ completedBeforeRun.set(0);
3195
+ },
3196
+ };
3197
+ if (devtoolsHandle) {
3198
+ devtoolsHandle.current = batch;
3199
+ const internals = queryCreator.subtle.creatorInternals;
3200
+ const unregister = registerQueryDevtoolsEntry({
3201
+ kind: 'query-batch',
3202
+ handle: devtoolsHandle,
3203
+ route: internals.route,
3204
+ clientRef: internals.client,
3205
+ meta: { method: internals.method, concurrency, stopOnError: !!stopOnError },
3206
+ });
3207
+ destroyRef.onDestroy(unregister);
3208
+ }
3209
+ return batch;
3210
+ };
3211
+
2927
3212
  /**
2928
3213
  * Resolves an {@link QueryInvalidationOptions.url} to the absolute form request URLs are built in, so
2929
3214
  * the comparison - and the message the other tabs receive - never depends on who resolves it.
@@ -4320,6 +4605,8 @@ const buildSequence = (steps, state, devtoolsHandle) => {
4320
4605
  state.running.set(false);
4321
4606
  return { ok: true, responses: responses, snapshots };
4322
4607
  };
4608
+ const completed = computed(() => state.snapshots().length, /* @ts-ignore */
4609
+ ...(ngDevMode ? [{ debugName: "completed" }] : /* istanbul ignore next */ []));
4323
4610
  const sequence = {
4324
4611
  then: (query, mapArgs) => buildSequence([
4325
4612
  ...steps,
@@ -4328,6 +4615,8 @@ const buildSequence = (steps, state, devtoolsHandle) => {
4328
4615
  status: state.status.asReadonly(),
4329
4616
  running: state.running.asReadonly(),
4330
4617
  currentStep: state.currentStep.asReadonly(),
4618
+ completed,
4619
+ progress: computed(() => (steps.length === 0 ? 0 : (completed() / steps.length) * 100)),
4331
4620
  total: steps.length,
4332
4621
  queries: steps.map((s) => s.query),
4333
4622
  error: state.error.asReadonly(),
@@ -4500,6 +4789,54 @@ const resolveFieldTreePath = (fieldTree, path) => {
4500
4789
  return typeof current === 'function' ? current : null;
4501
4790
  };
4502
4791
 
4792
+ /**
4793
+ * Builds a signal form's `submission.action` around a mutation: submitting executes the query with
4794
+ * args derived from the form's value, waits for it to settle, and maps a failed request's violations
4795
+ * back onto the fields that caused them. `form().submitting()` therefore covers the whole round trip.
4796
+ *
4797
+ * This is the submit-time counterpart to {@link validateWithQuery}. The query's args come from the
4798
+ * submitted value rather than a `withArgs()` feature, which also means the query no longer reads the
4799
+ * form it belongs to - so it can be declared before it, and no derivation runs per keystroke.
4800
+ *
4801
+ * ```ts
4802
+ * protected createPost = createQuerySubmission({
4803
+ * queryCreator: postPost,
4804
+ * args: (value) => ({ body: value }),
4805
+ * onSuccess: (post) => this.router.navigate(['/posts', post.id]),
4806
+ * });
4807
+ *
4808
+ * protected form = form(this.model, postSchema, {
4809
+ * submission: { action: this.createPost.action },
4810
+ * });
4811
+ * ```
4812
+ *
4813
+ * ```html
4814
+ * <form [etForm]="form">…</form>
4815
+ * <et-query-error [error]="createPost.query.error()" [query]="createPost.query" />
4816
+ * ```
4817
+ *
4818
+ * Call it from an injection context.
4819
+ */
4820
+ const createQuerySubmission = (config) => {
4821
+ // The args reach the query through `execute()`, never `withArgs()`, so a function route has to be
4822
+ // told the missing feature is intentional or creating the query throws ET100.
4823
+ const query = config.queryCreator({ silenceMissingWithArgsFeatureError: true });
4824
+ const action = async (field) => {
4825
+ const args = config.args?.(field().value(), field) ?? null;
4826
+ if (config.args && args === null)
4827
+ return undefined;
4828
+ const snapshot = await executeUntilSettled(query, args === null ? undefined : { args });
4829
+ const error = snapshot.error();
4830
+ if (error) {
4831
+ return (config.mapViolations?.(error, field) ??
4832
+ mapViolationsToFormErrors({ fieldTree: field, error, rewritePath: config.rewritePath }));
4833
+ }
4834
+ config.onSuccess?.(snapshot.response(), field);
4835
+ return undefined;
4836
+ };
4837
+ return { query, action };
4838
+ };
4839
+
4503
4840
  // Shared core for the query-backed async validators (`validateWithQuery` /
4504
4841
  // `validateWithV2Query`). Everything except how the query is executed - the `factory` that turns
4505
4842
  // the debounced params into a `Resource` - is identical between the v2 and v3 variants, so it is
@@ -7253,6 +7590,18 @@ const generateQueryDevtoolsNumberPreset = (preset) => {
7253
7590
  }
7254
7591
  }
7255
7592
  };
7593
+ /**
7594
+ * Generates a plausible sample number inside the bounds a caller declares - a small integer, or one with
7595
+ * two decimals when `fractional`. The number presets break a layout on purpose; this one does not.
7596
+ */
7597
+ const generateQueryDevtoolsSampleNumber = (bounds) => {
7598
+ const min = bounds.min ?? 1;
7599
+ const max = Math.max(min, bounds.max ?? min + 999);
7600
+ const value = randomIntBetween(min, Math.min(max, min + 999));
7601
+ if (!bounds.fractional || value >= max)
7602
+ return value;
7603
+ return Math.min(max, Math.round((value + Math.random()) * 100) / 100);
7604
+ };
7256
7605
  const DAY_MS = 24 * 60 * 60 * 1000;
7257
7606
  /** `invalid` is deliberately unparseable - "the API sent a date my code can't parse" is a real bug class. */
7258
7607
  const datePresetValue = (preset) => {
@@ -7454,34 +7803,50 @@ const armQueryDevtoolsOverrideTransfer = (recorder, ops) => {
7454
7803
 
7455
7804
  // Generated from package.json by tools/scripts/generate-version.js - do not edit.
7456
7805
  /** The version of `@ethlete/query` this build was cut from. */
7457
- const QUERY_VERSION = '6.0.0-next.36';
7806
+ const QUERY_VERSION = '6.0.0-next.38';
7458
7807
 
7459
7808
  /** How deep a schema is expanded before a nested branch is given up on. */
7460
7809
  const MAX_DEPTH = 12;
7461
7810
  /** How many elements are generated for an array, whatever its `minItems` says. */
7462
7811
  const MAX_ITEMS = 3;
7812
+ /**
7813
+ * How many array elements are generated on their own rather than copied from the first. Nested arrays
7814
+ * multiply, so without a ceiling a body of arrays-in-arrays costs `MAX_ITEMS ^ MAX_DEPTH` walks.
7815
+ */
7816
+ const VARIED_ITEMS_BUDGET = 200;
7463
7817
  const HTTP_METHODS = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'];
7464
- const loader = /* @__PURE__ */ signal(null, /* @ts-ignore */
7465
- ...(ngDevMode ? [{ debugName: "loader" }] : /* istanbul ignore next */ []));
7466
- const state = /* @__PURE__ */ signal({ status: 'unavailable' }, /* @ts-ignore */
7467
- ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
7468
- const schemaDocument = /* @__PURE__ */ signal(null, /* @ts-ignore */
7469
- ...(ngDevMode ? [{ debugName: "schemaDocument" }] : /* istanbul ignore next */ []));
7818
+ /** The key a single loader is filed under, so one description answers for every client. */
7819
+ const ANY_CLIENT = '*';
7820
+ const loaders = /* @__PURE__ */ signal({}, /* @ts-ignore */
7821
+ ...(ngDevMode ? [{ debugName: "loaders" }] : /* istanbul ignore next */ []));
7822
+ const states = /* @__PURE__ */ signal({}, /* @ts-ignore */
7823
+ ...(ngDevMode ? [{ debugName: "states" }] : /* istanbul ignore next */ []));
7824
+ const documents = /* @__PURE__ */ signal({}, /* @ts-ignore */
7825
+ ...(ngDevMode ? [{ debugName: "documents" }] : /* istanbul ignore next */ []));
7470
7826
  const isRecord = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
7827
+ /** Which description answers for a client: its own, or the one that answers for all of them. */
7828
+ const keyOf = (clientName) => {
7829
+ const declared = loaders();
7830
+ if (clientName in declared)
7831
+ return clientName;
7832
+ return ANY_CLIENT in declared ? ANY_CLIENT : clientName;
7833
+ };
7834
+ const documentOf = (clientName) => documents()[keyOf(clientName)] ?? null;
7471
7835
  /**
7472
- * Where the API description stands, for the panel's seeding controls.
7836
+ * Where the description of one query client's API stands, for the panel's seeding controls.
7473
7837
  *
7474
7838
  * Part of the devtools contract. **Not part of the general public contract.**
7475
7839
  */
7476
- const queryDevtoolsSchemaState = /* @__PURE__ */ state.asReadonly();
7840
+ const queryDevtoolsSchemaState = (clientName) => states()[keyOf(clientName)] ?? { status: 'unavailable' };
7477
7841
  /**
7478
- * Installs the application's schema loader. Called by `provideQueryDevtools()`; nothing else may call it.
7842
+ * Installs the application's schema loaders. Called by `provideQueryDevtools()`; nothing else may call it.
7479
7843
  * @internal
7480
7844
  */
7481
7845
  const setQueryDevtoolsSchemaLoader = (next) => {
7482
- loader.set(next ?? null);
7483
- state.set({ status: next ? 'idle' : 'unavailable' });
7484
- schemaDocument.set(null);
7846
+ const declared = next === undefined ? {} : typeof next === 'function' ? { [ANY_CLIENT]: next } : { ...next };
7847
+ loaders.set(declared);
7848
+ states.set(Object.fromEntries(Object.keys(declared).map((key) => [key, { status: 'idle' }])));
7849
+ documents.set({});
7485
7850
  };
7486
7851
  /** A `() => import('./openapi.json')` loader hands back the module rather than the document inside it. */
7487
7852
  const unwrapModule = (value) => {
@@ -7498,53 +7863,58 @@ const messageOf = (error) => (error instanceof Error ? error.message : String(er
7498
7863
  *
7499
7864
  * Part of the devtools contract. **Not part of the general public contract.**
7500
7865
  */
7501
- const loadQueryDevtoolsSchema = () => {
7502
- const load = loader();
7503
- const status = state().status;
7866
+ const loadQueryDevtoolsSchema = (clientName) => {
7867
+ const key = keyOf(clientName);
7868
+ const load = loaders()[key];
7869
+ const status = queryDevtoolsSchemaState(clientName).status;
7504
7870
  if (!load || status === 'loading' || status === 'ready')
7505
7871
  return;
7506
- state.set({ status: 'loading' });
7872
+ const setState = (next) => states.update((current) => ({ ...current, [key]: next }));
7873
+ setState({ status: 'loading' });
7507
7874
  Promise.resolve()
7508
7875
  .then(() => load())
7509
7876
  .then((value) => {
7510
7877
  const parsed = unwrapModule(value);
7511
7878
  if (!isRecord(parsed))
7512
7879
  throw new Error('The schema loader did not return an object.');
7513
- schemaDocument.set(parsed);
7514
- state.set({ status: 'ready' });
7880
+ documents.update((current) => ({ ...current, [key]: parsed }));
7881
+ setState({ status: 'ready' });
7515
7882
  })
7516
7883
  .catch((error) => {
7517
- schemaDocument.set(null);
7518
- state.set({ status: 'error', message: messageOf(error) });
7884
+ documents.update((current) => {
7885
+ const { [key]: _dropped, ...rest } = current;
7886
+ return rest;
7887
+ });
7888
+ setState({ status: 'error', message: messageOf(error) });
7519
7889
  });
7520
7890
  };
7521
- const namedSchemas = /* @__PURE__ */ computed(() => {
7522
- const doc = schemaDocument();
7523
- if (!doc)
7524
- return {};
7891
+ const schemasOf = (doc) => {
7525
7892
  const components = doc['components'];
7526
7893
  return {
7527
7894
  ...(isRecord(doc['$defs']) ? doc['$defs'] : null),
7528
7895
  ...(isRecord(doc['definitions']) ? doc['definitions'] : null),
7529
7896
  ...(isRecord(components) && isRecord(components['schemas']) ? components['schemas'] : null),
7530
7897
  };
7531
- }, /* @ts-ignore */
7532
- ...(ngDevMode ? [{ debugName: "namedSchemas" }] : /* istanbul ignore next */ []));
7898
+ };
7899
+ const namedSchemasByKey = /* @__PURE__ */ computed(() => Object.fromEntries(Object.entries(documents()).map(([key, doc]) => [key, schemasOf(doc)])), /* @ts-ignore */
7900
+ ...(ngDevMode ? [{ debugName: "namedSchemasByKey" }] : /* istanbul ignore next */ []));
7901
+ const namedSchemas = (clientName) => namedSchemasByKey()[keyOf(clientName)] ?? {};
7902
+ const schemaNamesByKey = /* @__PURE__ */ computed(() => Object.fromEntries(Object.entries(namedSchemasByKey()).map(([key, schemas]) => [key, Object.keys(schemas).sort()])), /* @ts-ignore */
7903
+ ...(ngDevMode ? [{ debugName: "schemaNamesByKey" }] : /* istanbul ignore next */ []));
7533
7904
  /**
7534
- * Every schema the description names, sorted - the designer's "seed from a type" list.
7905
+ * Every schema one client's description names, sorted - the designer's "seed from a type" list.
7535
7906
  *
7536
7907
  * Part of the devtools contract. **Not part of the general public contract.**
7537
7908
  */
7538
- const queryDevtoolsSchemaNames = /* @__PURE__ */ computed(() => Object.keys(namedSchemas()).sort(), /* @ts-ignore */
7539
- ...(ngDevMode ? [{ debugName: "queryDevtoolsSchemaNames" }] : /* istanbul ignore next */ []));
7909
+ const queryDevtoolsSchemaNames = (clientName) => schemaNamesByKey()[keyOf(clientName)] ?? [];
7540
7910
  const decodePointer = (step) => decodeURIComponent(step.replace(/~1/g, '/').replace(/~0/g, '~'));
7541
7911
  /** The last segment of a `$ref` - `#/components/schemas/MatchId` is what a field's type is called. */
7542
7912
  const refLabel = (ref) => decodePointer(ref.split('/').pop() ?? ref);
7543
- /** Resolves a local JSON pointer against the loaded document. A remote `$ref` cannot be followed. */
7544
- const resolveRef = (ref) => {
7913
+ /** Resolves a local JSON pointer against one loaded document. A remote `$ref` cannot be followed. */
7914
+ const resolveRef = (ref, doc) => {
7545
7915
  if (!ref.startsWith('#/'))
7546
7916
  return undefined;
7547
- let current = schemaDocument();
7917
+ let current = doc;
7548
7918
  for (const step of ref.slice(2).split('/')) {
7549
7919
  if (!isRecord(current))
7550
7920
  return undefined;
@@ -7626,27 +7996,62 @@ const FORMAT_SAMPLES = {
7626
7996
  byte: '',
7627
7997
  binary: '',
7628
7998
  };
7999
+ const STRESS_STRING_PRESETS = ['long', 'longWord', 'unicode'];
8000
+ const finiteNumber = (value) => (typeof value === 'number' && Number.isFinite(value) ? value : null);
8001
+ const pickStressStringPreset = () => STRESS_STRING_PRESETS[Math.floor(Math.random() * STRESS_STRING_PRESETS.length)];
8002
+ /** Keeps a generated string inside `minLength`/`maxLength`, since a seed is exported as a real body. */
8003
+ const fitLength = (value, schema) => {
8004
+ const min = finiteNumber(schema['minLength']);
8005
+ const max = finiteNumber(schema['maxLength']);
8006
+ let out = value;
8007
+ while (min !== null && out.length < min)
8008
+ out += value || 'x';
8009
+ return max === null ? out : out.slice(0, max);
8010
+ };
7629
8011
  /**
7630
- * A placeholder string: the declared format's shape where there is one, otherwise the field's own name -
7631
- * which reads as obviously unreal while still saying which field you are looking at.
8012
+ * The value of a string field. A declared format wins in every style - a `date-time` full of lorem is
8013
+ * wrong data rather than a stress test - and an unformatted string is the field's own name, a short
8014
+ * sample or one of the three shapes that break a layout.
7632
8015
  */
7633
- const stringSample = (node, schema) => {
8016
+ const stringSample = (node, schema, ctx) => {
7634
8017
  const format = schema['format'];
7635
8018
  if (typeof format === 'string' && format in FORMAT_SAMPLES)
7636
8019
  return FORMAT_SAMPLES[format];
8020
+ if (ctx.style === 'realistic')
8021
+ return fitLength(generateQueryDevtoolsStringPreset('short'), schema);
8022
+ if (ctx.style === 'stress')
8023
+ return fitLength(generateQueryDevtoolsStringPreset(pickStressStringPreset()), schema);
7637
8024
  const title = schema['title'];
7638
8025
  if (typeof title === 'string' && title)
7639
8026
  return title;
7640
8027
  return node.key ?? 'string';
7641
8028
  };
7642
- const numberSample = (schema) => {
7643
- for (const keyword of ['minimum', 'exclusiveMinimum', 'default']) {
7644
- const value = schema[keyword];
7645
- if (typeof value === 'number' && Number.isFinite(value))
7646
- return keyword === 'exclusiveMinimum' ? value + 1 : value;
8029
+ const boundsOf = (schema) => {
8030
+ const exclusiveMin = finiteNumber(schema['exclusiveMinimum']);
8031
+ const exclusiveMax = finiteNumber(schema['exclusiveMaximum']);
8032
+ return {
8033
+ min: finiteNumber(schema['minimum']) ?? (exclusiveMin === null ? null : exclusiveMin + 1),
8034
+ max: finiteNumber(schema['maximum']) ?? (exclusiveMax === null ? null : exclusiveMax - 1),
8035
+ };
8036
+ };
8037
+ const clampToBounds = (value, bounds) => {
8038
+ if (bounds.min !== null && value < bounds.min)
8039
+ return bounds.min;
8040
+ if (bounds.max !== null && value > bounds.max)
8041
+ return bounds.max;
8042
+ return value;
8043
+ };
8044
+ const numberSample = (schema, ctx) => {
8045
+ const bounds = boundsOf(schema);
8046
+ if (ctx.style === 'placeholder')
8047
+ return bounds.min ?? finiteNumber(schema['default']) ?? 0;
8048
+ if (ctx.style === 'realistic') {
8049
+ return generateQueryDevtoolsSampleNumber({ ...bounds, fractional: typeOf(schema) === 'number' });
7647
8050
  }
7648
- return 0;
8051
+ const allowsNegative = bounds.min === null || bounds.min < 0;
8052
+ return clampToBounds(generateQueryDevtoolsNumberPreset(allowsNegative && Math.random() < 0.5 ? 'negative' : 'huge'), bounds);
7649
8053
  };
8054
+ const booleanSample = (ctx) => ctx.style !== 'placeholder' && Math.random() < 0.5;
7650
8055
  const childNode = (parent, child) => ({
7651
8056
  schema: child.schema,
7652
8057
  path: parent.path ? `${parent.path}.${child.key}` : child.key,
@@ -7680,12 +8085,14 @@ const generateArray = (node, ctx) => {
7680
8085
  const items = schema['items'];
7681
8086
  if (!isRecord(items))
7682
8087
  return [];
7683
- const minItems = typeof schema['minItems'] === 'number' ? schema['minItems'] : 1;
7684
- const count = Math.min(Math.max(1, minItems), MAX_ITEMS);
8088
+ const minItems = finiteNumber(schema['minItems']) ?? (ctx.style === 'placeholder' ? 1 : MAX_ITEMS);
8089
+ const count = Math.min(Math.max(1, minItems), MAX_ITEMS, finiteNumber(schema['maxItems']) ?? MAX_ITEMS);
7685
8090
  const target = { schema: items, path: `${node.path ? `${node.path}.` : ''}*`, depth: node.depth + 1, key: node.key };
7686
8091
  ctx.types.set(target.path, describeSchema(items));
7687
8092
  const element = generate(target, ctx);
7688
- return Array.from({ length: count }, () => structuredCopy(element));
8093
+ return Array.from({ length: count }, (_, index) => index && ctx.style !== 'placeholder' && ctx.varied++ < VARIED_ITEMS_BUDGET
8094
+ ? generate(target, ctx)
8095
+ : structuredCopy(element));
7689
8096
  };
7690
8097
  /** Each generated element is its own value, so editing one in the designer does not edit the others. */
7691
8098
  const structuredCopy = (value) => {
@@ -7719,7 +8126,7 @@ const generate = (node, ctx) => {
7719
8126
  ctx.notes.add(`${name} contains itself - the recursion was cut at ${at(node.path)} with null.`);
7720
8127
  return null;
7721
8128
  }
7722
- const resolved = resolveRef(ref);
8129
+ const resolved = resolveRef(ref, ctx.doc);
7723
8130
  if (resolved === undefined) {
7724
8131
  ctx.notes.add(`${ref} could not be resolved - generated as null at ${at(node.path)}.`);
7725
8132
  return null;
@@ -7754,12 +8161,12 @@ const generate = (node, ctx) => {
7754
8161
  case 'array':
7755
8162
  return generateArray(node, ctx);
7756
8163
  case 'string':
7757
- return stringSample(node, schema);
8164
+ return stringSample(node, schema, ctx);
7758
8165
  case 'integer':
7759
8166
  case 'number':
7760
- return numberSample(schema);
8167
+ return numberSample(schema, ctx);
7761
8168
  case 'boolean':
7762
- return false;
8169
+ return booleanSample(ctx);
7763
8170
  case 'null':
7764
8171
  return null;
7765
8172
  default:
@@ -7770,21 +8177,22 @@ const generate = (node, ctx) => {
7770
8177
  ctx.notes.add(`${at(node.path)} declares no type - generated as null.`);
7771
8178
  return null;
7772
8179
  };
7773
- const seedFrom = (schema, name) => {
7774
- const ctx = { types: new Map(), notes: new Set(), refs: name ? [name] : [] };
8180
+ const seedFrom = (schema, name, style, doc) => {
8181
+ const ctx = { types: new Map(), notes: new Set(), refs: name ? [name] : [], style, varied: 0, doc };
7775
8182
  const body = generate({ schema, path: '', depth: 0, key: null }, ctx);
7776
8183
  return { body, schemaName: name, types: ctx.types, notes: [...ctx.notes] };
7777
8184
  };
7778
8185
  /**
7779
- * Generates a body from one named schema (`MatchView`), or `null` when the description does not name it.
8186
+ * Generates a body from one schema the client's description names (`MatchView`), or `null` when it names
8187
+ * no such thing. The style decides how lifelike its values are; the shape is the same either way.
7780
8188
  *
7781
8189
  * Part of the devtools contract. **Not part of the general public contract.**
7782
8190
  */
7783
- const seedQueryDevtoolsSchemaBody = (name) => {
7784
- const schema = namedSchemas()[name];
8191
+ const seedQueryDevtoolsSchemaBody = (clientName, name, style = 'placeholder') => {
8192
+ const schema = namedSchemas(clientName)[name];
7785
8193
  if (schema === undefined)
7786
8194
  return null;
7787
- return seedFrom(schema, name);
8195
+ return seedFrom(schema, name, style, documentOf(clientName));
7788
8196
  };
7789
8197
  /** Where a schema was collected from, so the same name arriving from two pointers is caught. */
7790
8198
  const originOf = (label, pointer) => pointer ?? `named:${label}`;
@@ -7821,8 +8229,9 @@ const rewriteRefs = (value, queue) => {
7821
8229
  *
7822
8230
  * Part of the devtools contract. **Not part of the general public contract.**
7823
8231
  */
7824
- const collectQueryDevtoolsSchemaComponents = (names) => {
7825
- const declared = namedSchemas();
8232
+ const collectQueryDevtoolsSchemaComponents = (clientName, names) => {
8233
+ const declared = namedSchemas(clientName);
8234
+ const doc = documentOf(clientName);
7826
8235
  const schemas = {};
7827
8236
  const notes = new Set();
7828
8237
  const origins = new Map();
@@ -7837,7 +8246,7 @@ const collectQueryDevtoolsSchemaComponents = (names) => {
7837
8246
  }
7838
8247
  continue;
7839
8248
  }
7840
- const schema = request.pointer === null ? declared[request.label] : resolveRef(request.pointer);
8249
+ const schema = request.pointer === null ? declared[request.label] : resolveRef(request.pointer, doc);
7841
8250
  if (schema === undefined) {
7842
8251
  if (request.pointer !== null) {
7843
8252
  notes.add(`${request.pointer} could not be resolved, so ${request.label} is missing from the export.`);
@@ -7884,14 +8293,8 @@ const patternsMatch = (a, b) => {
7884
8293
  return isParam(segment) || isParam(other) ? isParam(segment) && isParam(other) : segment === other;
7885
8294
  });
7886
8295
  };
7887
- /**
7888
- * Every route the description declares, as the designer offers them - including the ones no query has
7889
- * ever called, which is the case a mock exists for.
7890
- *
7891
- * Part of the devtools contract. **Not part of the general public contract.**
7892
- */
7893
- const queryDevtoolsSchemaRoutes = /* @__PURE__ */ computed(() => {
7894
- const paths = schemaDocument()?.['paths'];
8296
+ const routesOf = (doc) => {
8297
+ const paths = doc['paths'];
7895
8298
  if (!isRecord(paths))
7896
8299
  return [];
7897
8300
  const routes = [];
@@ -7911,10 +8314,18 @@ const queryDevtoolsSchemaRoutes = /* @__PURE__ */ computed(() => {
7911
8314
  }
7912
8315
  }
7913
8316
  return routes;
7914
- }, /* @ts-ignore */
7915
- ...(ngDevMode ? [{ debugName: "queryDevtoolsSchemaRoutes" }] : /* istanbul ignore next */ []));
7916
- const findOperation = (target) => {
7917
- const paths = schemaDocument()?.['paths'];
8317
+ };
8318
+ const routesByKey = /* @__PURE__ */ computed(() => Object.fromEntries(Object.entries(documents()).map(([key, doc]) => [key, routesOf(doc)])), /* @ts-ignore */
8319
+ ...(ngDevMode ? [{ debugName: "routesByKey" }] : /* istanbul ignore next */ []));
8320
+ /**
8321
+ * Every route one client's description declares, as the designer offers them - including the ones no
8322
+ * query has ever called, which is the case a mock exists for.
8323
+ *
8324
+ * Part of the devtools contract. **Not part of the general public contract.**
8325
+ */
8326
+ const queryDevtoolsSchemaRoutes = (clientName) => routesByKey()[keyOf(clientName)] ?? [];
8327
+ const findOperation = (target, doc) => {
8328
+ const paths = doc?.['paths'];
7918
8329
  if (!isRecord(paths))
7919
8330
  return null;
7920
8331
  const method = target.method.toLowerCase();
@@ -7971,8 +8382,9 @@ const jsonSchemaOf = (response) => {
7971
8382
  *
7972
8383
  * Part of the devtools contract. **Not part of the general public contract.**
7973
8384
  */
7974
- const seedQueryDevtoolsSchemaRoute = (target) => {
7975
- const match = findOperation(target);
8385
+ const seedQueryDevtoolsSchemaRoute = (target, style = 'placeholder') => {
8386
+ const doc = documentOf(target.clientName);
8387
+ const match = findOperation(target, doc);
7976
8388
  if (!match)
7977
8389
  return null;
7978
8390
  const success = successResponse(match.operation);
@@ -7985,11 +8397,11 @@ const seedQueryDevtoolsSchemaRoute = (target) => {
7985
8397
  // schema its `name` stands for - otherwise the walk reads the name as one it is already expanding and
7986
8398
  // cuts the whole body as a cycle.
7987
8399
  const ref = isRecord(json.schema) ? json.schema['$ref'] : null;
7988
- const named = typeof ref === 'string' ? { schema: resolveRef(ref), name: refLabel(ref) } : null;
8400
+ const named = typeof ref === 'string' ? { schema: resolveRef(ref, doc), name: refLabel(ref) } : null;
7989
8401
  if (named && named.schema === undefined)
7990
8402
  return null;
7991
8403
  const seed = json.example === undefined
7992
- ? seedFrom(named ? named.schema : json.schema, named ? named.name : null)
8404
+ ? seedFrom(named ? named.schema : json.schema, named ? named.name : null, style, doc)
7993
8405
  : {
7994
8406
  body: json.example,
7995
8407
  schemaName: null,
@@ -8372,6 +8784,12 @@ const applyQueryDevtoolsTokenTtl = (options) => {
8372
8784
  * so the list is capped for the same reason the repository caps its unused entries.
8373
8785
  */
8374
8786
  const MAX_QUERY_DEVTOOLS_TOMBSTONES = 50;
8787
+ /**
8788
+ * How many of its settled items' queries one batch keeps. Counted per batch rather than against
8789
+ * {@link MAX_QUERY_DEVTOOLS_TOMBSTONES}, so a bulk run cannot evict the tombstones the panel is read
8790
+ * for - and low, because the batch's own entry already holds every item's args, response and error.
8791
+ */
8792
+ const MAX_QUERY_BATCH_TOMBSTONES = 20;
8375
8793
  const frozen = (value) => () => value;
8376
8794
  const noop = () => undefined;
8377
8795
  /**
@@ -8593,8 +9011,8 @@ const registerEntry = (registration) => {
8593
9011
  if (index === -1)
8594
9012
  return list;
8595
9013
  const next = list.slice();
8596
- // Only queries leave a tombstone. A stack, sequence, form or auth provider is a container whose
8597
- // interesting state is the queries it owns - each of which tombstones on its own.
9014
+ // Only queries leave a tombstone. A stack, sequence, batch, form or auth provider is a container
9015
+ // whose interesting state is the queries it owns - each of which tombstones on its own.
8598
9016
  if (fullEntry.kind !== 'query') {
8599
9017
  next.splice(index, 1);
8600
9018
  return next;
@@ -8603,16 +9021,39 @@ const registerEntry = (registration) => {
8603
9021
  return capTombstones(next);
8604
9022
  });
8605
9023
  };
8606
- /** Drops the oldest tombstones once there are more than {@link MAX_QUERY_DEVTOOLS_TOMBSTONES} of them. */
9024
+ /** The oldest `count` entries of a bucket, which is what a cap drops when the bucket is over it. */
9025
+ const oldestOver = (bucket, cap) => bucket.length <= cap
9026
+ ? []
9027
+ : bucket.sort((a, b) => (a.destroyedAt ?? 0) - (b.destroyedAt ?? 0)).slice(0, bucket.length - cap);
9028
+ /**
9029
+ * Caps the tombstones the registry holds. A batch's items are counted per batch rather than against the
9030
+ * shared budget: a batch destroys one query per item as it settles, so a single 500-item run would
9031
+ * otherwise fill the whole buffer and evict every tombstone the panel is actually read for - the `401`
9032
+ * that took its component down with it. Each batch keeps its own recent tail instead.
9033
+ */
8607
9034
  const capTombstones = (list) => {
8608
- const excess = list.filter((e) => e.destroyedAt).length - MAX_QUERY_DEVTOOLS_TOMBSTONES;
8609
- if (excess <= 0)
8610
- return list;
8611
- const doomed = new Set(list
8612
- .filter((e) => e.destroyedAt)
8613
- .sort((a, b) => (a.destroyedAt ?? 0) - (b.destroyedAt ?? 0))
8614
- .slice(0, excess));
8615
- return list.filter((e) => !doomed.has(e));
9035
+ const shared = [];
9036
+ const perBatch = new Map();
9037
+ for (const entry of list) {
9038
+ if (!entry.destroyedAt)
9039
+ continue;
9040
+ const batch = entry.meta.batch;
9041
+ if (!batch) {
9042
+ shared.push(entry);
9043
+ continue;
9044
+ }
9045
+ const bucket = perBatch.get(batch);
9046
+ if (bucket)
9047
+ bucket.push(entry);
9048
+ else
9049
+ perBatch.set(batch, [entry]);
9050
+ }
9051
+ const doomed = new Set(oldestOver(shared, MAX_QUERY_DEVTOOLS_TOMBSTONES));
9052
+ for (const bucket of perBatch.values()) {
9053
+ for (const entry of oldestOver(bucket, MAX_QUERY_BATCH_TOMBSTONES))
9054
+ doomed.add(entry);
9055
+ }
9056
+ return doomed.size ? list.filter((e) => !doomed.has(e)) : list;
8616
9057
  };
8617
9058
  /**
8618
9059
  * Forgets destroyed entries the registry is holding - the panel's "clear gone" action. Pass the ids to
@@ -14196,5 +14637,5 @@ const createWebSocketClient = (options) => {
14196
14637
  * Generated bundle index. Do not edit.
14197
14638
  */
14198
14639
 
14199
- export { BasicAuthProvider, BearerAuthFeatureType, BooleanArrayQueryField, CustomHeaderAuthProvider, DEFAULT_KEEP_UNUSED_FOR, DEFAULT_QUERY_PERSISTENCE_MAX_AGE, DEFAULT_QUERY_PERSISTENCE_MAX_ENTRIES, DEFAULT_QUERY_PERSISTENCE_VERSION, DEFAULT_QUERY_PERSISTENCE_WRITE_DELAY, DateArrayQueryField, DateQueryField, EMPTY_QUERY_DEVTOOLS_FAULT, EntityStore, IGNORED_FILTER_COUNT_FIELDS, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, LegacyQuery, LegacyQueryCreator, MAX_QUERY_DEVTOOLS_TOMBSTONES, MAX_UNUSED_ENTRIES, NumberArrayQueryField, ParseHttpErrorCodeToMessageDePipe, ParseHttpErrorCodeToMessageEnPipe, ParseHttpErrorCodeToTitleDePipe, ParseHttpErrorCodeToTitleEnPipe, QUERY_CLIENT_DEVTOOLS_TOKEN, QUERY_DEVTOOLS_FAULT_STATUSES, QUERY_DEVTOOLS_TOKEN_TTL_LIMIT, QUERY_PERSISTENCE_STORE_VERSION, QUERY_SYNC_PROTOCOL_VERSION, QUERY_VERSION, QueryClientFeatureType, QueryDevtoolsComponent, QueryDirective, QueryFeatureType, QueryField, QueryForm, QueryRuntimeErrorCode, QueryShortNamePipe, QueryStore, SERVER_ERROR_KIND, SERVER_VIOLATION_ERROR_KIND, SPEED_BUFFER_TIME_IN_MS, SearchQueryField, SortQueryField, StringArrayQueryField, V2BearerAuthProvider, V2Query, V2QueryClient, V2QueryCreator, addQueryContainerHandling, applyQueryDevtoolsOverrides, applyQueryDevtoolsTokenTtl, applyQueryFeatures, armAllQueryDevtoolsMocks, armQueryDevtoolsMock, armQueryDevtoolsOverrideTransfer, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, booleanArrayQueryField, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, canOverrideQueryDevtoolsTokenTtl, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, clearQueryDevtoolsArmedMocks, clearQueryDevtoolsFaults, clearQueryDevtoolsMockStore, clearQueryDevtoolsOverrideStore, clearQueryDevtoolsStore, clearQueryDevtoolsTokenTtl, clearQueryDevtoolsTombstones, clearRestoredQueryDevtoolsOverrides, collectLeafPaths, collectQueryDevtoolsSchemaComponents, collectQueryFormLinks, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, consumeSuppressQueryStackDevtools, contentfulGqlLikePaginationAdapter, countUnresolvedQueryDevtoolsOverrides, createAuthGuard, createBaseQuery, createBaseQueryCreator, createBearerAuthProvider, createDefaultRetryFn, createDeleteQuery, createExecuteFn, createGetQuery, createGqlExecuteFn, createGqlMutationViaGet, createGqlMutationViaPost, createGqlQuery, createGqlQueryCreator, createGqlQueryViaGet, createGqlQueryViaPost, createHttpRequest, createIndexedDbQueryPersistenceAdapter, createInfinityQueryConfig, createLegacyQueryCreator, createNoopQueryPersistenceAdapter, createPagedQueryStack, createPatchQuery, createPersistentAuthFeature, createPostQuery, createPutQuery, createQuery, 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, deleteQueryDevtoolsMock, describeQueryDevtoolsFeatures, detectContentTypeHeader, detectPaginationShape, dynLikePaginationAdapter, effectComputed, emptyQueryArgs, ethletePaginationAdapter, executeUntilSettled, extractExpiresInSeconds, extractFormViolations, extractHtmlErrorMessage, extractQuery, fakePaginationAdapter, filterFailure, filterNull, filterQueryStates, filterSuccess, forEachHeader, formatQueryDevtoolsDuration, generateQueryDevtoolsNumberPreset, generateQueryDevtoolsStringPreset, getBearerAuthProviderName, getDefaultHeaders, getQueryClientName, getQueryFeatureUsage, getResponseUrl, ggLikePaginationAdapter, gql, gqlDataPropertyMissingInResponse, hasHeader, hasQueryDevtoolsOverridesAtPath, htmlErrorPayload, htmlQueryErrorParser, ignoreAutoRefresh, initQueryDevtoolsFaults, initQueryDevtoolsMocks, initQueryDevtoolsOverridePersistence, initQueryDevtoolsSettings, injectInfinityQueryResponseDelay, injectQueryContext, insertFrom, invalidBaseRouteError, invalidBodyError, invalidRouteError, invalidStateInsideSecureExecuteFactory, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isClassValidatorError, isCreateGqlQueryOptions, isCustomHeaderAuthProvider, isDateShapedLeaf, isEmptyString, isGqlQueryConfig, isHtmlErrorPayload, isLegacyQuery, isNaN$1 as isNaN, isPageOutOfRangeError, isQuery, isQueryCollection, isQueryDevtoolsEnabled, isQueryDevtoolsFaultArmed, isQueryDevtoolsRequestInterceptionEnabled, isQueryErrorResponse, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyFormViolationListError, isSymfonyListError, isSymfonyPagerfantaOutOfRangeError, isUnderInvalidatedUrl, legacyPrepareFallbackInjector, legacyPrepareWithoutInjectionContext, loadQueryDevtoolsSchema, mapToPaginated, mapViolationsToFormErrors, matchesQueryDevtoolsMockPattern, matchesQueryDevtoolsMockQuery, maybeExecute, measureQueryDevtoolsPayload, mergeHeaders, nestedEffect, noteQueryFormRead, numberArrayQueryField, pagedQueryStackNextPageCalledWithoutPreviousPage, pagedQueryStackPageBiggerThanTotalPages, pagedQueryStackPreviousPageCalledButAlreadyAtFirstPage, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, parseHttpErrorCodeToMessageDe, parseHttpErrorCodeToMessageEn, parseHttpErrorCodeToTitleDe, parseHttpErrorCodeToTitleEn, parseQueryDevtoolsOverrideTransfer, parseQueryRoute, patchQueryDevtoolsTokenPayload, pathParamsMissingInRouteFunctionError, provideInfinityQueryResponseDelay, provideLegacyPrepareFallback, provideQueryClientForDevtools, provideQueryDevtools, queryArrayComputed, queryClientFeatureUsedMultipleTimes, queryComputed, queryComputedTillTruthy, queryDevtoolsAbout, queryDevtoolsArmedMocks, queryDevtoolsArmedMocksRestored, queryDevtoolsEntries, queryDevtoolsFaults, queryDevtoolsFaultsRestored, queryDevtoolsFnDetail, queryDevtoolsMockId, queryDevtoolsMocks, queryDevtoolsOverridePersistence, queryDevtoolsRequestPath, queryDevtoolsResponseHistory, queryDevtoolsRestoredOverridesScope, queryDevtoolsSchemaNames, queryDevtoolsSchemaRoutes, queryDevtoolsSchemaState, queryDevtoolsSettings, queryDevtoolsStorage, queryDevtoolsTokenTtls, queryErrorMessage, queryErrorMessages, queryExecute, queryFeatureUsedMultipleTimes, queryField, querySequence, querySequenceAlreadyRunning, queryStackTotalQueriesAndExpectedQueriesMismatch, queryStackWithArgsUsed, queryStackWithResponseUpdateUsed, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, queryStateErrorSignal, queryStateLoadingSignal, queryStateResponseSignal, queryStateSignal, readQueryDevtoolsStore, registerEthleteVersion, registerQueryDevtoolsEntry, registerQueryErrorParser, removeFrom, request, resetExecuteState, resetPageOnError, resolveInvalidationUrl, resolveQueryDevtoolsFault, resolveQueryDevtoolsFaultForAttempt, resolveQueryDevtoolsMock, resolveQueryDevtoolsMockForAttempt, restoredQueryDevtoolsOverrides, runDefaultQueryRetry, runQueryErrorParsers, saveQueryDevtoolsMock, searchQueryField, seedQueryDevtoolsSchemaBody, seedQueryDevtoolsSchemaRoute, serializeBody, serializeQueryDevtoolsOverrideTransfer, setDefaultQueryRetryFn, setQueryDevtoolsAppInfo, setQueryDevtoolsArmedMocksScope, setQueryDevtoolsFault, setQueryDevtoolsFaultResolver, setQueryDevtoolsFaultsScope, setQueryDevtoolsFormLinksFactory, setQueryDevtoolsMockResolver, setQueryDevtoolsOverridePersistence, setQueryDevtoolsOverridesFactory, setQueryDevtoolsOverridesScope, setQueryDevtoolsRegistrar, setQueryDevtoolsResponseHistory, setQueryDevtoolsSchemaLoader, setQueryDevtoolsSettings, setQueryDevtoolsStatsFactory, setQueryDevtoolsTokenPayloadPatcher, setQueryDevtoolsTokenTtl, setupQueryDependencies, setupQueryExecuteState, setupQueryState, shouldAutoExecuteGqlQuery, shouldAutoExecuteQuery, shouldCacheQuery, shouldRetryRequest, silenceMissingWithArgsFeatureErrorUsedButWithArgsPresent, skipPaginationPageParamCalculator, smartDuplicateArrayItem, snapshotQueryDevtoolsHandle, sortQueryField, splitQueryConfig, stringArrayQueryField, stringifyQueryRouteParts, sumQueryDevtoolsStats, suppressNextQueryStackDevtools, switchQueryCollectionState, switchQueryState, symfonyQueryErrorParser, takeUntilResponse, toQuerySignal, toQuerySubject, tokensNotAvailableInsideAuthAndExec, tombstoneOf, transformArrayResponse, transformExecStateToQueryState, transformGql, transformMethod, transformPaginatedResponse, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray, uncacheableRequestHasAllowCacheParam, uncacheableRequestHasCacheKeyParam, unwrapQuerySyncMessage, v2BuildQueryCacheKey, v2ExtractExpiresInSeconds, v2ShouldCacheQuery, v2ShouldRetryRequest, validateWithQuery, validateWithV2Query, withArgs, withArgsQueryFeatureMissingButRouteIsFunction, withAuthenticationQuery, withAutoRefresh, withAutoRefreshUsedInManualQuery, withAutoRefreshUsedOnUnsupportedHttpMethod, withBearerAuthMultiTabSync, withDefaultRetry, withErrorHandling, withEthleteApiErrors, withHtmlErrorParsing, withInactivityLogout, withLogging, withLongPolling, withLongPollingUsedOnUnsupportedHttpMethod, withLongPollingUsedWithPolling, withMultiTabSync, withPageResetOnError, withPersistentAuth, withPolling, withPollingUsedOnUnsupportedHttpMethod, withQueryDevtoolsOverridePersistence, withQueryPersistence, withRefreshQuery, withResponseUpdate, withSuccessHandling, withSymfonyErrors, withTokenExpirationWarning, withTokenRevocation, withTracking, wrapAsObservableSignal, wrapQuerySyncMessage, writeQueryDevtoolsStore };
14640
+ export { BasicAuthProvider, BearerAuthFeatureType, BooleanArrayQueryField, CustomHeaderAuthProvider, DEFAULT_KEEP_UNUSED_FOR, DEFAULT_QUERY_PERSISTENCE_MAX_AGE, DEFAULT_QUERY_PERSISTENCE_MAX_ENTRIES, DEFAULT_QUERY_PERSISTENCE_VERSION, DEFAULT_QUERY_PERSISTENCE_WRITE_DELAY, DateArrayQueryField, DateQueryField, EMPTY_QUERY_DEVTOOLS_FAULT, EntityStore, IGNORED_FILTER_COUNT_FIELDS, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, LegacyQuery, LegacyQueryCreator, MAX_QUERY_BATCH_TOMBSTONES, MAX_QUERY_DEVTOOLS_TOMBSTONES, MAX_UNUSED_ENTRIES, NumberArrayQueryField, ParseHttpErrorCodeToMessageDePipe, ParseHttpErrorCodeToMessageEnPipe, ParseHttpErrorCodeToTitleDePipe, ParseHttpErrorCodeToTitleEnPipe, QUERY_CLIENT_DEVTOOLS_TOKEN, QUERY_DEVTOOLS_FAULT_STATUSES, QUERY_DEVTOOLS_TOKEN_TTL_LIMIT, QUERY_PERSISTENCE_STORE_VERSION, QUERY_SYNC_PROTOCOL_VERSION, QUERY_VERSION, QueryClientFeatureType, QueryDevtoolsComponent, QueryDirective, QueryFeatureType, QueryField, QueryForm, QueryRuntimeErrorCode, QueryShortNamePipe, QueryStore, SERVER_ERROR_KIND, SERVER_VIOLATION_ERROR_KIND, SPEED_BUFFER_TIME_IN_MS, SearchQueryField, SortQueryField, StringArrayQueryField, V2BearerAuthProvider, V2Query, V2QueryClient, V2QueryCreator, addQueryContainerHandling, applyQueryDevtoolsOverrides, applyQueryDevtoolsTokenTtl, applyQueryFeatures, armAllQueryDevtoolsMocks, armQueryDevtoolsMock, armQueryDevtoolsOverrideTransfer, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, booleanArrayQueryField, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, canOverrideQueryDevtoolsTokenTtl, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, clearQueryDevtoolsArmedMocks, clearQueryDevtoolsFaults, clearQueryDevtoolsMockStore, clearQueryDevtoolsOverrideStore, clearQueryDevtoolsStore, clearQueryDevtoolsTokenTtl, clearQueryDevtoolsTombstones, clearRestoredQueryDevtoolsOverrides, collectLeafPaths, collectQueryDevtoolsSchemaComponents, collectQueryFormLinks, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, consumeSuppressQueryStackDevtools, contentfulGqlLikePaginationAdapter, countUnresolvedQueryDevtoolsOverrides, createAuthGuard, createBaseQuery, createBaseQueryCreator, createBearerAuthProvider, createDefaultRetryFn, createDeleteQuery, createExecuteFn, createGetQuery, createGqlExecuteFn, createGqlMutationViaGet, createGqlMutationViaPost, createGqlQuery, createGqlQueryCreator, createGqlQueryViaGet, createGqlQueryViaPost, createHttpRequest, createIndexedDbQueryPersistenceAdapter, createInfinityQueryConfig, createLegacyQueryCreator, createNoopQueryPersistenceAdapter, createPagedQueryStack, createPatchQuery, createPersistentAuthFeature, createPostQuery, createPutQuery, createQuery, createQueryBatch, createQueryClient, createQueryCollection, createQueryCollectionSignal, createQueryCollectionSubject, createQueryContext, createQueryCreator, createQueryDevtoolsFormLinks, createQueryDevtoolsFormLinksRecorder, createQueryDevtoolsOverrides, createQueryDevtoolsOverridesRecorder, createQueryDevtoolsStats, createQueryDevtoolsStatsRecorder, createQueryErrorResponse, createQueryFeature, createQueryInvalidationFilter, createQueryKeyLockManager, createQueryObject, createQueryPersistenceEngine, createQueryRepository, createQuerySnapshotFn, createQueryStack, createQuerySubmission, createQuerySyncEngine, createQuerySyncTransport, createSecureDeleteQuery, createSecureExecuteFactory, createSecureExecuteFn, createSecureGetQuery, createSecureGqlExecuteFn, createSecureGqlMutationViaGet, createSecureGqlMutationViaPost, createSecureGqlQuery, createSecureGqlQueryCreator, createSecureGqlQueryViaGet, createSecureGqlQueryViaPost, createSecurePatchQuery, createSecurePostQuery, createSecurePutQuery, createSecureQuery, createSecureQueryCreator, createTrackingFeature, createWebSocketClient, currentQueryDevtoolsBatch, dateArrayQueryField, dateQueryField, decryptBearer, deepFreeze, def, defineQueryForm, deleteQueryDevtoolsMock, describeQueryDevtoolsFeatures, detectContentTypeHeader, detectPaginationShape, dynLikePaginationAdapter, effectComputed, emptyQueryArgs, ethletePaginationAdapter, executeUntilSettled, extractExpiresInSeconds, extractFormViolations, extractHtmlErrorMessage, extractQuery, fakePaginationAdapter, filterFailure, filterNull, filterQueryStates, filterSuccess, forEachHeader, formatQueryDevtoolsDuration, generateQueryDevtoolsNumberPreset, generateQueryDevtoolsSampleNumber, generateQueryDevtoolsStringPreset, getBearerAuthProviderName, getDefaultHeaders, getQueryClientName, getQueryFeatureUsage, getResponseUrl, ggLikePaginationAdapter, gql, gqlDataPropertyMissingInResponse, hasHeader, hasQueryDevtoolsOverridesAtPath, htmlErrorPayload, htmlQueryErrorParser, ignoreAutoRefresh, initQueryDevtoolsFaults, initQueryDevtoolsMocks, initQueryDevtoolsOverridePersistence, initQueryDevtoolsSettings, injectInfinityQueryResponseDelay, injectQueryContext, insertFrom, invalidBaseRouteError, invalidBodyError, invalidRouteError, invalidStateInsideSecureExecuteFactory, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isClassValidatorError, isCreateGqlQueryOptions, isCustomHeaderAuthProvider, isDateShapedLeaf, isEmptyString, isGqlQueryConfig, isHtmlErrorPayload, isLegacyQuery, isNaN$1 as isNaN, isPageOutOfRangeError, isQuery, isQueryCollection, isQueryDevtoolsEnabled, isQueryDevtoolsFaultArmed, isQueryDevtoolsRequestInterceptionEnabled, isQueryErrorResponse, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyFormViolationListError, isSymfonyListError, isSymfonyPagerfantaOutOfRangeError, isUnderInvalidatedUrl, legacyPrepareFallbackInjector, legacyPrepareWithoutInjectionContext, loadQueryDevtoolsSchema, mapToPaginated, mapViolationsToFormErrors, matchesQueryDevtoolsMockPattern, matchesQueryDevtoolsMockQuery, maybeExecute, measureQueryDevtoolsPayload, mergeHeaders, nestedEffect, noteQueryFormRead, numberArrayQueryField, pagedQueryStackNextPageCalledWithoutPreviousPage, pagedQueryStackPageBiggerThanTotalPages, pagedQueryStackPreviousPageCalledButAlreadyAtFirstPage, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, parseHttpErrorCodeToMessageDe, parseHttpErrorCodeToMessageEn, parseHttpErrorCodeToTitleDe, parseHttpErrorCodeToTitleEn, parseQueryDevtoolsOverrideTransfer, parseQueryRoute, patchQueryDevtoolsTokenPayload, pathParamsMissingInRouteFunctionError, provideInfinityQueryResponseDelay, provideLegacyPrepareFallback, provideQueryClientForDevtools, provideQueryDevtools, queryArrayComputed, queryBatchAlreadyRunning, queryBatchWithArgsUsed, queryClientFeatureUsedMultipleTimes, queryComputed, queryComputedTillTruthy, queryDevtoolsAbout, queryDevtoolsArmedMocks, queryDevtoolsArmedMocksRestored, queryDevtoolsEntries, queryDevtoolsFaults, queryDevtoolsFaultsRestored, queryDevtoolsFnDetail, queryDevtoolsMockId, queryDevtoolsMocks, queryDevtoolsOverridePersistence, queryDevtoolsRequestPath, queryDevtoolsResponseHistory, queryDevtoolsRestoredOverridesScope, queryDevtoolsSchemaNames, queryDevtoolsSchemaRoutes, queryDevtoolsSchemaState, queryDevtoolsSettings, queryDevtoolsStorage, queryDevtoolsTokenTtls, queryErrorMessage, queryErrorMessages, queryExecute, queryFeatureUsedMultipleTimes, queryField, querySequence, querySequenceAlreadyRunning, queryStackTotalQueriesAndExpectedQueriesMismatch, queryStackWithArgsUsed, queryStackWithResponseUpdateUsed, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, queryStateErrorSignal, queryStateLoadingSignal, queryStateResponseSignal, queryStateSignal, readQueryDevtoolsStore, registerEthleteVersion, registerQueryDevtoolsEntry, registerQueryErrorParser, removeFrom, request, resetExecuteState, resetPageOnError, resolveInvalidationUrl, resolveQueryDevtoolsFault, resolveQueryDevtoolsFaultForAttempt, resolveQueryDevtoolsMock, resolveQueryDevtoolsMockForAttempt, restoredQueryDevtoolsOverrides, runDefaultQueryRetry, runInQueryDevtoolsBatch, runQueryErrorParsers, saveQueryDevtoolsMock, searchQueryField, seedQueryDevtoolsSchemaBody, seedQueryDevtoolsSchemaRoute, serializeBody, serializeQueryDevtoolsOverrideTransfer, setDefaultQueryRetryFn, setQueryDevtoolsAppInfo, setQueryDevtoolsArmedMocksScope, setQueryDevtoolsFault, setQueryDevtoolsFaultResolver, setQueryDevtoolsFaultsScope, setQueryDevtoolsFormLinksFactory, setQueryDevtoolsMockResolver, setQueryDevtoolsOverridePersistence, setQueryDevtoolsOverridesFactory, setQueryDevtoolsOverridesScope, setQueryDevtoolsRegistrar, setQueryDevtoolsResponseHistory, setQueryDevtoolsSchemaLoader, setQueryDevtoolsSettings, setQueryDevtoolsStatsFactory, setQueryDevtoolsTokenPayloadPatcher, setQueryDevtoolsTokenTtl, setupQueryDependencies, setupQueryExecuteState, setupQueryState, shouldAutoExecuteGqlQuery, shouldAutoExecuteQuery, shouldCacheQuery, shouldRetryRequest, silenceMissingWithArgsFeatureErrorUsedButWithArgsPresent, skipPaginationPageParamCalculator, smartDuplicateArrayItem, snapshotQueryDevtoolsHandle, sortQueryField, splitQueryConfig, stringArrayQueryField, stringifyQueryRouteParts, sumQueryDevtoolsStats, suppressNextQueryStackDevtools, switchQueryCollectionState, switchQueryState, symfonyQueryErrorParser, takeUntilResponse, toQuerySignal, toQuerySubject, tokensNotAvailableInsideAuthAndExec, tombstoneOf, transformArrayResponse, transformExecStateToQueryState, transformGql, transformMethod, transformPaginatedResponse, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray, uncacheableRequestHasAllowCacheParam, uncacheableRequestHasCacheKeyParam, unwrapQuerySyncMessage, v2BuildQueryCacheKey, v2ExtractExpiresInSeconds, v2ShouldCacheQuery, v2ShouldRetryRequest, validateWithQuery, validateWithV2Query, withArgs, withArgsQueryFeatureMissingButRouteIsFunction, withAuthenticationQuery, withAutoRefresh, withAutoRefreshUsedInManualQuery, withAutoRefreshUsedOnUnsupportedHttpMethod, withBearerAuthMultiTabSync, withDefaultRetry, withErrorHandling, withEthleteApiErrors, withHtmlErrorParsing, withInactivityLogout, withLogging, withLongPolling, withLongPollingUsedOnUnsupportedHttpMethod, withLongPollingUsedWithPolling, withMultiTabSync, withPageResetOnError, withPersistentAuth, withPolling, withPollingUsedOnUnsupportedHttpMethod, withQueryDevtoolsOverridePersistence, withQueryPersistence, withRefreshQuery, withResponseUpdate, withSuccessHandling, withSymfonyErrors, withTokenExpirationWarning, withTokenRevocation, withTracking, wrapAsObservableSignal, wrapQuerySyncMessage, writeQueryDevtoolsStore };
14200
14641
  //# sourceMappingURL=ethlete-query.mjs.map