@ethlete/query-devtools 1.0.0-next.0 → 1.0.0-next.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethlete/query-devtools",
3
- "version": "1.0.0-next.0",
3
+ "version": "1.0.0-next.10",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
@@ -12,6 +12,10 @@ declare const queryDevtoolsShortcutLabel: () => "⌘⌥Q" | "Ctrl+Alt+Q";
12
12
  * host application's global CSS (Tailwind resets, button styles, …) can never touch it and its own
13
13
  * styles can never leak out. Uses px (not rem) internally so it doesn't depend on the host's root
14
14
  * font-size; theme accent colour is read from an inherited custom property with a fallback.
15
+ *
16
+ * Mounted on its own - without `<et-query-devtools-lazy>` or `<et-query-devtools>` - it declares no
17
+ * devtools UI, so the floating API env and session pills take themselves off the page once the
18
+ * application settles. Call `setQueryDevtoolsUiMounted(true)` to keep them.
15
19
  */
16
20
  declare class QueryDevtoolsToggleComponent {
17
21
  tampered: _angular_core.InputSignal<boolean>;
@@ -1,7 +1,7 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { Signal, WritableSignal, OnInit } from '@angular/core';
3
3
  import * as _ethlete_query from '@ethlete/query';
4
- import { JsonPath, QueryDevtoolsOverridesRecorder, QueryRefreshCause, QueryRepositoryEntryDestroyedCause, Query, QueryRepositoryCacheEntry, HttpRequestRetryState, HttpRequestLoadingProgressState, QueryDevtoolsStats, QueryDevtoolsStatsHandle, QueryDevtoolsEntry, QueryRepository, QueryClient, QueryKeyLockState, QueryDevtoolsFeature, QueryDevtoolsFault, AnyQueryStack, AnyPagedQueryStack, QuerySequence, AnyBearerAuthProvider, WebSocketDevtoolsHandle, QueryDevtoolsFormHandle, QuerySequenceStatus, AnyQuerySnapshot, QueryDevtoolsRun, QueryDevtoolsRunError, WebSocketDevtoolsMessage, QueryDevtoolsStorageScope } from '@ethlete/query';
4
+ import { JsonPath, QueryDevtoolsOverridesRecorder, QueryRefreshCause, QueryRepositoryEntryDestroyedCause, Query, QueryRepositoryCacheEntry, HttpRequestRetryState, HttpRequestLoadingProgressState, QueryDevtoolsStats, QueryDevtoolsStatsHandle, QueryDevtoolsEntry, AnyQueryBatchItemResult, QueryRepository, QueryClient, QueryKeyLockState, QueryDevtoolsFeature, QueryDevtoolsFault, AnyQueryStack, AnyPagedQueryStack, QuerySequence, AnyQueryBatch, AnyBearerAuthProvider, WebSocketDevtoolsHandle, QueryDevtoolsFormHandle, QuerySequenceStatus, AnyQuerySnapshot, QueryDevtoolsRun, QueryDevtoolsRunError, WebSocketDevtoolsMessage, QueryDevtoolsStorageScope, QueryDevtoolsApiEnvSwitch } from '@ethlete/query';
5
5
  import { ResizeEdge, DragMoveEvent, ResizeMoveEvent } from '@ethlete/core';
6
6
 
7
7
  type AboutRow = {
@@ -82,7 +82,10 @@ declare class QueryDevtoolsJsonComponent {
82
82
  private shapePath;
83
83
  protected annotation: _angular_core.Signal<string | null>;
84
84
  protected annotationTitle: _angular_core.Signal<string>;
85
- /** A `Date` or a `File` is object-typed but has nothing to expand into, so it renders as a leaf. */
85
+ /**
86
+ * A `Date` is object-typed but has nothing to expand into, so it renders as a leaf. A resolved
87
+ * header provider is the other way round: a function that does expand.
88
+ */
86
89
  protected isContainer: _angular_core.Signal<boolean>;
87
90
  /** The entries this node covers: the container's own, or just the window a chunk stands for. */
88
91
  ownEntries: _angular_core.Signal<JsonEntry[]>;
@@ -93,7 +96,7 @@ declare class QueryDevtoolsJsonComponent {
93
96
  private togglePath;
94
97
  private defaultExpanded;
95
98
  private localExpanded;
96
- protected expanded: _angular_core.Signal<boolean>;
99
+ private expanded;
97
100
  /** Only slices that actually contain a match unfold while searching, so a filter stays cheap. */
98
101
  private chunkHasHit;
99
102
  protected effectiveExpanded: _angular_core.Signal<boolean>;
@@ -167,6 +170,30 @@ type QueryDevtoolsDiff = {
167
170
  truncated: boolean;
168
171
  };
169
172
 
173
+ /** Which SDK feature a lock name belongs to, or `other` for one the panel did not put there. */
174
+ type DevtoolsLockKind = 'auth' | 'poll' | 'other';
175
+ /** Where the tab the panel is open in stands on one lock. */
176
+ type DevtoolsLockStanding = 'holder' | 'queued' | 'absent' | 'unknown';
177
+ /** One lock name, with every client that holds or waits for it folded into a single row. */
178
+ type DevtoolsLockRow = {
179
+ /** The raw name, so a lock the panel cannot decode is still greppable from the row. */
180
+ name: string;
181
+ /** What the name means: the provider for an auth lock, the cache key for a poll lock. */
182
+ label: string;
183
+ kind: DevtoolsLockKind;
184
+ /** The sync channel a poll lock belongs to, or `null` for a name that carries no such part. */
185
+ channel: string | null;
186
+ /**
187
+ * Held plus queued on this name. Every participant requests the same lock and exactly one gets it, so
188
+ * this is the number of tabs, workers and service workers taking part - the same arithmetic the auth
189
+ * provider's own `instanceCount` does.
190
+ */
191
+ tabs: number;
192
+ standing: DevtoolsLockStanding;
193
+ /** This tab's 1-based place in the queue, or `null` unless {@link standing} is `queued`. */
194
+ queuePlace: number | null;
195
+ };
196
+
170
197
  type AnyQuery = Query<any>;
171
198
  /** The query a detail pane is showing, together with the registry entry it was registered as. */
172
199
  type QueryDevtoolsSelection = {
@@ -178,7 +205,7 @@ type QueryDevtoolsSelection = {
178
205
  * to count, so the badge/overflow logic would push it behind **More** - it is reached from the header's
179
206
  * gear instead.
180
207
  */
181
- type DevtoolsTab = 'queries' | 'stacks' | 'sequences' | 'forms' | 'auth' | 'ws' | 'cache' | 'timeline' | 'events' | 'faults' | 'mocks' | 'about' | 'settings';
208
+ type DevtoolsTab = 'queries' | 'stacks' | 'sequences' | 'batches' | 'forms' | 'auth' | 'ws' | 'cache' | 'locks' | 'timeline' | 'events' | 'faults' | 'mocks' | 'about' | 'settings';
182
209
  /**
183
210
  * The sections of the query detail drawer. The head and its actions stay pinned above them - the detail
184
211
  * holds more than fits a column, and everything below the actions is reading material.
@@ -208,11 +235,11 @@ type RouteSegment = {
208
235
  name?: string;
209
236
  };
210
237
  /**
211
- * Which tab refreshes an auth provider's tokens, as the auth tab's chip renders it. `title` carries
212
- * the caveats the label has no room for - why every tab reads as the leader, or how approximate the
213
- * tab count is.
238
+ * A one-line verdict the panel renders as a chip - which tab refreshes an auth provider's tokens, where
239
+ * this tab stands on a lock. `title` carries the caveats the label has no room for: why every tab reads
240
+ * as the leader, or how approximate a tab count is.
214
241
  */
215
- type QueryDevtoolsLeadership = {
242
+ type QueryDevtoolsChip = {
216
243
  label: string;
217
244
  tone: 'success' | 'muted';
218
245
  title: string;
@@ -237,6 +264,20 @@ type QueryLink = {
237
264
  clientBaseUrl: string;
238
265
  stats?: QueryDevtoolsStatsHandle;
239
266
  };
267
+ /** One settled item of a query batch, with the route the args it was sent with resolve to. */
268
+ type BatchItemRow = {
269
+ result: AnyQueryBatchItemResult;
270
+ segments: RouteSegment[];
271
+ };
272
+ /**
273
+ * A batch's settled items as its card lists them. Capped, and `hidden` says by how much - a bulk run
274
+ * settles more items than a list can hold, and a truncated one must not read as the whole run.
275
+ */
276
+ type BatchItemView = {
277
+ rows: BatchItemRow[];
278
+ total: number;
279
+ hidden: number;
280
+ };
240
281
  /**
241
282
  * Query stats plus the numbers the panel derives from them rather than storing: an execution that never
242
283
  * reached the network was answered from the cache, and the averages come from the running totals.
@@ -367,6 +408,7 @@ type QueryDevtoolsHost = {
367
408
  queryEntries: Signal<QueryDevtoolsEntry[]>;
368
409
  stackEntries: Signal<QueryDevtoolsEntry[]>;
369
410
  sequenceEntries: Signal<QueryDevtoolsEntry[]>;
411
+ batchEntries: Signal<QueryDevtoolsEntry[]>;
370
412
  formEntries: Signal<QueryDevtoolsEntry[]>;
371
413
  authEntries: Signal<QueryDevtoolsEntry[]>;
372
414
  wsEntries: Signal<QueryDevtoolsEntry[]>;
@@ -391,6 +433,14 @@ type QueryDevtoolsHost = {
391
433
  clearPersistedQueries(client: QueryClient): void;
392
434
  /** The features of the client behind a cache tab card, or `null` for a client without any. */
393
435
  clientFeatures(client: QueryClient | null | undefined): QueryDevtoolsFeature[] | null;
436
+ /**
437
+ * Every Web Lock held or queued across this origin, decoded, or `null` in a browser without the Web
438
+ * Locks API. Empty while the Locks tab has not read its first snapshot - it polls, because Web Locks
439
+ * has no change event to listen to.
440
+ */
441
+ lockRows: Signal<DevtoolsLockRow[] | null>;
442
+ /** Where this tab stands on one lock, as a chip: whether it holds it, waits for it, or is not in it. */
443
+ lockStanding(row: DevtoolsLockRow): QueryDevtoolsChip;
394
444
  /** Unique client names present across queries and auth providers, for the Queries/Timeline pickers. */
395
445
  clientNames: Signal<string[]>;
396
446
  /** What each tab holds - also drives the tab bar's own badges, so it lives here rather than per-tab. */
@@ -418,6 +468,7 @@ type QueryDevtoolsHost = {
418
468
  asStack(entry: QueryDevtoolsEntry): AnyQueryStack;
419
469
  asPagedStack(entry: QueryDevtoolsEntry): AnyPagedQueryStack;
420
470
  asSequence(entry: QueryDevtoolsEntry): QuerySequence<unknown[]>;
471
+ asBatch(entry: QueryDevtoolsEntry): AnyQueryBatch;
421
472
  asAuth(entry: QueryDevtoolsEntry): AnyBearerAuthProvider;
422
473
  asWs(entry: QueryDevtoolsEntry): WebSocketDevtoolsHandle;
423
474
  asForm(entry: QueryDevtoolsEntry): QueryDevtoolsFormHandle;
@@ -426,7 +477,7 @@ type QueryDevtoolsHost = {
426
477
  /** The access-token expiry the app acts on, plus the lifetime the panel has armed over it. */
427
478
  authTokenLifetime(entry: QueryDevtoolsEntry): QueryDevtoolsTokenLifetime;
428
479
  /** The multi-tab leadership chip, or `null` for a provider without `withBearerAuthMultiTabSync`. */
429
- authLeadership(auth: AnyBearerAuthProvider): QueryDevtoolsLeadership | null;
480
+ authLeadership(auth: AnyBearerAuthProvider): QueryDevtoolsChip | null;
430
481
  queryStatus(query: AnyQuery): 'idle' | 'loading' | 'success' | 'error';
431
482
  isStale(query: AnyQuery): boolean;
432
483
  /** Whether an entry is showing an armed response override or a devtools-faulted outcome. */
@@ -443,6 +494,11 @@ type QueryDevtoolsHost = {
443
494
  requestUrl(query: AnyQuery): string | null;
444
495
  requestPath(url: string): string;
445
496
  queryArgs(query: AnyQuery): unknown;
497
+ /**
498
+ * The headers the query's last run sent, or - before it has run - the ones its args and its client
499
+ * resolve to now. `null` when there are none, or while a header provider cannot resolve yet.
500
+ */
501
+ requestHeaders(query: AnyQuery): Record<string, string> | null;
446
502
  routeSegments(entry: QueryDevtoolsEntry | undefined, query: AnyQuery): RouteSegment[];
447
503
  queryActivity(entry: QueryDevtoolsEntry): QueryActivity;
448
504
  linkActivity(link: QueryLink): QueryActivity;
@@ -460,6 +516,30 @@ type QueryDevtoolsHost = {
460
516
  /** Whether a sequence step's in/out detail (`<entryId>:<stepIndex>`) is expanded - persisted. */
461
517
  isStepExpanded(entryId: string, index: number): boolean;
462
518
  toggleStep(entryId: string, index: number): void;
519
+ /** A batch's route with its path params left as `:name` - a batch fills them in per item, not once. */
520
+ batchRouteSegments(entry: QueryDevtoolsEntry): RouteSegment[];
521
+ /**
522
+ * The batch entry that created a query, or `null` for a query no batch did. What lets the Queries list
523
+ * fold a bulk run's items under one row instead of listing whatever it has in flight.
524
+ */
525
+ batchOf(entry: QueryDevtoolsEntry): QueryDevtoolsEntry | null;
526
+ /**
527
+ * The item queries a batch has in flight. Only those: a batch destroys each item's query the moment
528
+ * that item settles, so a settled item is read from {@link batchItems} instead.
529
+ */
530
+ queriesForBatch(entry: QueryDevtoolsEntry): QueryLink[];
531
+ /** A batch's settled items, failures first and capped - see {@link BatchItemView}. */
532
+ batchItems(entry: QueryDevtoolsEntry): BatchItemView;
533
+ /**
534
+ * The registry entry of one of a batch's items, or `null` once it has fallen out of the batch's capped
535
+ * tombstone tail - which is what makes an item row openable only while its query is still kept.
536
+ */
537
+ batchItemQueryId(entry: QueryDevtoolsEntry, index: number): string | null;
538
+ /** An item's throughput line (`12.4 items/s · ~8s left`), or `null` before there is a rate to show. */
539
+ batchThroughput(batch: AnyQueryBatch): string | null;
540
+ /** Whether a batch item's args/response detail (`<entryId>:<itemIndex>`) is expanded - persisted. */
541
+ isBatchItemExpanded(entryId: string, index: number): boolean;
542
+ toggleBatchItem(entryId: string, index: number): void;
463
543
  /** Keys of the Queries-list groups of identical rows the user opened - persisted. */
464
544
  expandedQueryGroups: Signal<ReadonlySet<string>>;
465
545
  toggleQueryGroup(key: string): void;
@@ -600,6 +680,16 @@ type QueryDevtoolsHost = {
600
680
  entry: QueryDevtoolsEntry;
601
681
  query: AnyQuery;
602
682
  } | null>;
683
+ batchSelectedQueryId: WritableSignal<string | null>;
684
+ batchSelectedQuery: Signal<{
685
+ entry: QueryDevtoolsEntry;
686
+ query: AnyQuery;
687
+ } | null>;
688
+ eventSelectedQueryId: WritableSignal<string | null>;
689
+ eventSelectedQuery: Signal<{
690
+ entry: QueryDevtoolsEntry;
691
+ query: AnyQuery;
692
+ } | null>;
603
693
  formSelectedQueryId: WritableSignal<string | null>;
604
694
  formSelectedQuery: Signal<{
605
695
  entry: QueryDevtoolsEntry;
@@ -641,7 +731,7 @@ type QueryDevtoolsHost = {
641
731
  resetPaneSize(pane: PaneTarget): void;
642
732
  };
643
733
 
644
- type ScopeKey = 'viewState' | 'pins' | 'overrides' | 'mocks' | 'armedMocks' | 'armedFaults';
734
+ type ScopeKey = 'viewState' | 'pins' | 'overrides' | 'mocks' | 'armedMocks' | 'armedFaults' | 'authSessions';
645
735
  type ScopeRow = {
646
736
  key: ScopeKey;
647
737
  label: string;
@@ -670,6 +760,7 @@ type LimitRow = {
670
760
  * otherwise hold as constants, and the toggles their own tabs also carry.
671
761
  */
672
762
  declare class QueryDevtoolsSettingsComponent {
763
+ private document;
673
764
  protected host: QueryDevtoolsHost;
674
765
  protected readonly SCOPE_ROWS: ScopeRow[];
675
766
  protected readonly SCOPES: {
@@ -684,9 +775,27 @@ declare class QueryDevtoolsSettingsComponent {
684
775
  /** What queries actually retain, which is the application's value unless this panel raised it. */
685
776
  protected responseHistory: _angular_core.Signal<number>;
686
777
  protected mockCount: _angular_core.Signal<number>;
778
+ protected sessionCount: _angular_core.Signal<number>;
687
779
  protected armedMockCount: _angular_core.Signal<number>;
688
780
  protected armedFaultCount: _angular_core.Signal<number>;
689
781
  protected resetConfirming: _angular_core.WritableSignal<boolean>;
782
+ protected readonly FORGET_SESSIONS: () => void;
783
+ /** The backends the application declared, or an empty list - the card renders only for a declared one. */
784
+ protected apiEnvs: _angular_core.Signal<QueryDevtoolsApiEnvSwitch[]>;
785
+ /** The env id (or typed URL) a switch's key holds, or `null` while the application picks for itself. */
786
+ protected apiEnvValue(apiSwitch: QueryDevtoolsApiEnvSwitch): string | null;
787
+ /** The env a switch falls back to with nothing stored, described for the default button. */
788
+ protected apiEnvFallback(apiSwitch: QueryDevtoolsApiEnvSwitch): {
789
+ label: string;
790
+ production: boolean;
791
+ };
792
+ /** Whether the pick in force - the stored env, or the fallback behind an unwritten key - is production. */
793
+ protected apiEnvIsProduction(apiSwitch: QueryDevtoolsApiEnvSwitch): boolean;
794
+ /** A stored value no declared env carries, which is a URL somebody typed in below. */
795
+ protected apiEnvCustomUrl(apiSwitch: QueryDevtoolsApiEnvSwitch): string;
796
+ /** Writes the application's own key and reloads - it is read before Angular boots, so nothing else can. */
797
+ protected pickApiEnv(apiSwitch: QueryDevtoolsApiEnvSwitch, value: string | null): void;
798
+ protected setCustomApiUrl(apiSwitch: QueryDevtoolsApiEnvSwitch, value: string): void;
690
799
  protected settings(): _ethlete_query.QueryDevtoolsSettings;
691
800
  protected scopeOf(key: ScopeKey): QueryDevtoolsStorageScope;
692
801
  protected limitOf(key: LimitKey): number;
@@ -729,21 +838,6 @@ type FloatRect = {
729
838
  width: number;
730
839
  height: number;
731
840
  };
732
- /**
733
- * A drag in progress: the panel's docked edge, the floating panel being moved or resized, or the
734
- * divider between a two-pane tab's panes.
735
- */
736
- type ResizeDrag = {
737
- /** The document the pointer moves in - a popped-out panel lives in a window of its own. */
738
- doc: Document;
739
- } & ({
740
- kind: 'panel';
741
- } | {
742
- kind: 'pane';
743
- pane: PaneTarget;
744
- axis: PaneAxis;
745
- container: HTMLElement;
746
- });
747
841
  type PersistedState = {
748
842
  open?: boolean;
749
843
  height?: number;
@@ -753,12 +847,19 @@ type PersistedState = {
753
847
  listHeight?: number | null;
754
848
  drawerHeight?: number | null;
755
849
  dock?: DevtoolsDock;
850
+ reservesSpace?: boolean;
756
851
  floatRect?: FloatRect;
757
852
  floatParked?: boolean;
758
853
  activeTab?: DevtoolsTab;
759
854
  detailTab?: DetailTab;
760
855
  selectedClientName?: string | null;
761
856
  selectedQueryId?: string | null;
857
+ stackSelectedQueryId?: string | null;
858
+ sequenceSelectedQueryId?: string | null;
859
+ batchSelectedQueryId?: string | null;
860
+ eventSelectedQueryId?: string | null;
861
+ formSelectedQueryId?: string | null;
862
+ timelineSelectedQueryId?: string | null;
762
863
  selectedFormId?: string | null;
763
864
  inspectFilterIds?: string[] | null;
764
865
  queryFilter?: string;
@@ -771,6 +872,7 @@ type PersistedState = {
771
872
  socketFilter?: string;
772
873
  jsonSearch?: string;
773
874
  expandedSteps?: string[];
875
+ expandedBatchItems?: string[];
774
876
  expandedQueryGroups?: string[];
775
877
  jsonExpanded?: string[];
776
878
  jsonCollapsed?: string[];
@@ -821,6 +923,7 @@ declare class QueryDevtoolsComponent implements OnInit {
821
923
  private destroyRef;
822
924
  private document;
823
925
  private viewport;
926
+ private isDocumentVisible;
824
927
  /**
825
928
  * Opens the panel as soon as it is created, whatever the stored view state says. Set by
826
929
  * `<et-query-devtools-lazy>`, which downloads the panel on the click that was meant to open it.
@@ -842,6 +945,9 @@ declare class QueryDevtoolsComponent implements OnInit {
842
945
  } | {
843
946
  id: "sequences";
844
947
  label: string;
948
+ } | {
949
+ id: "batches";
950
+ label: string;
845
951
  } | {
846
952
  id: "forms";
847
953
  label: string;
@@ -854,6 +960,9 @@ declare class QueryDevtoolsComponent implements OnInit {
854
960
  } | {
855
961
  id: "cache";
856
962
  label: string;
963
+ } | {
964
+ id: "locks";
965
+ label: string;
857
966
  } | {
858
967
  id: "timeline";
859
968
  label: string;
@@ -920,7 +1029,7 @@ declare class QueryDevtoolsComponent implements OnInit {
920
1029
  protected drawerWidth: WritableSignal<number | null>;
921
1030
  protected listHeight: WritableSignal<number | null>;
922
1031
  protected drawerHeight: WritableSignal<number | null>;
923
- protected drag: WritableSignal<ResizeDrag | null>;
1032
+ private drag;
924
1033
  protected resizing: _angular_core.Signal<boolean>;
925
1034
  /** Which edge the panel is docked to, or `float` for a window of its own inside the page. */
926
1035
  protected dock: WritableSignal<DevtoolsDock>;
@@ -956,6 +1065,11 @@ declare class QueryDevtoolsComponent implements OnInit {
956
1065
  readonly label: "Pop out";
957
1066
  readonly hint: "Move the panel into a window of its own - the same live panel, on your other screen";
958
1067
  }>;
1068
+ /**
1069
+ * Whether a docked panel takes its size out of the page instead of covering it - so the last rows of a
1070
+ * long page can still be scrolled to. Only docks can: a float sits wherever it was dragged.
1071
+ */
1072
+ protected reservesSpace: WritableSignal<boolean>;
959
1073
  /** Where the floating panel sits and how big it is. Kept while docked, so a return to float restores it. */
960
1074
  private floatRect;
961
1075
  /** The rect a resize gesture started from, or `null` outside one. */
@@ -993,6 +1107,20 @@ declare class QueryDevtoolsComponent implements OnInit {
993
1107
  /** The floating panel's offset from the viewport's top-left, or `null` while it is docked. */
994
1108
  protected panelInsetBlock: _angular_core.Signal<number | null>;
995
1109
  protected panelInsetInline: _angular_core.Signal<number | null>;
1110
+ /**
1111
+ * The panel's rendered size, not its dragged one - the stylesheet clamps a dock (`min-block-size`,
1112
+ * `max-block-size: 90vh`) and it is the clamped size the page has to give up.
1113
+ */
1114
+ private panelSize;
1115
+ /** Which padding a docked panel asks of the page and how much, or `null` when it asks for none. */
1116
+ private pageReservation;
1117
+ /**
1118
+ * The viewport edge a docked panel covers, reserved for overlays whatever {@link reservesSpace} says:
1119
+ * page content can be scrolled out from under the panel, a dialog or a menu cannot. A dock edge is
1120
+ * logical, so which physical edge a side dock covers flips in RTL - read from the panel, since the
1121
+ * writing direction cannot change under a dock switch.
1122
+ */
1123
+ private overlayReservation;
996
1124
  /** Which section of the query detail is showing. Shared by the Queries tab and both drawers. */
997
1125
  detailTab: WritableSignal<DetailTab>;
998
1126
  selectedClientName: WritableSignal<string | null>;
@@ -1001,6 +1129,8 @@ declare class QueryDevtoolsComponent implements OnInit {
1001
1129
  selectedFormId: WritableSignal<string | null>;
1002
1130
  stackSelectedQueryId: WritableSignal<string | null>;
1003
1131
  sequenceSelectedQueryId: WritableSignal<string | null>;
1132
+ batchSelectedQueryId: WritableSignal<string | null>;
1133
+ eventSelectedQueryId: WritableSignal<string | null>;
1004
1134
  formSelectedQueryId: WritableSignal<string | null>;
1005
1135
  timelineSelectedQueryId: WritableSignal<string | null>;
1006
1136
  /** Free-text narrowing of the Queries list. Every whitespace-separated term has to match. */
@@ -1046,6 +1176,8 @@ declare class QueryDevtoolsComponent implements OnInit {
1046
1176
  private socketEmitError;
1047
1177
  /** Keys (`<entryId>:<stepIndex>`) of the sequence steps whose in/out detail is expanded. */
1048
1178
  private expandedSteps;
1179
+ /** Keys (`<entryId>:<itemIndex>`) of the batch items whose args/response detail is expanded. */
1180
+ private expandedBatchItems;
1049
1181
  /** Keys of the Queries-list groups the user opened - the tab is rebuilt on every switch back. */
1050
1182
  expandedQueryGroups: WritableSignal<ReadonlySet<string>>;
1051
1183
  /** Shared value-explorer search term. */
@@ -1088,9 +1220,19 @@ declare class QueryDevtoolsComponent implements OnInit {
1088
1220
  private copiedReset$;
1089
1221
  /** 1-second tick driving the cache freshness countdowns. */
1090
1222
  private clock;
1223
+ /**
1224
+ * The probe lock behind every Locks row's "this tab" answer, and the last snapshot read through it.
1225
+ * Both only exist while the Locks tab is on screen - see the polling stream in the constructor.
1226
+ */
1227
+ private probeLocks;
1228
+ private probeId;
1229
+ private probeHold;
1230
+ private lockSnapshot;
1231
+ lockRows: _angular_core.Signal<DevtoolsLockRow[] | null>;
1091
1232
  /** "Inspect" mode: hover the live UI to find the query that a component created. */
1092
1233
  protected inspectActive: WritableSignal<boolean>;
1093
- protected inspectHover: WritableSignal<{
1234
+ /** @internal */
1235
+ inspectHover: WritableSignal<{
1094
1236
  rect: DOMRect;
1095
1237
  entries: QueryDevtoolsEntry[];
1096
1238
  } | null>;
@@ -1110,6 +1252,7 @@ declare class QueryDevtoolsComponent implements OnInit {
1110
1252
  protected panelTampered: _angular_core.Signal<boolean>;
1111
1253
  stackEntries: _angular_core.Signal<QueryDevtoolsEntry[]>;
1112
1254
  sequenceEntries: _angular_core.Signal<QueryDevtoolsEntry[]>;
1255
+ batchEntries: _angular_core.Signal<QueryDevtoolsEntry[]>;
1113
1256
  formEntries: _angular_core.Signal<QueryDevtoolsEntry[]>;
1114
1257
  authEntries: _angular_core.Signal<QueryDevtoolsEntry[]>;
1115
1258
  wsEntries: _angular_core.Signal<QueryDevtoolsEntry[]>;
@@ -1167,6 +1310,9 @@ declare class QueryDevtoolsComponent implements OnInit {
1167
1310
  } | {
1168
1311
  id: "sequences";
1169
1312
  label: string;
1313
+ } | {
1314
+ id: "batches";
1315
+ label: string;
1170
1316
  } | {
1171
1317
  id: "forms";
1172
1318
  label: string;
@@ -1179,6 +1325,9 @@ declare class QueryDevtoolsComponent implements OnInit {
1179
1325
  } | {
1180
1326
  id: "cache";
1181
1327
  label: string;
1328
+ } | {
1329
+ id: "locks";
1330
+ label: string;
1182
1331
  } | {
1183
1332
  id: "timeline";
1184
1333
  label: string;
@@ -1205,6 +1354,9 @@ declare class QueryDevtoolsComponent implements OnInit {
1205
1354
  } | {
1206
1355
  id: "sequences";
1207
1356
  label: string;
1357
+ } | {
1358
+ id: "batches";
1359
+ label: string;
1208
1360
  } | {
1209
1361
  id: "forms";
1210
1362
  label: string;
@@ -1217,6 +1369,9 @@ declare class QueryDevtoolsComponent implements OnInit {
1217
1369
  } | {
1218
1370
  id: "cache";
1219
1371
  label: string;
1372
+ } | {
1373
+ id: "locks";
1374
+ label: string;
1220
1375
  } | {
1221
1376
  id: "timeline";
1222
1377
  label: string;
@@ -1245,6 +1400,14 @@ declare class QueryDevtoolsComponent implements OnInit {
1245
1400
  entry: QueryDevtoolsEntry;
1246
1401
  query: AnyQuery;
1247
1402
  } | null>;
1403
+ batchSelectedQuery: _angular_core.Signal<{
1404
+ entry: QueryDevtoolsEntry;
1405
+ query: AnyQuery;
1406
+ } | null>;
1407
+ eventSelectedQuery: _angular_core.Signal<{
1408
+ entry: QueryDevtoolsEntry;
1409
+ query: AnyQuery;
1410
+ } | null>;
1248
1411
  formSelectedQuery: _angular_core.Signal<{
1249
1412
  entry: QueryDevtoolsEntry;
1250
1413
  query: AnyQuery;
@@ -1371,7 +1534,20 @@ declare class QueryDevtoolsComponent implements OnInit {
1371
1534
  * query) never writes them to its own `args` signal - only the `withArgs` feature does - so the args
1372
1535
  * its current request was built from stand in.
1373
1536
  */
1374
- queryArgs(query: AnyQuery): Omit<any, "response"> | null;
1537
+ queryArgs(query: AnyQuery): Omit<any, "response" | "rawResponse"> | null;
1538
+ /**
1539
+ * The headers a query's request carries, as a plain `name: value` record, or `null` for a query that
1540
+ * has none the panel can read. The set the last run sent, so it stays readable after the token it
1541
+ * used was replaced; for a query that has not run, what its current args and its client resolve to
1542
+ * now. `null` while a header provider throws - a secure query's needs an access token.
1543
+ *
1544
+ * The args tree cannot answer this on its own: a `withArgs` query reads its args from the feature's
1545
+ * source, which the secure `Authorization` provider is never written back to, and client-level
1546
+ * headers are merged in per execution rather than being part of the args at all.
1547
+ */
1548
+ requestHeaders(query: AnyQuery): {
1549
+ [k: string]: string;
1550
+ } | null;
1375
1551
  queryStatus(query: AnyQuery): QueryStatus;
1376
1552
  /**
1377
1553
  * A request in flight is already refreshing, so reporting it as stale on top of `loading` is noise -
@@ -1547,6 +1723,7 @@ declare class QueryDevtoolsComponent implements OnInit {
1547
1723
  asStack(entry: QueryDevtoolsEntry): AnyQueryStack;
1548
1724
  asPagedStack(entry: QueryDevtoolsEntry): AnyPagedQueryStack;
1549
1725
  asSequence(entry: QueryDevtoolsEntry): QuerySequence<unknown[]>;
1726
+ asBatch(entry: QueryDevtoolsEntry): AnyQueryBatch;
1550
1727
  asAuth(entry: QueryDevtoolsEntry): AnyBearerAuthProvider;
1551
1728
  asWs(entry: QueryDevtoolsEntry): WebSocketDevtoolsHandle;
1552
1729
  /**
@@ -1591,11 +1768,13 @@ declare class QueryDevtoolsComponent implements OnInit {
1591
1768
  authTokenPayload(auth: AnyBearerAuthProvider): Record<string, unknown> | null;
1592
1769
  queriesForStack(stack: AnyQueryStack | AnyPagedQueryStack): QueryLink[];
1593
1770
  authQueryKeys(auth: AnyBearerAuthProvider): string[];
1771
+ /** Where this tab stands on one lock, as a chip. @see lockRows */
1772
+ lockStanding(row: DevtoolsLockRow): QueryDevtoolsChip;
1594
1773
  /**
1595
1774
  * Which tab refreshes this provider's tokens, as a chip: whether it is this one, how many tabs are
1596
1775
  * in the election, and - when there is no election - why every tab reads as the leader.
1597
1776
  */
1598
- authLeadership(auth: AnyBearerAuthProvider): QueryDevtoolsLeadership | null;
1777
+ authLeadership(auth: AnyBearerAuthProvider): QueryDevtoolsChip | null;
1599
1778
  /**
1600
1779
  * The access token's expiry as the app sees it, plus whatever the panel is doing to it: an armed
1601
1780
  * lifetime replaces the countdown, and the token's own is reported next to it so the card never claims
@@ -1609,6 +1788,19 @@ declare class QueryDevtoolsComponent implements OnInit {
1609
1788
  expandQueryGroup(key: string): void;
1610
1789
  isStepExpanded(entryId: string, index: number): boolean;
1611
1790
  toggleStep(entryId: string, index: number): void;
1791
+ /** A batch's route with its path params left as `:name` - a batch fills them in per item, not once. */
1792
+ batchRouteSegments(entry: QueryDevtoolsEntry): RouteSegment[];
1793
+ batchOf(entry: QueryDevtoolsEntry): QueryDevtoolsEntry | null;
1794
+ queriesForBatch(entry: QueryDevtoolsEntry): QueryLink[];
1795
+ /**
1796
+ * The registry entry of one of a batch's items, or `null` once it has fallen out of the batch's capped
1797
+ * tombstone tail - which is what makes an item row openable only while its query is still kept.
1798
+ */
1799
+ batchItemQueryId(entry: QueryDevtoolsEntry, index: number): string | null;
1800
+ batchItems(entry: QueryDevtoolsEntry): BatchItemView;
1801
+ batchThroughput(batch: AnyQueryBatch): string | null;
1802
+ isBatchItemExpanded(entryId: string, index: number): boolean;
1803
+ toggleBatchItem(entryId: string, index: number): void;
1612
1804
  /** Dedents a GraphQL document (template-literal indentation) for readable display. */
1613
1805
  gqlDocument(doc: string): string;
1614
1806
  featureLabel(type: string): string;
@@ -1634,6 +1826,24 @@ declare class QueryDevtoolsComponent implements OnInit {
1634
1826
  content: string;
1635
1827
  type: string;
1636
1828
  }): void;
1829
+ /**
1830
+ * The headers an execution of this request would resolve to now: the client's with the per-request
1831
+ * ones merged on top, providers called. `undefined` when a provider throws, which for a secure query
1832
+ * means no access token is available yet.
1833
+ */
1834
+ private resolvedHeaders;
1835
+ /**
1836
+ * The same route rendered from a set of args rather than from a query, which is what a batch item leaves
1837
+ * behind: the batch destroys its query the moment the item settles.
1838
+ */
1839
+ private argsRouteSegments;
1840
+ private renderRoute;
1841
+ /**
1842
+ * Takes - or gives back - the lock whose name only this tab can have produced. Its `clientId` in the
1843
+ * snapshot is what tells this tab's rows from another tab's: `LockInfo` carries no tab identity, and
1844
+ * the platform offers no way to ask for one's own client id.
1845
+ */
1846
+ private holdProbeLock;
1637
1847
  /**
1638
1848
  * The two runs the diff compares, oldest first - normalised by run index, so picking a pair in either
1639
1849
  * order reads the same way round as the `#before → #after` header prints it.
@@ -1720,6 +1930,7 @@ declare class QueryDevtoolsComponent implements OnInit {
1720
1930
  private sessionQuery;
1721
1931
  private sessionActivity;
1722
1932
  private sessionSequence;
1933
+ private sessionBatch;
1723
1934
  private sessionForm;
1724
1935
  /**
1725
1936
  * An auth provider without its tokens. A session report is a file that gets attached to a ticket, and
@@ -1771,7 +1982,7 @@ declare class QueryDevtoolsComponent implements OnInit {
1771
1982
  declare const QUERY_DEVTOOLS_IMPORTS: readonly [typeof QueryDevtoolsComponent];
1772
1983
 
1773
1984
  /** The version of `@ethlete/query-devtools` this build was cut from. */
1774
- declare const QUERY_DEVTOOLS_VERSION = "1.0.0-next.0";
1985
+ declare const QUERY_DEVTOOLS_VERSION = "1.0.0-next.10";
1775
1986
 
1776
1987
  export { QUERY_DEVTOOLS_IMPORTS, QUERY_DEVTOOLS_VERSION, QueryDevtoolsAboutComponent, QueryDevtoolsComponent, QueryDevtoolsJsonComponent, QueryDevtoolsJsonStylesComponent, QueryDevtoolsSettingsComponent, QueryDevtoolsTimelineStylesComponent, clampFloatToPeek, kindOf, resizedFloatRect, settledFloatRect };
1777
1988
  export type { JsonKind };