@ethlete/query 6.0.0-next.41 → 6.0.0-next.42

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,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Injector, effect, DestroyRef, InjectionToken, EnvironmentInjector, ElementRef, ErrorHandler, createEnvironmentInjector, untracked, signal, linkedSignal, computed, runInInjectionContext, isDevMode, PLATFORM_ID, resource, DOCUMENT, VERSION, makeEnvironmentProviders, assertInInjectionContext, provideEnvironmentInitializer, ChangeDetectorRef, ViewContainerRef, TemplateRef, Input, Directive, input, Pipe, ViewEncapsulation, Component, NgZone } from '@angular/core';
2
+ import { inject, Injector, effect, DestroyRef, InjectionToken, EnvironmentInjector, ElementRef, ErrorHandler, createEnvironmentInjector, untracked, signal, linkedSignal, computed, runInInjectionContext, isDevMode, PLATFORM_ID, resource, DOCUMENT, VERSION, makeEnvironmentProviders, provideEnvironmentInitializer, ApplicationRef, assertInInjectionContext, ChangeDetectorRef, ViewContainerRef, TemplateRef, Input, Directive, input, Pipe, ViewEncapsulation, Component, NgZone } from '@angular/core';
3
3
  import { UrlTree, Router, RedirectCommand, ActivatedRoute } from '@angular/router';
4
4
  import { Observable, defer, from, filter, Subject, Subscription, throwError, of, timer, switchMap, tap, retry, catchError, EMPTY as EMPTY$1, take, takeUntil, finalize, mergeMap, toArray, map, merge, takeWhile, firstValueFrom, race, concatMap, fromEvent, throttleTime, interval, startWith, pairwise, BehaviorSubject, combineLatest, ReplaySubject, shareReplay, skip, withLatestFrom, debounceTime } from 'rxjs';
5
5
  import { defineStaticProvider, RuntimeError, clamp, randomId, defineRootProvider, isObject, injectUnsavedChangesCoordinator, injectRoute, getCookie, deleteCookie, setCookie, CORE_VERSION, createDestroy, computedTillTruthy, defineProvider, toProvideFn, toInjectFn, nextFrame, injectQueryParams, injectQueryParamChanges, clone, equal, ET_PROPERTY_REMOVED, previousSignalValue } from '@ethlete/core';
@@ -7098,20 +7098,71 @@ const queryDevtoolsAbout = () => ({
7098
7098
  app,
7099
7099
  });
7100
7100
 
7101
+ /**
7102
+ * Whether a devtools UI is on the page, which is what the floating pills follow. Kept apart from the
7103
+ * pills themselves so `@ethlete/query-devtools/toggle` can declare itself without pulling the pill
7104
+ * renderer into the bundle an application ships.
7105
+ */
7106
+ let mounted = 0;
7107
+ let settled = false;
7108
+ let notify = null;
7109
+ /**
7110
+ * Declares a devtools UI on the page, and takes the declaration back when it goes. The floating pills
7111
+ * paint only while one is mounted, so an application that renders no devtools trigger shows no pills
7112
+ * either.
7113
+ *
7114
+ * Part of the devtools contract. **Not part of the general public contract.**
7115
+ */
7116
+ const setQueryDevtoolsUiMounted = (isMounted) => {
7117
+ mounted = Math.max(0, mounted + (isMounted ? 1 : -1));
7118
+ notify?.();
7119
+ };
7120
+ /**
7121
+ * Says the application has rendered and settled, which is what lets the pills stop painting where no
7122
+ * devtools UI is mounted. Called by `provideQueryDevtools()`.
7123
+ * @internal
7124
+ */
7125
+ const markQueryDevtoolsAppSettled = () => {
7126
+ settled = true;
7127
+ notify?.();
7128
+ };
7129
+ /**
7130
+ * Whether the pills may paint. Until the application settles they do whatever the UI does: a boot that
7131
+ * hangs on the backend it was just pointed at renders no component at all, and is the case they exist
7132
+ * for.
7133
+ * @internal
7134
+ */
7135
+ const queryDevtoolsPillsAllowed = () => mounted > 0 || !settled;
7136
+ /** Hands the pills a way to repaint on a change here. Called by the pill renderer. @internal */
7137
+ const onQueryDevtoolsUiChange = (listener) => {
7138
+ notify = listener;
7139
+ };
7140
+
7101
7141
  const HOST_ID = 'et-query-devtools-pill';
7102
7142
  /** What the picker writes for "let the application decide", which is the key removed. */
7103
7143
  const DEFAULT_VALUE = '';
7104
7144
  /** Prefixes a production env's name, so the open dropdown says which option is the real backend. */
7105
7145
  const PRODUCTION_MARK = '⚠ ';
7146
+ /** Holds `1` while the pills are folded into the summary chip. Unwritten reads as folded. */
7147
+ const COLLAPSED_KEY = 'et-query-devtools-pills-collapsed';
7106
7148
  const STYLE = `
7107
7149
  :host {
7150
+ --_accent: var(--et-theme-color-primary-solid, #60a5fa);
7151
+ --_surface: linear-gradient(135deg, #1f1f23, #2a2a30);
7152
+ --_ring: inset 0 0 0 1px rgb(255 255 255 / 0.08);
7153
+ --_lift: 0 6px 20px rgb(0 0 0 / 0.35);
7154
+ --_control: 24px;
7155
+
7108
7156
  position: fixed;
7109
7157
  display: flex;
7110
7158
  flex-direction: column;
7111
- align-items: flex-end;
7112
- gap: 8px;
7159
+ /* Stretch, not flex-end: it hands every pill the widest pill's width, so the stack keeps one left
7160
+ edge as well as one right edge. */
7161
+ align-items: stretch;
7162
+ gap: 6px 8px;
7113
7163
  inset-block-end: 64px;
7114
7164
  inset-inline-end: 16px;
7165
+ max-inline-size: min(420px, calc(100vw - 32px));
7115
7166
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
7116
7167
  font-size: 13px;
7117
7168
  /* One below the panel and the toggle button (2147483010), so an open panel covers the pill - the
@@ -7119,47 +7170,97 @@ const STYLE = `
7119
7170
  z-index: 2147483009;
7120
7171
  }
7121
7172
 
7122
- label {
7123
- --_accent: var(--et-theme-color-primary-solid, #60a5fa);
7124
-
7125
- display: inline-flex;
7173
+ .pill {
7174
+ display: flex;
7126
7175
  align-items: center;
7127
7176
  gap: 8px;
7128
- padding: 8px 10px 8px 12px;
7177
+ box-sizing: border-box;
7178
+ block-size: 34px;
7179
+ padding-inline: 12px 5px;
7129
7180
  border-radius: 999px;
7130
- background: linear-gradient(135deg, #1f1f23, #2a2a30);
7181
+ background: var(--_surface);
7131
7182
  color: #fafafa;
7132
7183
  box-shadow:
7133
- 0 6px 20px rgb(0 0 0 / 0.35),
7134
- inset 0 0 0 1px rgb(255 255 255 / 0.08);
7184
+ var(--_lift),
7185
+ var(--_ring);
7186
+ }
7187
+
7188
+ .lead {
7189
+ display: inline-flex;
7190
+ flex: none;
7191
+ align-items: center;
7192
+ gap: 6px;
7193
+ overflow: hidden;
7135
7194
  }
7136
7195
 
7137
7196
  .name {
7138
- color: #a1a1aa;
7139
- font-size: 11px;
7197
+ color: #8f8f98;
7198
+ font-size: 10px;
7140
7199
  font-weight: 600;
7141
- letter-spacing: 0.04em;
7200
+ letter-spacing: 0.08em;
7142
7201
  line-height: 1;
7143
7202
  text-transform: uppercase;
7203
+ white-space: nowrap;
7144
7204
  }
7145
7205
 
7146
7206
  select {
7147
- max-inline-size: 220px;
7148
- padding: 3px 6px;
7207
+ flex: 1;
7208
+ min-inline-size: 0;
7209
+ box-sizing: border-box;
7210
+ block-size: var(--_control);
7211
+ padding-inline: 8px 24px;
7149
7212
  border: none;
7150
- border-radius: 5px;
7151
- background: rgb(255 255 255 / 0.07);
7213
+ border-radius: 7px;
7214
+ appearance: none;
7215
+ background-color: rgb(255 255 255 / 0.07);
7216
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23a1a1aa' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
7217
+ background-repeat: no-repeat;
7218
+ background-position: right 8px center;
7219
+ background-size: 9px 6px;
7152
7220
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.12);
7153
7221
  color: #fafafa;
7154
7222
  font: inherit;
7155
7223
  font-size: 12px;
7224
+ line-height: var(--_control);
7225
+ text-overflow: ellipsis;
7226
+ cursor: pointer;
7227
+ }
7228
+
7229
+ .pill button {
7230
+ flex: none;
7231
+ box-sizing: border-box;
7232
+ block-size: var(--_control);
7233
+ padding-inline: 9px;
7234
+ border: none;
7235
+ border-radius: 7px;
7236
+ background: rgb(255 255 255 / 0.07);
7237
+ box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.12);
7238
+ color: #d4d4d8;
7239
+ font: inherit;
7240
+ font-size: 11px;
7156
7241
  font-weight: 600;
7157
7242
  line-height: 1;
7158
7243
  cursor: pointer;
7159
7244
  }
7160
7245
 
7161
- select:hover {
7246
+ select:hover,
7247
+ .pill button:hover {
7248
+ background-color: rgb(255 255 255 / 0.13);
7249
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--_accent) 60%, transparent);
7250
+ color: #fafafa;
7251
+ }
7252
+
7253
+ select:focus-visible,
7254
+ .pill button:focus-visible,
7255
+ .chip:focus-visible {
7256
+ outline: 2px solid var(--_accent);
7257
+ outline-offset: 2px;
7258
+ }
7259
+
7260
+ .pill button[data-on] {
7261
+ background: color-mix(in srgb, var(--_accent) 20%, transparent);
7162
7262
  box-shadow: inset 0 0 0 1px var(--_accent);
7263
+ color: #fafafa;
7163
7264
  }
7164
7265
 
7165
7266
  /* The popup is painted by the browser, which does not inherit the pill's dark background. */
@@ -7168,7 +7269,7 @@ const STYLE = `
7168
7269
  color: #fafafa;
7169
7270
  }
7170
7271
 
7171
- label[data-production] {
7272
+ .pill[data-production] {
7172
7273
  background: linear-gradient(135deg, #7f1d1d, #b91c1c);
7173
7274
  color: #fff;
7174
7275
  box-shadow:
@@ -7176,50 +7277,119 @@ const STYLE = `
7176
7277
  inset 0 0 0 1px rgb(254 202 202 / 0.7);
7177
7278
  }
7178
7279
 
7179
- label[data-production] .name {
7280
+ .pill[data-production] .name {
7180
7281
  color: #fee2e2;
7181
7282
  }
7182
7283
 
7183
- label[data-production] .mark {
7184
- font-size: 15px;
7284
+ .pill[data-production] .mark {
7285
+ flex: none;
7286
+ font-size: 14px;
7185
7287
  line-height: 1;
7186
7288
  }
7187
7289
 
7188
- label[data-production] select {
7189
- background: rgb(0 0 0 / 0.35);
7290
+ .pill[data-production] select {
7291
+ background-color: rgb(0 0 0 / 0.35);
7292
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23fecaca' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
7190
7293
  box-shadow: inset 0 0 0 1px rgb(254 202 202 / 0.6);
7191
7294
  text-transform: uppercase;
7192
7295
  }
7193
7296
 
7194
- label[data-production] option {
7195
- background: #450a0a;
7297
+ .pill[data-production] select:hover {
7298
+ background-color: rgb(0 0 0 / 0.5);
7299
+ box-shadow: inset 0 0 0 1px #fecaca;
7196
7300
  }
7197
7301
 
7198
- label[data-auth] {
7199
- --_accent: var(--et-theme-color-success-solid, #34d399);
7302
+ .pill[data-production] option {
7303
+ background: #450a0a;
7200
7304
  }
7201
7305
 
7202
- button {
7203
- padding: 3px 7px;
7306
+ .chip {
7307
+ display: inline-flex;
7308
+ align-items: center;
7309
+ align-self: flex-end;
7310
+ gap: 8px;
7311
+ box-sizing: border-box;
7312
+ block-size: 28px;
7313
+ max-inline-size: 100%;
7314
+ padding-inline: 11px 12px;
7204
7315
  border: none;
7205
- border-radius: 5px;
7206
- background: rgb(255 255 255 / 0.07);
7207
- box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.12);
7316
+ border-radius: 999px;
7317
+ background: var(--_surface);
7318
+ box-shadow:
7319
+ var(--_lift),
7320
+ var(--_ring);
7208
7321
  color: #fafafa;
7209
7322
  font: inherit;
7210
- font-size: 11px;
7323
+ font-size: 12px;
7211
7324
  font-weight: 600;
7212
- line-height: 1.4;
7325
+ line-height: 1;
7213
7326
  cursor: pointer;
7214
7327
  }
7215
7328
 
7216
- button:hover {
7217
- box-shadow: inset 0 0 0 1px var(--_accent);
7329
+ .chip:hover {
7330
+ box-shadow:
7331
+ var(--_lift),
7332
+ inset 0 0 0 1px var(--_accent);
7333
+ }
7334
+
7335
+ .caret {
7336
+ flex: none;
7337
+ color: var(--_accent);
7338
+ font-size: 8px;
7339
+ line-height: 1;
7340
+ transition: transform 0.15s ease;
7341
+ }
7342
+
7343
+ .values {
7344
+ overflow: hidden;
7345
+ min-inline-size: 0;
7346
+ color: #d4d4d8;
7347
+ text-overflow: ellipsis;
7348
+ white-space: nowrap;
7349
+ }
7350
+
7351
+ .fold {
7352
+ color: #8f8f98;
7353
+ font-size: 11px;
7354
+ letter-spacing: 0.04em;
7355
+ }
7356
+
7357
+ :host([data-collapsed]) .pill,
7358
+ :host([data-collapsed]) .fold {
7359
+ display: none;
7360
+ }
7361
+
7362
+ :host(:not([data-collapsed])) .caret {
7363
+ transform: rotate(180deg);
7364
+ }
7365
+
7366
+ :host(:not([data-collapsed])) .values {
7367
+ display: none;
7218
7368
  }
7219
7369
 
7220
- button[data-on] {
7221
- background: rgb(52 211 153 / 0.18);
7222
- box-shadow: inset 0 0 0 1px rgb(52 211 153 / 0.7);
7370
+ /* Subgrid, where it exists: one set of columns for the whole stack, so every picker starts and ends
7371
+ on the same edge whatever its provider is called. The flex rules above are the fallback. */
7372
+ @supports (grid-template-columns: subgrid) {
7373
+ :host {
7374
+ display: grid;
7375
+ grid-template-columns: auto minmax(0, 1fr) auto;
7376
+ }
7377
+
7378
+ .pill {
7379
+ display: grid;
7380
+ grid-column: 1 / -1;
7381
+ grid-template-columns: subgrid;
7382
+ }
7383
+
7384
+ /* Nothing follows the picker on an env pill, so it takes the session pill's button column too. */
7385
+ .pill:not([data-auth]) select {
7386
+ grid-column: 2 / -1;
7387
+ }
7388
+
7389
+ .chip {
7390
+ grid-column: 1 / -1;
7391
+ justify-self: end;
7392
+ }
7223
7393
  }
7224
7394
 
7225
7395
  /* The whole viewport, so the warning is on screen wherever the reader is looking. Outside the pill's
@@ -7235,7 +7405,7 @@ const STYLE = `
7235
7405
  }
7236
7406
 
7237
7407
  @media (prefers-reduced-motion: no-preference) {
7238
- label[data-production] {
7408
+ .pill[data-production] {
7239
7409
  animation: et-qd-api-env-pulse 1.6s ease-in-out infinite;
7240
7410
  }
7241
7411
 
@@ -7273,6 +7443,28 @@ const STYLE = `
7273
7443
  /** The env a stored value lands on, which is the switch's own fallback while nothing is stored. */
7274
7444
  const resolvedEnvOf = (apiSwitch, stored) => apiSwitch.envs.find((env) => env.id === (stored || apiSwitch.fallback));
7275
7445
  const nameOf = (env) => `${env.production ? PRODUCTION_MARK : ''}${env.label ?? env.id}`;
7446
+ /** The one value a folded switch reads as: the env behind the pick, or a typed URL. */
7447
+ const summaryOfSwitch = (apiSwitch, stored) => {
7448
+ const env = resolvedEnvOf(apiSwitch, stored);
7449
+ return env ? nameOf(env) : stored || apiSwitch.name;
7450
+ };
7451
+ const summaryOfAuthRow = (row) => (row.tabLocal ? `${row.current} · own tab` : row.current);
7452
+ const readCollapsed = () => {
7453
+ try {
7454
+ return window.localStorage.getItem(COLLAPSED_KEY) !== '0';
7455
+ }
7456
+ catch {
7457
+ return true;
7458
+ }
7459
+ };
7460
+ const writeCollapsed = (collapsed) => {
7461
+ try {
7462
+ window.localStorage.setItem(COLLAPSED_KEY, collapsed ? '1' : '0');
7463
+ }
7464
+ catch {
7465
+ // ignore (private mode / disabled storage / quota)
7466
+ }
7467
+ };
7276
7468
  const optionsOf = (apiSwitch, stored) => {
7277
7469
  const fallback = apiSwitch.envs.find((env) => env.id === apiSwitch.fallback);
7278
7470
  const options = [
@@ -7293,21 +7485,27 @@ const optionsOf = (apiSwitch, stored) => {
7293
7485
  };
7294
7486
  const buildSwitch = (doc, apiSwitch, stored, pick) => {
7295
7487
  const production = resolvedEnvOf(apiSwitch, stored)?.production === true;
7296
- const label = doc.createElement('label');
7297
- label.title = production
7488
+ // A div, not a label: a label forwards its own hover to the control it names, so a pointer over the
7489
+ // pill's trailing button would light the picker up as well.
7490
+ const pill = doc.createElement('div');
7491
+ pill.className = 'pill';
7492
+ pill.title = production
7298
7493
  ? `${apiSwitch.name} points at production. The data is real. Picking reloads the page.`
7299
7494
  : `${apiSwitch.name} — picking reloads the page`;
7495
+ const lead = doc.createElement('span');
7496
+ lead.className = 'lead';
7300
7497
  if (production) {
7301
- label.setAttribute('data-production', '');
7498
+ pill.setAttribute('data-production', '');
7302
7499
  const mark = doc.createElement('span');
7303
7500
  mark.className = 'mark';
7304
7501
  mark.textContent = '⚠';
7305
7502
  mark.setAttribute('aria-hidden', 'true');
7306
- label.append(mark);
7503
+ lead.append(mark);
7307
7504
  }
7308
7505
  const name = doc.createElement('span');
7309
7506
  name.className = 'name';
7310
7507
  name.textContent = production ? `${apiSwitch.name} · live` : apiSwitch.name;
7508
+ lead.append(name);
7311
7509
  const select = doc.createElement('select');
7312
7510
  select.setAttribute('aria-label', apiSwitch.name);
7313
7511
  for (const option of optionsOf(apiSwitch, stored)) {
@@ -7319,27 +7517,35 @@ const buildSwitch = (doc, apiSwitch, stored, pick) => {
7319
7517
  select.append(element);
7320
7518
  }
7321
7519
  select.addEventListener('change', () => pick(apiSwitch.storageKey, select.value === DEFAULT_VALUE ? null : select.value));
7322
- label.append(name, select);
7323
- return label;
7520
+ pill.append(lead, select);
7521
+ return pill;
7324
7522
  };
7325
7523
  let envState = null;
7326
7524
  let authState = null;
7327
7525
  const buildAuthRow = (doc, row) => {
7328
- const label = doc.createElement('label');
7329
- label.setAttribute('data-auth', '');
7330
- label.title = row.tabLocal
7526
+ const pill = doc.createElement('div');
7527
+ pill.className = 'pill';
7528
+ pill.setAttribute('data-auth', '');
7529
+ pill.title = row.tabLocal
7331
7530
  ? `${row.name} holds this tab's own session. The other tabs are on theirs.`
7332
7531
  : `${row.name} - the session every tab of this app shares`;
7532
+ const lead = doc.createElement('span');
7533
+ lead.className = 'lead';
7333
7534
  const name = doc.createElement('span');
7334
7535
  name.className = 'name';
7335
7536
  name.textContent = row.tabLocal ? `${row.name} · this tab` : row.name;
7537
+ lead.append(name);
7336
7538
  const select = doc.createElement('select');
7337
7539
  select.setAttribute('aria-label', `${row.name} session`);
7338
- const current = doc.createElement('option');
7339
- current.value = '';
7340
- current.textContent = row.current;
7341
- current.selected = !row.options.some((option) => option.selected);
7342
- select.append(current);
7540
+ // Only where the live tokens belong to no stored session: with one selected below, this would read as
7541
+ // a second session of the same name.
7542
+ if (!row.options.some((option) => option.selected)) {
7543
+ const current = doc.createElement('option');
7544
+ current.value = '';
7545
+ current.textContent = row.current;
7546
+ current.selected = true;
7547
+ select.append(current);
7548
+ }
7343
7549
  for (const option of row.options) {
7344
7550
  const element = doc.createElement('option');
7345
7551
  element.value = option.value;
@@ -7362,8 +7568,30 @@ const buildAuthRow = (doc, row) => {
7362
7568
  if (row.tabLocal)
7363
7569
  isolate.setAttribute('data-on', '');
7364
7570
  isolate.addEventListener('click', row.toggleTabLocal);
7365
- label.append(name, select, isolate);
7366
- return label;
7571
+ pill.append(lead, select, isolate);
7572
+ return pill;
7573
+ };
7574
+ const buildChip = (doc, values, collapsed, toggle) => {
7575
+ const chip = doc.createElement('button');
7576
+ chip.type = 'button';
7577
+ chip.className = 'chip';
7578
+ chip.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
7579
+ chip.title = collapsed ? 'Show the devtools switches' : 'Hide the devtools switches';
7580
+ // The visible text says which state the pills are in, not what the click does - hence a name of its own.
7581
+ chip.setAttribute('aria-label', chip.title);
7582
+ const caret = doc.createElement('span');
7583
+ caret.className = 'caret';
7584
+ caret.textContent = '▲';
7585
+ caret.setAttribute('aria-hidden', 'true');
7586
+ const text = doc.createElement('span');
7587
+ text.className = 'values';
7588
+ text.textContent = values.join(' · ');
7589
+ const fold = doc.createElement('span');
7590
+ fold.className = 'fold';
7591
+ fold.textContent = 'hide';
7592
+ chip.append(caret, text, fold);
7593
+ chip.addEventListener('click', toggle);
7594
+ return chip;
7367
7595
  };
7368
7596
  const render = (doc) => {
7369
7597
  doc.getElementById(HOST_ID)?.remove();
@@ -7371,6 +7599,8 @@ const render = (doc) => {
7371
7599
  const rows = authState?.rows ?? [];
7372
7600
  if (!switches.length && !rows.length)
7373
7601
  return;
7602
+ if (!queryDevtoolsPillsAllowed())
7603
+ return;
7374
7604
  const host = doc.createElement('div');
7375
7605
  host.id = HOST_ID;
7376
7606
  // Shadow DOM is intentional, for the same reason the toggle button uses it: this paints over the
@@ -7379,13 +7609,16 @@ const render = (doc) => {
7379
7609
  const style = doc.createElement('style');
7380
7610
  style.textContent = STYLE;
7381
7611
  shadow.append(style);
7382
- let production = false;
7612
+ const storedOf = (apiSwitch) => envState?.read(apiSwitch.storageKey) ?? DEFAULT_VALUE;
7613
+ const production = switches.some((apiSwitch) => resolvedEnvOf(apiSwitch, storedOf(apiSwitch))?.production === true);
7614
+ // A production pick unfolds the pills whatever is stored: the warning is the point of the pill.
7615
+ const collapsed = !production && readCollapsed();
7616
+ if (collapsed)
7617
+ host.setAttribute('data-collapsed', '');
7383
7618
  for (const row of rows)
7384
7619
  shadow.append(buildAuthRow(doc, row));
7385
7620
  for (const apiSwitch of switches) {
7386
- const stored = envState?.read(apiSwitch.storageKey) ?? DEFAULT_VALUE;
7387
- production ||= resolvedEnvOf(apiSwitch, stored)?.production === true;
7388
- shadow.append(buildSwitch(doc, apiSwitch, stored, (storageKey, value) => envState?.pick(storageKey, value)));
7621
+ shadow.append(buildSwitch(doc, apiSwitch, storedOf(apiSwitch), (storageKey, value) => envState?.pick(storageKey, value)));
7389
7622
  }
7390
7623
  if (production) {
7391
7624
  const frame = doc.createElement('div');
@@ -7393,6 +7626,16 @@ const render = (doc) => {
7393
7626
  frame.setAttribute('aria-hidden', 'true');
7394
7627
  shadow.append(frame);
7395
7628
  }
7629
+ else {
7630
+ const values = [
7631
+ ...rows.map(summaryOfAuthRow),
7632
+ ...switches.map((apiSwitch) => summaryOfSwitch(apiSwitch, storedOf(apiSwitch))),
7633
+ ];
7634
+ shadow.append(buildChip(doc, values, collapsed, () => {
7635
+ writeCollapsed(!collapsed);
7636
+ render(doc);
7637
+ }));
7638
+ }
7396
7639
  doc.body.append(host);
7397
7640
  };
7398
7641
  /**
@@ -7405,6 +7648,9 @@ const render = (doc) => {
7405
7648
  * part of this is on the page before `bootstrapApplication` starts.
7406
7649
  */
7407
7650
  const renderPills = () => {
7651
+ // Registered here rather than at module scope: a module-scope call would make this module
7652
+ // unshakeable, and cost every application that never renders a pill the whole renderer.
7653
+ onQueryDevtoolsUiChange(renderPills);
7408
7654
  const doc = globalThis.document;
7409
7655
  if (!doc)
7410
7656
  return;
@@ -7696,6 +7942,12 @@ const providers = /* @__PURE__ */ signal([], /* @ts-ignore */
7696
7942
  const tabLocal = /* @__PURE__ */ signal({}, /* @ts-ignore */
7697
7943
  ...(ngDevMode ? [{ debugName: "tabLocal" }] : /* istanbul ignore next */ []));
7698
7944
  const live = /* @__PURE__ */ new Map();
7945
+ /**
7946
+ * The account each provider's next captured token pair was logged in as, set by
7947
+ * `loginQueryDevtoolsAuthAccount` and consumed by the capture it causes. `previous` is the session that
7948
+ * was in force before, which the logout on the way out would otherwise take out of reach.
7949
+ */
7950
+ const pendingLogins = /* @__PURE__ */ new Map();
7699
7951
  let idCounter = 0;
7700
7952
  const nextId = (prefix) => `${prefix}-${Date.now().toString(36)}-${++idCounter}`;
7701
7953
  /**
@@ -7773,6 +8025,8 @@ const sanitizeSession = (value) => {
7773
8025
  accessToken: session.accessToken,
7774
8026
  refreshToken: session.refreshToken,
7775
8027
  subject: typeof session.subject === 'string' ? session.subject : null,
8028
+ identity: typeof session.identity === 'string' ? session.identity : null,
8029
+ account: typeof session.account === 'string' ? session.account : null,
7776
8030
  expiresAt: typeof session.expiresAt === 'number' ? session.expiresAt : null,
7777
8031
  savedAt: typeof session.savedAt === 'number' ? session.savedAt : 0,
7778
8032
  };
@@ -7860,6 +8114,21 @@ const trackQueryDevtoolsAuthProvider = (registration) => {
7860
8114
  syncPill();
7861
8115
  };
7862
8116
  };
8117
+ /**
8118
+ * Drops what the previous user left behind. Their responses are cached under keys the next user's
8119
+ * requests hit, and a bound secure query would go on rendering a body that was fetched for somebody else.
8120
+ *
8121
+ * Only ever once the new tokens are in force: `unbindAllSecure` re-arms every secure query that
8122
+ * auto-executes on the first access token it sees, so clearing before them re-runs all of them on the
8123
+ * token the previous user still holds - and caches that answer for the one arriving.
8124
+ */
8125
+ const clearClientData = (entry) => {
8126
+ const { repository } = entry.client;
8127
+ repository.unbindAllSecure();
8128
+ for (const cacheEntry of repository.subtle.cacheEntries())
8129
+ repository.subtle.evict(cacheEntry.key);
8130
+ void entry.client.clearPersistedQueries();
8131
+ };
7863
8132
  /**
7864
8133
  * Writes a live token pair into the vault. A pair whose subject is already stored updates that session
7865
8134
  * rather than adding another, which is what lets a plain login in the application fill the picker.
@@ -7872,23 +8141,46 @@ const remember = (options) => {
7872
8141
  const scope = scopeOf();
7873
8142
  const identity = identityOf(accessToken);
7874
8143
  const activeId = active()[provider] ?? null;
7875
- const activeSession = store().sessions.find((session) => session.id === activeId);
7876
- const bySubject = identity.subject
7877
- ? store().sessions.find((session) => session.provider === provider && session.scope === scope && session.subject === identity.subject)
8144
+ const account = pendingLogins.get(provider) ?? null;
8145
+ pendingLogins.delete(provider);
8146
+ const mine = store().sessions.filter((session) => session.provider === provider && session.scope === scope);
8147
+ // This pair is already on record: the tab it belongs to lost only the pointer, which a new tab always
8148
+ // does - the pointer is the tab's own. Without this a token that carries no `sub` grows a second entry
8149
+ // per tab, and a third, until the picker is a column of sessions all named the same.
8150
+ const byTokens = mine.find((session) => session.refreshToken === refreshToken || session.accessToken === accessToken);
8151
+ const byAccount = account ? mine.find((session) => session.account === account.id) : undefined;
8152
+ const bySubject = identity.subject ? mine.find((session) => session.subject === identity.subject) : undefined;
8153
+ // The name the token claims, for a backend that issues no `sub`. A session held for another account is
8154
+ // left alone: two accounts are two slots even where one person's name is on both.
8155
+ const byIdentity = identity.label
8156
+ ? mine.find((session) => session.identity === identity.label && (!account || !session.account || session.account === account.id))
7878
8157
  : undefined;
7879
- // The session on record is only a rotation of the live one while both name the same user. Logging in as
7880
- // somebody else without logging out first would otherwise overwrite the tokens of the user this tab is
7881
- // switching away from - which is the one pair the vault exists to keep.
7882
- const isRotation = !activeSession || !identity.subject || !activeSession.subject || activeSession.subject === identity.subject;
7883
- const target = isRotation ? (activeSession ?? bySubject) : bySubject;
8158
+ // An account login logs out on the way in, and a logout lets go of the pointer, so the session this tab
8159
+ // was on has to be carried in by the pending login instead.
8160
+ const candidate = mine.find((session) => session.id === (activeId ?? account?.previous ?? null));
8161
+ // Whoever the live tokens belong to, the candidate is a different user as soon as one claim says so.
8162
+ // Without this a login as somebody else would overwrite the tokens of the user this tab is leaving,
8163
+ // which is the one pair the vault exists to keep.
8164
+ const isOtherUser = !!candidate &&
8165
+ ((!!identity.subject && !!candidate.subject && candidate.subject !== identity.subject) ||
8166
+ (!!identity.label && !!candidate.identity && candidate.identity !== identity.label) ||
8167
+ (!!account && !!candidate.account && candidate.account !== account.id));
8168
+ // The last resort for a token that names nobody at all: the newest session nothing can tell it apart
8169
+ // from. An account login is left out - it is asking for a session of its own.
8170
+ const byNothing = identity.subject || identity.label || account
8171
+ ? undefined
8172
+ : mine.filter((session) => !session.subject && !session.account).sort((a, b) => b.savedAt - a.savedAt)[0];
8173
+ const target = byTokens ?? byAccount ?? bySubject ?? byIdentity ?? (isOtherUser ? undefined : candidate) ?? byNothing;
7884
8174
  const session = {
7885
8175
  id: target?.id ?? nextId('session'),
7886
8176
  provider,
7887
- label: target?.label ?? identity.label ?? 'session',
8177
+ label: target?.label ?? identity.label ?? account?.label ?? 'session',
7888
8178
  scope,
7889
8179
  accessToken,
7890
8180
  refreshToken,
7891
8181
  subject: identity.subject,
8182
+ identity: identity.label ?? target?.identity ?? null,
8183
+ account: target?.account ?? account?.id ?? null,
7892
8184
  expiresAt: identity.expiresAt,
7893
8185
  savedAt: Date.now(),
7894
8186
  };
@@ -7904,6 +8196,13 @@ const remember = (options) => {
7904
8196
  }
7905
8197
  persist();
7906
8198
  syncPill();
8199
+ // Another session than this tab was on. A rotation of the same one is not a change of user, and a
8200
+ // login that never landed leaves its pending entry behind for the next rotation to find.
8201
+ if (account && session.id !== account.previous) {
8202
+ const entry = live.get(provider);
8203
+ if (entry)
8204
+ clearClientData(entry);
8205
+ }
7907
8206
  };
7908
8207
  /** Lets go of the session a provider was on, without forgetting what the vault holds of it. */
7909
8208
  const forgetActive = (provider) => {
@@ -7963,7 +8262,7 @@ const queryDevtoolsAuthAccountsFor = (provider) => {
7963
8262
  provider,
7964
8263
  label: account.label,
7965
8264
  loginQuery: account.loginQuery,
7966
- fields: DEFAULT_FIELDS,
8265
+ fields: account.fields?.length ? account.fields : queryDevtoolsAuthFieldsFor(provider, account.loginQuery),
7967
8266
  declared: false,
7968
8267
  }));
7969
8268
  return [...fromApp, ...fromPanel];
@@ -7988,6 +8287,15 @@ const clearQueryDevtoolsAuthCredentials = (accountId) => {
7988
8287
  persist();
7989
8288
  syncPill();
7990
8289
  };
8290
+ /**
8291
+ * What a login needs on one provider, taken from an account the application declared for the same query.
8292
+ * The shape a hand-added account starts from, for a backend whose login is not `email` and `password`.
8293
+ */
8294
+ const queryDevtoolsAuthFieldsFor = (provider, loginQuery) => {
8295
+ const mine = declared().filter((account) => account.provider === provider && account.fields?.length);
8296
+ const shape = (loginQuery ? mine.find((account) => account.loginQuery === loginQuery) : undefined) ?? mine[0];
8297
+ return (shape?.fields ?? DEFAULT_FIELDS).map(({ name, label, type }) => ({ name, label, type }));
8298
+ };
7991
8299
  /** Adds an account the application does not declare, for the backend in force. */
7992
8300
  const addQueryDevtoolsAuthAccount = (options) => {
7993
8301
  const account = { ...options, id: nextId('account'), scope: scopeOf() };
@@ -8024,6 +8332,23 @@ const forgetQueryDevtoolsAuthSession = (sessionId) => {
8024
8332
  persist();
8025
8333
  syncPill();
8026
8334
  };
8335
+ /**
8336
+ * Drops every session this backend issued for one provider. The accounts and what was typed in for them
8337
+ * are left alone, so the way back in is one login.
8338
+ */
8339
+ const forgetQueryDevtoolsAuthSessionsFor = (provider) => {
8340
+ const scope = scopeOf();
8341
+ const dropped = new Set(store()
8342
+ .sessions.filter((session) => session.provider === provider && session.scope === scope)
8343
+ .map((session) => session.id));
8344
+ store.update((current) => ({
8345
+ ...current,
8346
+ sessions: current.sessions.filter((session) => !dropped.has(session.id)),
8347
+ }));
8348
+ active.update((current) => Object.fromEntries(Object.entries(current).map(([name, id]) => [name, id && dropped.has(id) ? null : id])));
8349
+ persist();
8350
+ syncPill();
8351
+ };
8027
8352
  /** Empties the vault: every session, every account added in the panel, every credential. */
8028
8353
  const clearQueryDevtoolsAuthSessions = () => {
8029
8354
  store.set(EMPTY);
@@ -8033,17 +8358,6 @@ const clearQueryDevtoolsAuthSessions = () => {
8033
8358
  syncPill();
8034
8359
  };
8035
8360
  const reload = () => globalThis.location?.reload();
8036
- /**
8037
- * Drops what the previous user left behind. Their responses are cached under keys the next user's
8038
- * requests hit, and a bound secure query would go on rendering a body that was fetched for somebody else.
8039
- */
8040
- const clearClientData = (entry) => {
8041
- const { repository } = entry.client;
8042
- repository.unbindAllSecure();
8043
- for (const cacheEntry of repository.subtle.cacheEntries())
8044
- repository.subtle.evict(cacheEntry.key);
8045
- void entry.client.clearPersistedQueries();
8046
- };
8047
8361
  /**
8048
8362
  * Puts one stored session's tokens in force. The reload is the default because a switch only replaces
8049
8363
  * what the query layer holds: an application that keeps the user anywhere else - a profile service, the
@@ -8056,7 +8370,6 @@ const switchQueryDevtoolsAuthSession = (options) => {
8056
8370
  const entry = live.get(session.provider);
8057
8371
  if (!entry || session.scope !== scopeOf())
8058
8372
  return;
8059
- clearClientData(entry);
8060
8373
  setActive(session.provider, session.id);
8061
8374
  if (tabLocal()[session.provider]) {
8062
8375
  writeSeeds({
@@ -8071,6 +8384,7 @@ const switchQueryDevtoolsAuthSession = (options) => {
8071
8384
  }
8072
8385
  persist();
8073
8386
  entry.handle.setTokens(session.accessToken, session.refreshToken);
8387
+ clearClientData(entry);
8074
8388
  syncPill();
8075
8389
  if (options.reload ?? queryDevtoolsSettings().reloadOnAuthSwitch)
8076
8390
  reload();
@@ -8089,8 +8403,9 @@ const loginQueryDevtoolsAuthAccount = (accountId) => {
8089
8403
  const query = entry?.handle.queries?.[account.loginQuery];
8090
8404
  if (!entry || !query)
8091
8405
  return;
8092
- clearClientData(entry);
8406
+ const previous = active()[account.provider] ?? null;
8093
8407
  setActive(account.provider, null);
8408
+ pendingLogins.set(account.provider, { id: account.id, label: account.label, previous });
8094
8409
  persist();
8095
8410
  query.execute(account.buildArgs?.(account.values) ?? { body: account.values });
8096
8411
  };
@@ -8123,6 +8438,10 @@ const setQueryDevtoolsAuthTabLocal = (options) => {
8123
8438
  writeSeeds({ ...seeds, [provider]: { sessionId, scope: scopeOf(), accessToken, refreshToken } });
8124
8439
  reload();
8125
8440
  };
8441
+ /** When a session's tokens were last written, which is what tells two same-named ones apart. */
8442
+ const savedAtLabel = (session) => session.savedAt
8443
+ ? new Date(session.savedAt).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })
8444
+ : 'unknown';
8126
8445
  /** What the floating pill offers, rebuilt whenever any of it changes. */
8127
8446
  const syncPill = () => {
8128
8447
  const rows = untracked(() => providers().map((provider) => {
@@ -8130,6 +8449,10 @@ const syncPill = () => {
8130
8449
  const accounts = queryDevtoolsAuthAccountsFor(provider);
8131
8450
  const activeId = active()[provider] ?? null;
8132
8451
  const current = sessions.find((session) => session.id === activeId);
8452
+ const shared = new Map();
8453
+ for (const session of sessions)
8454
+ shared.set(session.label, (shared.get(session.label) ?? 0) + 1);
8455
+ const labelOf = (session) => shared.get(session.label) === 1 ? session.label : `${session.label} · ${savedAtLabel(session)}`;
8133
8456
  return {
8134
8457
  name: provider,
8135
8458
  current: current?.label ?? (live.get(provider)?.handle.accessToken() ? 'unnamed session' : 'anonymous'),
@@ -8137,7 +8460,7 @@ const syncPill = () => {
8137
8460
  options: [
8138
8461
  ...sessions.map((session) => ({
8139
8462
  value: `session:${session.id}`,
8140
- label: session.label,
8463
+ label: labelOf(session),
8141
8464
  title: `Switch to ${session.label}`,
8142
8465
  selected: session.id === activeId,
8143
8466
  disabled: false,
@@ -9259,7 +9582,7 @@ const armQueryDevtoolsOverrideTransfer = (recorder, ops) => {
9259
9582
 
9260
9583
  // Generated from package.json by tools/scripts/generate-version.js - do not edit.
9261
9584
  /** The version of `@ethlete/query` this build was cut from. */
9262
- const QUERY_VERSION = '6.0.0-next.41';
9585
+ const QUERY_VERSION = '6.0.0-next.42';
9263
9586
 
9264
9587
  /** How deep a schema is expanded before a nested branch is given up on. */
9265
9588
  const MAX_DEPTH = 12;
@@ -10566,7 +10889,16 @@ const provideQueryDevtools = (options) => {
10566
10889
  if (!isDevMode()) {
10567
10890
  console.warn('You are using the Query Devtools in production mode. This increases the size of your bundle and should only be used for development purposes.');
10568
10891
  }
10569
- return makeEnvironmentProviders([]);
10892
+ return makeEnvironmentProviders([
10893
+ // The floating pills paint before this - before `bootstrapApplication`, so a boot that hangs on the
10894
+ // backend it was just pointed at can still be pointed somewhere else. Once the application has
10895
+ // settled they follow the devtools trigger instead, and an app that renders none shows no pills.
10896
+ provideEnvironmentInitializer(() => {
10897
+ void inject(ApplicationRef)
10898
+ .whenStable()
10899
+ .then(() => markQueryDevtoolsAppSettled());
10900
+ }),
10901
+ ]);
10570
10902
  };
10571
10903
 
10572
10904
  const getOpName = /\b(?:query|mutation)\s+([\w-]+)(?:\s*\([^)]*\))?\s*\{/;
@@ -16253,5 +16585,5 @@ const createWebSocketClient = (options) => {
16253
16585
  * Generated bundle index. Do not edit.
16254
16586
  */
16255
16587
 
16256
- export { AuthBearerRefreshStrategy, BasicAuthProvider, BearerAuthFeatureType, BooleanArrayQueryField, CustomHeaderAuthProvider, DEFAULT_KEEP_UNUSED_FOR, DEFAULT_QUERY_PERSISTENCE_MAX_AGE, DEFAULT_QUERY_PERSISTENCE_MAX_ENTRIES, DEFAULT_QUERY_PERSISTENCE_VERSION, DEFAULT_QUERY_PERSISTENCE_WRITE_DELAY, DateArrayQueryField, DateQueryField, EMPTY_QUERY_DEVTOOLS_FAULT, EntityStore, IGNORED_FILTER_COUNT_FIELDS, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, LegacyQuery, LegacyQueryCreator, MAX_QUERY_BATCH_TOMBSTONES, MAX_QUERY_DEVTOOLS_TOMBSTONES, MAX_UNUSED_ENTRIES, NumberArrayQueryField, ParseHttpErrorCodeToMessageDePipe, ParseHttpErrorCodeToMessageEnPipe, ParseHttpErrorCodeToTitleDePipe, ParseHttpErrorCodeToTitleEnPipe, QUERY_CLIENT_DEVTOOLS_TOKEN, QUERY_DEVTOOLS_FAULT_STATUSES, QUERY_DEVTOOLS_TOKEN_TTL_LIMIT, QUERY_PERSISTENCE_STORE_VERSION, QUERY_SYNC_PROTOCOL_VERSION, QUERY_VERSION, QueryClientFeatureType, QueryDevtoolsComponent, QueryDirective, QueryFeatureType, QueryField, QueryForm, QueryRuntimeErrorCode, QueryShortNamePipe, QueryStateType, QueryStore, SERVER_ERROR_KIND, SERVER_VIOLATION_ERROR_KIND, SPEED_BUFFER_TIME_IN_MS, SearchQueryField, SortQueryField, StringArrayQueryField, V2BearerAuthProvider, V2Query, V2QueryClient, V2QueryCreator, addQueryContainerHandling, addQueryDevtoolsAuthAccount, applyQueryDevtoolsOverrides, applyQueryDevtoolsTokenTtl, applyQueryFeatures, armAllQueryDevtoolsMocks, armQueryDevtoolsMock, armQueryDevtoolsOverrideTransfer, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, booleanArrayQueryField, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, canOverrideQueryDevtoolsTokenTtl, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, clearQueryDevtoolsArmedMocks, clearQueryDevtoolsAuthCredentials, clearQueryDevtoolsAuthSessions, 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, forgetQueryDevtoolsAuthSession, formatQueryDevtoolsDuration, generateQueryDevtoolsNumberPreset, generateQueryDevtoolsSampleNumber, generateQueryDevtoolsStringPreset, getBearerAuthProviderName, getDefaultHeaders, getQueryClientName, getQueryFeatureUsage, getResponseUrl, ggLikePaginationAdapter, gql, gqlDataPropertyMissingInResponse, hasHeader, hasQueryDevtoolsOverridesAtPath, htmlErrorPayload, htmlQueryErrorParser, ignoreAutoRefresh, initQueryDevtoolsAuthSessions, 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, loginQueryDevtoolsAuthAccount, logoutQueryDevtoolsAuthSession, 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, queryDevtoolsApiEnvIds, queryDevtoolsApiEnvIsProduction, queryDevtoolsApiEnvScope, queryDevtoolsApiEnvValues, queryDevtoolsApiEnvs, queryDevtoolsArmedMocks, queryDevtoolsArmedMocksRestored, queryDevtoolsAuthAccountsFor, queryDevtoolsAuthActive, queryDevtoolsAuthOtherScopeCount, queryDevtoolsAuthProviders, queryDevtoolsAuthSessions, queryDevtoolsAuthSessionsFor, queryDevtoolsAuthTabLocal, 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, readQueryDevtoolsAuthSeed, readQueryDevtoolsAuthSeedFor, readQueryDevtoolsStore, registerEthleteVersion, registerQueryDevtoolsAuthProvider, registerQueryDevtoolsEntry, registerQueryErrorParser, removeFrom, removeQueryDevtoolsAuthAccount, renameQueryDevtoolsAuthSession, request, resetExecuteState, resetPageOnError, resolveInvalidationUrl, resolveQueryDevtoolsFault, resolveQueryDevtoolsFaultForAttempt, resolveQueryDevtoolsMock, resolveQueryDevtoolsMockForAttempt, restoredQueryDevtoolsOverrides, runDefaultQueryRetry, runInQueryDevtoolsBatch, runQueryErrorParsers, saveQueryDevtoolsMock, searchQueryField, seedQueryDevtoolsSchemaBody, seedQueryDevtoolsSchemaRoute, serializeBody, serializeQueryDevtoolsOverrideTransfer, setDefaultQueryRetryFn, setQueryDevtoolsApiEnv, setQueryDevtoolsApiEnvs, setQueryDevtoolsAppInfo, setQueryDevtoolsArmedMocksScope, setQueryDevtoolsAuthCredentials, setQueryDevtoolsAuthProviderRegistrar, setQueryDevtoolsAuthSeedReader, setQueryDevtoolsAuthTabLocal, 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, switchQueryDevtoolsAuthSession, switchQueryState, symfonyQueryErrorParser, takeUntilResponse, toQuerySignal, toQuerySubject, tokensNotAvailableInsideAuthAndExec, tombstoneOf, trackQueryDevtoolsAuthProvider, 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 };
16588
+ export { AuthBearerRefreshStrategy, BasicAuthProvider, BearerAuthFeatureType, BooleanArrayQueryField, CustomHeaderAuthProvider, DEFAULT_KEEP_UNUSED_FOR, DEFAULT_QUERY_PERSISTENCE_MAX_AGE, DEFAULT_QUERY_PERSISTENCE_MAX_ENTRIES, DEFAULT_QUERY_PERSISTENCE_VERSION, DEFAULT_QUERY_PERSISTENCE_WRITE_DELAY, DateArrayQueryField, DateQueryField, EMPTY_QUERY_DEVTOOLS_FAULT, EntityStore, IGNORED_FILTER_COUNT_FIELDS, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, LegacyQuery, LegacyQueryCreator, MAX_QUERY_BATCH_TOMBSTONES, MAX_QUERY_DEVTOOLS_TOMBSTONES, MAX_UNUSED_ENTRIES, NumberArrayQueryField, ParseHttpErrorCodeToMessageDePipe, ParseHttpErrorCodeToMessageEnPipe, ParseHttpErrorCodeToTitleDePipe, ParseHttpErrorCodeToTitleEnPipe, QUERY_CLIENT_DEVTOOLS_TOKEN, QUERY_DEVTOOLS_FAULT_STATUSES, QUERY_DEVTOOLS_TOKEN_TTL_LIMIT, QUERY_PERSISTENCE_STORE_VERSION, QUERY_SYNC_PROTOCOL_VERSION, QUERY_VERSION, QueryClientFeatureType, QueryDevtoolsComponent, QueryDirective, QueryFeatureType, QueryField, QueryForm, QueryRuntimeErrorCode, QueryShortNamePipe, QueryStateType, QueryStore, SERVER_ERROR_KIND, SERVER_VIOLATION_ERROR_KIND, SPEED_BUFFER_TIME_IN_MS, SearchQueryField, SortQueryField, StringArrayQueryField, V2BearerAuthProvider, V2Query, V2QueryClient, V2QueryCreator, addQueryContainerHandling, addQueryDevtoolsAuthAccount, applyQueryDevtoolsOverrides, applyQueryDevtoolsTokenTtl, applyQueryFeatures, armAllQueryDevtoolsMocks, armQueryDevtoolsMock, armQueryDevtoolsOverrideTransfer, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, booleanArrayQueryField, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, canOverrideQueryDevtoolsTokenTtl, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, clearQueryDevtoolsArmedMocks, clearQueryDevtoolsAuthCredentials, clearQueryDevtoolsAuthSessions, 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, forgetQueryDevtoolsAuthSession, forgetQueryDevtoolsAuthSessionsFor, formatQueryDevtoolsDuration, generateQueryDevtoolsNumberPreset, generateQueryDevtoolsSampleNumber, generateQueryDevtoolsStringPreset, getBearerAuthProviderName, getDefaultHeaders, getQueryClientName, getQueryFeatureUsage, getResponseUrl, ggLikePaginationAdapter, gql, gqlDataPropertyMissingInResponse, hasHeader, hasQueryDevtoolsOverridesAtPath, htmlErrorPayload, htmlQueryErrorParser, ignoreAutoRefresh, initQueryDevtoolsAuthSessions, 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, loginQueryDevtoolsAuthAccount, logoutQueryDevtoolsAuthSession, 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, queryDevtoolsApiEnvIds, queryDevtoolsApiEnvIsProduction, queryDevtoolsApiEnvScope, queryDevtoolsApiEnvValues, queryDevtoolsApiEnvs, queryDevtoolsArmedMocks, queryDevtoolsArmedMocksRestored, queryDevtoolsAuthAccountsFor, queryDevtoolsAuthActive, queryDevtoolsAuthFieldsFor, queryDevtoolsAuthOtherScopeCount, queryDevtoolsAuthProviders, queryDevtoolsAuthSessions, queryDevtoolsAuthSessionsFor, queryDevtoolsAuthTabLocal, 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, readQueryDevtoolsAuthSeed, readQueryDevtoolsAuthSeedFor, readQueryDevtoolsStore, registerEthleteVersion, registerQueryDevtoolsAuthProvider, registerQueryDevtoolsEntry, registerQueryErrorParser, removeFrom, removeQueryDevtoolsAuthAccount, renameQueryDevtoolsAuthSession, request, resetExecuteState, resetPageOnError, resolveInvalidationUrl, resolveQueryDevtoolsFault, resolveQueryDevtoolsFaultForAttempt, resolveQueryDevtoolsMock, resolveQueryDevtoolsMockForAttempt, restoredQueryDevtoolsOverrides, runDefaultQueryRetry, runInQueryDevtoolsBatch, runQueryErrorParsers, saveQueryDevtoolsMock, searchQueryField, seedQueryDevtoolsSchemaBody, seedQueryDevtoolsSchemaRoute, serializeBody, serializeQueryDevtoolsOverrideTransfer, setDefaultQueryRetryFn, setQueryDevtoolsApiEnv, setQueryDevtoolsApiEnvs, setQueryDevtoolsAppInfo, setQueryDevtoolsArmedMocksScope, setQueryDevtoolsAuthCredentials, setQueryDevtoolsAuthProviderRegistrar, setQueryDevtoolsAuthSeedReader, setQueryDevtoolsAuthTabLocal, setQueryDevtoolsFault, setQueryDevtoolsFaultResolver, setQueryDevtoolsFaultsScope, setQueryDevtoolsFormLinksFactory, setQueryDevtoolsMockResolver, setQueryDevtoolsOverridePersistence, setQueryDevtoolsOverridesFactory, setQueryDevtoolsOverridesScope, setQueryDevtoolsRegistrar, setQueryDevtoolsResponseHistory, setQueryDevtoolsSchemaLoader, setQueryDevtoolsSettings, setQueryDevtoolsStatsFactory, setQueryDevtoolsTokenPayloadPatcher, setQueryDevtoolsTokenTtl, setQueryDevtoolsUiMounted, setupQueryDependencies, setupQueryExecuteState, setupQueryState, shouldAutoExecuteGqlQuery, shouldAutoExecuteQuery, shouldCacheQuery, shouldRetryRequest, silenceMissingWithArgsFeatureErrorUsedButWithArgsPresent, skipPaginationPageParamCalculator, smartDuplicateArrayItem, snapshotQueryDevtoolsHandle, sortQueryField, splitQueryConfig, stringArrayQueryField, stringifyQueryRouteParts, sumQueryDevtoolsStats, suppressNextQueryStackDevtools, switchQueryCollectionState, switchQueryDevtoolsAuthSession, switchQueryState, symfonyQueryErrorParser, takeUntilResponse, toQuerySignal, toQuerySubject, tokensNotAvailableInsideAuthAndExec, tombstoneOf, trackQueryDevtoolsAuthProvider, 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 };
16257
16589
  //# sourceMappingURL=ethlete-query.mjs.map