@ethlete/query 6.0.0-next.18 → 6.0.0-next.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @ethlete/query
2
2
 
3
+ ## 6.0.0-next.19
4
+
5
+ ### Minor Changes
6
+
7
+ - [#3036](https://github.com/ethlete-io/ethdk/pull/3036) [`aa4bdde`](https://github.com/ethlete-io/ethdk/commit/aa4bdde586615ed13735ed9c970831b91323ebad) Thanks [@github-actions](https://github.com/apps/github-actions)! - Query devtools: add `provideQueryDevtools()` and a registry that instruments
8
+ queries, query stacks, paged query stacks, `querySequence`, bearer auth providers
9
+ and web socket clients so they can be inspected by `<et-query-devtools>` (from
10
+ `@ethlete/components`). Instrumentation is a no-op unless the provider is added,
11
+ so there is no overhead when it is omitted.
12
+
13
+ Supporting devtools APIs added: `querySequence` exposes a `stepArgs` signal (the
14
+ resolved input args of each step); the query repository gains
15
+ `subtle.cacheEntries()` / `subtle.cacheVersion` / `subtle.evict()`; queries gain
16
+ `subtle.setLoading()` / `subtle.setError()` (force UI states for testing);
17
+ `HttpRequest` exposes `method`, `url` and `expiresAt`; `QueryClient` exposes its
18
+ `baseUrl`; `QuerySequence` exposes its step `queries`; and web socket clients
19
+ expose a devtools handle (connection state, rooms, recent messages).
20
+
3
21
  ## 6.0.0-next.18
4
22
 
5
23
  ### Minor Changes
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { isDevMode, DestroyRef, InjectionToken, inject, Injector, EnvironmentInjector, ErrorHandler, createEnvironmentInjector, effect, untracked, signal, linkedSignal, computed, runInInjectionContext, assertInInjectionContext, ChangeDetectorRef, ViewContainerRef, TemplateRef, Input, Directive, ElementRef, input, Pipe, ViewEncapsulation, Component, resource, DOCUMENT, NgZone } from '@angular/core';
2
+ import { signal, isDevMode, makeEnvironmentProviders, DestroyRef, InjectionToken, inject, Injector, EnvironmentInjector, ElementRef, ErrorHandler, createEnvironmentInjector, effect, untracked, linkedSignal, computed, runInInjectionContext, assertInInjectionContext, ChangeDetectorRef, ViewContainerRef, TemplateRef, Input, Directive, input, Pipe, ViewEncapsulation, Component, resource, DOCUMENT, NgZone } from '@angular/core';
3
3
  import { createStaticProvider, RuntimeError, clamp, createDestroy, computedTillTruthy, getCookie, setCookie, deleteCookie, createProvider, nextFrame, randomId, createRootProvider, isObject, injectRoute, getDomain, injectQueryParamChanges, injectQueryParams, clone, equal, ET_PROPERTY_REMOVED, previousSignalValue } from '@ethlete/core';
4
4
  import { filter, Subject, Subscription, Observable, tap, retry, throwError, timer, catchError, takeUntil, startWith, pairwise, switchMap, of, BehaviorSubject, fromEvent, take, ReplaySubject, map, shareReplay, interval, skip, takeWhile, combineLatest, EMPTY, withLatestFrom, debounceTime, firstValueFrom, merge, throttleTime } from 'rxjs';
5
5
  import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
@@ -12,6 +12,126 @@ import { validateAsync } from '@angular/forms/signals';
12
12
  import { Router, ActivatedRoute } from '@angular/router';
13
13
  import { io } from 'socket.io-client';
14
14
 
15
+ const noop = () => undefined;
16
+ let devtoolsEnabled = false;
17
+ /**
18
+ * Whether {@link provideQueryDevtools} has been called. When `false`, every `register*` call is a
19
+ * no-op so the devtools instrumentation retains no references and adds no overhead in production.
20
+ * @internal
21
+ */
22
+ const isQueryDevtoolsEnabled = () => devtoolsEnabled;
23
+ const entries = signal([], /* @ts-ignore */
24
+ ...(ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []));
25
+ /**
26
+ * The reactive list of every registered devtools entry, consumed by the `<et-query-devtools>` UI.
27
+ */
28
+ const queryDevtoolsEntries = entries.asReadonly();
29
+ // Per-descriptor counter used to derive stable, reload-deterministic ids. Reset on page load (module
30
+ // re-eval), so the same queries created in the same order get the same ids across reloads — which is
31
+ // what lets the devtools restore the selected query after a reload.
32
+ const idCounters = new Map();
33
+ const descriptorOf = (entry) => {
34
+ const { kind, meta } = entry;
35
+ if (kind === 'query')
36
+ return `query|${meta.clientName ?? ''}|${meta.method ?? ''}|${meta.route ?? ''}`;
37
+ if (kind === 'auth-provider')
38
+ return `auth-provider|${meta.name ?? ''}`;
39
+ if (kind === 'ws-client')
40
+ return `ws-client|${meta.name ?? ''}`;
41
+ return kind;
42
+ };
43
+ /**
44
+ * Registers an entry with the devtools registry. Returns an unregister callback. A no-op (returning
45
+ * a no-op callback) unless {@link provideQueryDevtools} has been called.
46
+ *
47
+ * Ids are derived deterministically from a stable descriptor + a per-descriptor sequence number, so
48
+ * they survive a page reload (letting the UI restore the selected entry) instead of being random.
49
+ * @internal
50
+ */
51
+ const registerQueryDevtoolsEntry = (entry) => {
52
+ if (!devtoolsEnabled)
53
+ return noop;
54
+ let id = entry.id;
55
+ if (!id) {
56
+ const descriptor = descriptorOf(entry);
57
+ const seq = idCounters.get(descriptor) ?? 0;
58
+ idCounters.set(descriptor, seq + 1);
59
+ id = `${descriptor}#${seq}`;
60
+ }
61
+ const fullEntry = { ...entry, id, createdAt: Date.now() };
62
+ entries.update((list) => [...list, fullEntry]);
63
+ return () => entries.update((list) => list.filter((e) => e.id !== fullEntry.id));
64
+ };
65
+ let suppressStackRegistration = false;
66
+ /**
67
+ * Suppresses devtools registration for the next {@link createQueryStack} call. Used by
68
+ * `createPagedQueryStack` so its backing stack is not registered as a separate `query-stack` entry.
69
+ * @internal
70
+ */
71
+ const suppressNextQueryStackDevtools = () => {
72
+ suppressStackRegistration = true;
73
+ };
74
+ /**
75
+ * Reads and clears the suppress-next-stack flag. Always call this from `createQueryStack` (even when
76
+ * devtools are disabled) so a suppression request never leaks into a later stack.
77
+ * @internal
78
+ */
79
+ const consumeSuppressQueryStackDevtools = () => {
80
+ const value = suppressStackRegistration;
81
+ suppressStackRegistration = false;
82
+ return value;
83
+ };
84
+ /**
85
+ * Stringifies a query creator route. Function routes are invoked with an empty args object and any
86
+ * resulting `undefined` path segments are rendered as `:param`, matching the legacy devtools.
87
+ * @internal
88
+ */
89
+ const stringifyQueryRoute = (route) => {
90
+ if (route === undefined || route === null)
91
+ return '';
92
+ try {
93
+ if (typeof route === 'function') {
94
+ return route({}).replace(/undefined/g, ':param');
95
+ }
96
+ return String(route);
97
+ }
98
+ catch {
99
+ return typeof route === 'function' ? '(dynamic route)' : String(route);
100
+ }
101
+ };
102
+ /**
103
+ * Extracts the human readable client name from a query client tuple. The client's DI token is named
104
+ * `QueryClient_<name>`, so we strip the prefix to recover the original name.
105
+ * @internal
106
+ */
107
+ const getQueryClientName = (client) => {
108
+ const token = client[2];
109
+ const desc = token?.toString?.() ?? '';
110
+ return desc.replace('InjectionToken ', '').replace('QueryClient_', '') || 'unknown';
111
+ };
112
+ /**
113
+ * Enables the `@ethlete/query` devtools. Add this to your application providers (e.g. in
114
+ * `bootstrapApplication`) to make query clients, queries, stacks, sequences and auth providers
115
+ * appear in the `<et-query-devtools>` panel.
116
+ *
117
+ * When omitted, all devtools instrumentation is a no-op — no references are retained and there is no
118
+ * runtime overhead — so it is safe to leave out of production builds.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * bootstrapApplication(AppComponent, {
123
+ * providers: [provideQueryDevtools()],
124
+ * });
125
+ * ```
126
+ */
127
+ const provideQueryDevtools = () => {
128
+ devtoolsEnabled = true;
129
+ if (!isDevMode()) {
130
+ 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.');
131
+ }
132
+ return makeEnvironmentProviders([]);
133
+ };
134
+
15
135
  const getOpName = /(query|mutation) ?([\w\d-_]+)? ?\(.*?\)? \{/;
16
136
  const transformGql = (str) => {
17
137
  const normalizedStr = Array.isArray(str) ? str.join('') : str;
@@ -133,6 +253,7 @@ const setupQueryDependencies = (options) => {
133
253
  injector: undefined, // Will be set after injector creation
134
254
  ngErrorHandler: hostInjector.get(ErrorHandler),
135
255
  httpClient: hostInjector.get(HttpClient),
256
+ hostElement: hostInjector.get(ElementRef, null, { optional: true })?.nativeElement ?? null,
136
257
  };
137
258
  const queryContext = {
138
259
  deps: dependencies,
@@ -657,6 +778,8 @@ const createQueryObject = (options) => {
657
778
  const { state, execute, deps } = options;
658
779
  const destroy = () => deps.injector.destroy();
659
780
  const setResponse = (response) => state.rawResponse.set(response);
781
+ const setLoading = (loading) => state.loading.set(loading);
782
+ const setError = (error) => state.error.set(error);
660
783
  const createSnapshot = createQuerySnapshotFn({ state, execute, deps });
661
784
  // Pre-wrap all public signals once so both `query` and `roQuery` share the same instances.
662
785
  const wrappedArgs = wrapAsObservableSignal(state.args.asReadonly(), deps.injector);
@@ -701,6 +824,8 @@ const createQueryObject = (options) => {
701
824
  subtle: {
702
825
  destroy,
703
826
  setResponse,
827
+ setLoading,
828
+ setError,
704
829
  request: wrappedRequest,
705
830
  destroyRef: deps.scopeDestroyRef,
706
831
  injector: deps.injector,
@@ -734,7 +859,28 @@ const createBaseQuery = (options) => {
734
859
  };
735
860
  applyQueryFeatures(options.features, featureFnContext);
736
861
  maybeExecute({ execute, flags });
737
- return createQueryObject({ state, execute, deps });
862
+ const query = createQueryObject({ state, execute, deps });
863
+ if (isQueryDevtoolsEnabled()) {
864
+ const unregister = registerQueryDevtoolsEntry({
865
+ kind: 'query',
866
+ handle: query,
867
+ meta: {
868
+ clientName: getQueryClientName(client),
869
+ clientBaseUrl: deps.client.baseUrl,
870
+ route: stringifyQueryRoute(options.creatorInternals.route ??
871
+ options.creator?.route),
872
+ method: flags.method,
873
+ featureTypes: options.features.map((f) => f.type),
874
+ queryConfig: options.queryConfig,
875
+ creator: options.creator,
876
+ repository: deps.client.repository,
877
+ element: deps.hostElement,
878
+ gqlQuery: options.creatorInternals.query,
879
+ },
880
+ });
881
+ deps.destroyRef.onDestroy(unregister);
882
+ }
883
+ return query;
738
884
  });
739
885
  };
740
886
 
@@ -1718,6 +1864,8 @@ const createHttpRequest = (options) => {
1718
1864
  loading.set(state);
1719
1865
  };
1720
1866
  const httpRequest = {
1867
+ method: options.method,
1868
+ url: options.fullPath,
1721
1869
  execute,
1722
1870
  destroy,
1723
1871
  loading: loading.asReadonly(),
@@ -1726,6 +1874,7 @@ const createHttpRequest = (options) => {
1726
1874
  currentEvent: currentEvent.asReadonly(),
1727
1875
  events$: event$.asObservable(),
1728
1876
  isStale,
1877
+ expiresAt: expiresIn.asReadonly(),
1729
1878
  };
1730
1879
  return httpRequest;
1731
1880
  };
@@ -1886,6 +2035,17 @@ const createQueryStack = (options) => {
1886
2035
  runWithArgs,
1887
2036
  },
1888
2037
  };
2038
+ const skipDevtools = consumeSuppressQueryStackDevtools();
2039
+ if (isQueryDevtoolsEnabled() && !skipDevtools) {
2040
+ const unregister = registerQueryDevtoolsEntry({
2041
+ kind: 'query-stack',
2042
+ handle: stack,
2043
+ meta: {
2044
+ featureTypes: features.map((f) => f.type),
2045
+ },
2046
+ });
2047
+ inject(DestroyRef).onDestroy(unregister);
2048
+ }
1889
2049
  return stack;
1890
2050
  };
1891
2051
 
@@ -1958,6 +2118,7 @@ const createPagedQueryStack = (options) => {
1958
2118
  ...(ngDevMode ? [{ debugName: "resetTrigger" }] : /* istanbul ignore next */ []));
1959
2119
  const pageDirection = signal('next', /* @ts-ignore */
1960
2120
  ...(ngDevMode ? [{ debugName: "pageDirection" }] : /* istanbul ignore next */ []));
2121
+ suppressNextQueryStackDevtools();
1961
2122
  const stack = createQueryStack({
1962
2123
  args: () => null,
1963
2124
  queryCreator,
@@ -2165,6 +2326,16 @@ const createPagedQueryStack = (options) => {
2165
2326
  reset,
2166
2327
  execute,
2167
2328
  };
2329
+ if (isQueryDevtoolsEnabled()) {
2330
+ const unregister = registerQueryDevtoolsEntry({
2331
+ kind: 'paged-query-stack',
2332
+ handle: pagedQuery,
2333
+ meta: {
2334
+ featureTypes: features?.map((f) => f.type),
2335
+ },
2336
+ });
2337
+ inject(DestroyRef).onDestroy(unregister);
2338
+ }
2168
2339
  return pagedQuery;
2169
2340
  };
2170
2341
 
@@ -5285,6 +5456,11 @@ const generateUuid = () => randomId();
5285
5456
  const createQueryRepository = (config) => {
5286
5457
  const cache = new Map();
5287
5458
  const eventsSubject = new Subject();
5459
+ // Bumped on every cache mutation so the devtools cache view can react. Cheap enough to keep
5460
+ // unconditional — it is a single integer signal with no readers unless the devtools are open.
5461
+ const cacheVersion = signal(0, /* @ts-ignore */
5462
+ ...(ngDevMode ? [{ debugName: "cacheVersion" }] : /* istanbul ignore next */ []));
5463
+ const bumpCacheVersion = () => cacheVersion.update((v) => v + 1);
5288
5464
  const request = (options) => {
5289
5465
  const { args, creatorOptions, runQueryOptions } = options;
5290
5466
  const shouldCache = creatorOptions?.subtle?.useQueryRepositoryCache === false
@@ -5349,6 +5525,7 @@ const createQueryRepository = (config) => {
5349
5525
  cacheEntry.eventSubscription?.unsubscribe();
5350
5526
  cache.delete(key);
5351
5527
  }
5528
+ bumpCacheVersion();
5352
5529
  return true;
5353
5530
  };
5354
5531
  const unbindAllSecure = () => {
@@ -5361,6 +5538,7 @@ const createQueryRepository = (config) => {
5361
5538
  cache.delete(key);
5362
5539
  }
5363
5540
  }
5541
+ bumpCacheVersion();
5364
5542
  };
5365
5543
  const bind = (key, consumerDestroyRef, request, isSecure, allowReuse) => {
5366
5544
  const destroyListener = consumerDestroyRef.onDestroy(() => unbind(key, consumerDestroyRef));
@@ -5391,12 +5569,33 @@ const createQueryRepository = (config) => {
5391
5569
  eventSubscription,
5392
5570
  });
5393
5571
  }
5572
+ bumpCacheVersion();
5573
+ };
5574
+ const cacheEntries = () => Array.from(cache.entries()).map(([key, entry]) => ({
5575
+ key,
5576
+ isSecure: entry.isSecure,
5577
+ consumerCount: entry.consumers.size,
5578
+ request: entry.request,
5579
+ }));
5580
+ const evict = (key) => {
5581
+ const entry = cache.get(key);
5582
+ if (!entry)
5583
+ return;
5584
+ entry.request.destroy();
5585
+ entry.eventSubscription?.unsubscribe();
5586
+ cache.delete(key);
5587
+ bumpCacheVersion();
5394
5588
  };
5395
5589
  const repository = {
5396
5590
  request,
5397
5591
  unbind,
5398
5592
  unbindAllSecure,
5399
5593
  events$: eventsSubject.asObservable(),
5594
+ subtle: {
5595
+ cacheEntries,
5596
+ cacheVersion: cacheVersion.asReadonly(),
5597
+ evict,
5598
+ },
5400
5599
  };
5401
5600
  return repository;
5402
5601
  };
@@ -5411,6 +5610,7 @@ const createQueryClient = (options) => createRootProvider(() => {
5411
5610
  });
5412
5611
  const client = {
5413
5612
  repository,
5613
+ baseUrl: options.baseUrl,
5414
5614
  };
5415
5615
  return client;
5416
5616
  }, {
@@ -5505,9 +5705,10 @@ const createSequenceState = () => ({
5505
5705
  error: signal(null),
5506
5706
  failedAt: signal(null),
5507
5707
  snapshots: signal([]),
5708
+ stepArgs: signal([]),
5508
5709
  responses: signal([]),
5509
5710
  });
5510
- const buildSequence = (steps, state) => {
5711
+ const buildSequence = (steps, state, devtoolsHandle) => {
5511
5712
  const run = async () => {
5512
5713
  if (state.running())
5513
5714
  throw querySequenceAlreadyRunning();
@@ -5517,13 +5718,17 @@ const buildSequence = (steps, state) => {
5517
5718
  state.error.set(null);
5518
5719
  state.failedAt.set(null);
5519
5720
  state.snapshots.set([]);
5721
+ state.stepArgs.set([]);
5520
5722
  state.responses.set([]);
5521
5723
  const snapshots = [];
5724
+ const stepArgs = [];
5522
5725
  const responses = [];
5523
5726
  let previousResponse = undefined;
5524
5727
  for (const [i, step] of steps.entries()) {
5525
5728
  state.currentStep.set(i + 1);
5526
5729
  const { args } = step.produceArgs(previousResponse, responses);
5730
+ stepArgs.push(args);
5731
+ state.stepArgs.set([...stepArgs]);
5527
5732
  const snapshot = await executeUntilSettled(step.query, { args });
5528
5733
  snapshots.push(snapshot);
5529
5734
  state.snapshots.set([...snapshots]);
@@ -5544,21 +5749,26 @@ const buildSequence = (steps, state) => {
5544
5749
  state.running.set(false);
5545
5750
  return { ok: true, responses: responses, snapshots };
5546
5751
  };
5547
- return {
5752
+ const sequence = {
5548
5753
  then: (query, mapArgs) => buildSequence([
5549
5754
  ...steps,
5550
5755
  { query, produceArgs: (previousResponse, responses) => mapArgs(previousResponse, responses) },
5551
- ], state),
5756
+ ], state, devtoolsHandle),
5552
5757
  status: state.status.asReadonly(),
5553
5758
  running: state.running.asReadonly(),
5554
5759
  currentStep: state.currentStep.asReadonly(),
5555
5760
  total: steps.length,
5761
+ queries: steps.map((s) => s.query),
5556
5762
  error: state.error.asReadonly(),
5557
5763
  failedAt: state.failedAt.asReadonly(),
5558
5764
  snapshots: state.snapshots.asReadonly(),
5765
+ stepArgs: state.stepArgs.asReadonly(),
5559
5766
  responses: state.responses.asReadonly(),
5560
5767
  run,
5561
5768
  };
5769
+ if (devtoolsHandle)
5770
+ devtoolsHandle.current = sequence;
5771
+ return sequence;
5562
5772
  };
5563
5773
  /**
5564
5774
  * Starts an imperative waterfall of dependent queries. Chain the remaining steps with `.then()`
@@ -5582,7 +5792,27 @@ const buildSequence = (steps, state) => {
5582
5792
  * }
5583
5793
  * ```
5584
5794
  */
5585
- const querySequence = (query, seedArgs) => buildSequence([{ query, produceArgs: () => seedArgs() }], createSequenceState());
5795
+ const querySequence = (query, seedArgs) => {
5796
+ const devtoolsHandle = isQueryDevtoolsEnabled()
5797
+ ? { current: null }
5798
+ : undefined;
5799
+ const seed = buildSequence([{ query, produceArgs: () => seedArgs() }], createSequenceState(), devtoolsHandle);
5800
+ if (devtoolsHandle) {
5801
+ const unregister = registerQueryDevtoolsEntry({
5802
+ kind: 'query-sequence',
5803
+ handle: devtoolsHandle,
5804
+ meta: {},
5805
+ });
5806
+ // Sequences have no destroy hook; tie cleanup to the creating scope when there is one.
5807
+ try {
5808
+ inject(DestroyRef).onDestroy(unregister);
5809
+ }
5810
+ catch {
5811
+ // Created outside an injection context — the entry lives for the app's lifetime.
5812
+ }
5813
+ }
5814
+ return seed;
5815
+ };
5586
5816
 
5587
5817
  /**
5588
5818
  * Binds a query-backed async validator to a signal-forms field, adapting an `@ethlete/query` v3
@@ -6213,7 +6443,7 @@ const createBearerAuthProviderImpl = (config) => {
6213
6443
  };
6214
6444
  const features = setupFeatures(config.features, featureSetupContext);
6215
6445
  setupMultiTabSyncIfEnabled(config, accessToken, refreshToken, queryClient);
6216
- return {
6446
+ const provider = {
6217
6447
  queries,
6218
6448
  features: features,
6219
6449
  accessToken: accessToken.asReadonly(),
@@ -6226,6 +6456,20 @@ const createBearerAuthProviderImpl = (config) => {
6226
6456
  logout,
6227
6457
  afterTokenRefresh$,
6228
6458
  };
6459
+ if (isQueryDevtoolsEnabled()) {
6460
+ const unregister = registerQueryDevtoolsEntry({
6461
+ kind: 'auth-provider',
6462
+ handle: provider,
6463
+ meta: {
6464
+ name: config.name,
6465
+ clientName: getQueryClientName(config.queryClientRef),
6466
+ clientBaseUrl: queryClient.baseUrl,
6467
+ repository: queryClient.repository,
6468
+ },
6469
+ });
6470
+ destroyRef.onDestroy(unregister);
6471
+ }
6472
+ return provider;
6229
6473
  };
6230
6474
  const createBearerAuthProvider = (config) => createRootProvider(() => createBearerAuthProviderImpl(config), { name: `BearerAuthProvider_${config.name}` });
6231
6475
 
@@ -7789,6 +8033,7 @@ const messageMalformed = () => {
7789
8033
  return new RuntimeError(WebSocketRuntimeErrorCode.MESSAGE_MALFORMED, 'A message has been received but it is malformed (cannot be parsed as JSON).');
7790
8034
  };
7791
8035
 
8036
+ const MAX_DEVTOOLS_MESSAGES = 100;
7792
8037
  const createWebSocketClient = (options) => {
7793
8038
  return createRootProvider(() => {
7794
8039
  const socket = io(options.url, {
@@ -7799,6 +8044,17 @@ const createWebSocketClient = (options) => {
7799
8044
  const rooms = new Map();
7800
8045
  const isConnected = signal(false, /* @ts-ignore */
7801
8046
  ...(ngDevMode ? [{ debugName: "isConnected" }] : /* istanbul ignore next */ []));
8047
+ // Devtools instrumentation (no-op unless provideQueryDevtools() was called).
8048
+ const devtoolsEnabled = isQueryDevtoolsEnabled();
8049
+ const devtoolsRooms = signal([], /* @ts-ignore */
8050
+ ...(ngDevMode ? [{ debugName: "devtoolsRooms" }] : /* istanbul ignore next */ []));
8051
+ const devtoolsMessages = signal([], /* @ts-ignore */
8052
+ ...(ngDevMode ? [{ debugName: "devtoolsMessages" }] : /* istanbul ignore next */ []));
8053
+ let devtoolsMessageId = 0;
8054
+ const syncDevtoolsRooms = () => {
8055
+ if (devtoolsEnabled)
8056
+ devtoolsRooms.set([...rooms.keys()]);
8057
+ };
7802
8058
  const joinRoom = (room) => {
7803
8059
  const roomFn = typeof room === 'function' ? room : () => room;
7804
8060
  const pre = previousSignalValue(computed(() => roomFn()));
@@ -7815,6 +8071,7 @@ const createWebSocketClient = (options) => {
7815
8071
  latestMessage: message,
7816
8072
  };
7817
8073
  rooms.set(name, newRoom);
8074
+ syncDevtoolsRooms();
7818
8075
  return newRoom;
7819
8076
  };
7820
8077
  effect(() => {
@@ -7851,6 +8108,7 @@ const createWebSocketClient = (options) => {
7851
8108
  }
7852
8109
  socket.emit('leave-room', room);
7853
8110
  rooms.delete(room);
8111
+ syncDevtoolsRooms();
7854
8112
  };
7855
8113
  const setupWebSocketConnectionListener = () => {
7856
8114
  socket.on('connect', () => {
@@ -7865,6 +8123,16 @@ const createWebSocketClient = (options) => {
7865
8123
  socket.onAny((data) => {
7866
8124
  try {
7867
8125
  const json = JSON.parse(data);
8126
+ if (devtoolsEnabled) {
8127
+ const message = {
8128
+ id: devtoolsMessageId++,
8129
+ timestamp: Date.now(),
8130
+ room: json.room,
8131
+ event: json.event,
8132
+ data: json.data,
8133
+ };
8134
+ devtoolsMessages.update((log) => [message, ...log].slice(0, MAX_DEVTOOLS_MESSAGES));
8135
+ }
7868
8136
  const room = rooms.get(json.room);
7869
8137
  if (room)
7870
8138
  room.latestMessage.set(json);
@@ -7887,6 +8155,19 @@ const createWebSocketClient = (options) => {
7887
8155
  leaveRoom,
7888
8156
  },
7889
8157
  };
8158
+ if (devtoolsEnabled) {
8159
+ const handle = {
8160
+ connected: isConnected.asReadonly(),
8161
+ rooms: devtoolsRooms.asReadonly(),
8162
+ messages: devtoolsMessages.asReadonly(),
8163
+ };
8164
+ const unregister = registerQueryDevtoolsEntry({
8165
+ kind: 'ws-client',
8166
+ handle,
8167
+ meta: { name: options.name, url: options.url },
8168
+ });
8169
+ inject(DestroyRef).onDestroy(unregister);
8170
+ }
7890
8171
  return client;
7891
8172
  }, {
7892
8173
  name: `WebSocketClient_${options.name}`,
@@ -7897,5 +8178,5 @@ const createWebSocketClient = (options) => {
7897
8178
  * Generated bundle index. Do not edit.
7898
8179
  */
7899
8180
 
7900
- export { BasicAuthProvider, BearerAuthFeatureType, BooleanArrayQueryField, CLEAR_QUERY_ARGS, CustomHeaderAuthProvider, DateArrayQueryField, DateQueryField, EntityStore, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, LegacyQuery, LegacyQueryCreator, NumberArrayQueryField, ParseHttpErrorCodeToMessageDePipe, ParseHttpErrorCodeToMessageEnPipe, ParseHttpErrorCodeToTitleDePipe, ParseHttpErrorCodeToTitleEnPipe, QUERY_CLIENT_DEVTOOLS_TOKEN, QueryDevtoolsComponent, QueryDirective, QueryError, QueryFeatureType, QueryField, QueryForm, QueryRuntimeErrorCode, QueryShortNamePipe, QueryStore, SERVER_ERROR_KIND, SERVER_VIOLATION_ERROR_KIND, SPEED_BUFFER_TIME_IN_MS, SearchQueryField, SortQueryField, StringArrayQueryField, V2BearerAuthProvider, V2Query, V2QueryClient, V2QueryCreator, addQueryContainerHandling, applyQueryFeatures, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, buildErrorMessage, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, contentfulGqlLikePaginationAdapter, createBaseQuery, createBaseQueryCreator, createBearerAuthProvider, createDeleteQuery, createExecuteFn, createGetQuery, createGqlExecuteFn, createGqlMutationViaGet, createGqlMutationViaPost, createGqlQuery, createGqlQueryCreator, createGqlQueryViaGet, createGqlQueryViaPost, createHttpRequest, createInfinityQueryConfig, createLegacyQueryCreator, createPagedQueryStack, createPatchQuery, createPersistentAuthFeature, createPostQuery, createPutQuery, createQuery, createQueryClient, createQueryCollection, createQueryCollectionSignal, createQueryCollectionSubject, createQueryContext, createQueryCreator, createQueryErrorResponse, createQueryFeature, createQueryObject, createQueryRepository, createQuerySnapshotFn, createQueryStack, createSecureDeleteQuery, createSecureExecuteFactory, createSecureExecuteFn, createSecureGetQuery, createSecureGqlExecuteFn, createSecureGqlMutationViaGet, createSecureGqlMutationViaPost, createSecureGqlQuery, createSecureGqlQueryCreator, createSecureGqlQueryViaGet, createSecureGqlQueryViaPost, createSecurePatchQuery, createSecurePostQuery, createSecurePutQuery, createSecureQuery, createSecureQueryCreator, createTrackingFeature, createWebSocketClient, decryptBearer, deepFreeze, def, detectContentTypeHeader, dynLikePaginationAdapter, effectComputed, ethletePaginationAdapter, executeUntilSettled, extractExpiresInSeconds, extractFormViolations, extractQuery, fakePaginationAdapter, filterFailure, filterNull, filterQueryStates, filterSuccess, forEachHeader, getDefaultHeaders, getQueryFeatureUsage, getResponseUrl, ggLikePaginationAdapter, gql, gqlDataPropertyMissingInResponse, hasHeader, ignoreAutoRefresh, injectInfinityQueryResponseDelay, injectQueryContext, insertFrom, invalidBaseRouteError, invalidBodyError, invalidRouteError, invalidStateInsideSecureExecuteFactory, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isClassValidatorError, isCreateGqlQueryOptions, isCustomHeaderAuthProvider, isEmptyString, isGqlQueryConfig, isLegacyQuery, isNaN$1 as isNaN, isQuery, isQueryCollection, isQueryErrorResponse, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyFormViolationListError, isSymfonyListError, isSymfonyPagerfantaOutOfRangeError, mapToPaginated, mapViolationsToFormErrors, maybeExecute, mergeHeaders, nestedEffect, pagedQueryStackNextPageCalledWithoutPreviousPage, pagedQueryStackPageBiggerThanTotalPages, pagedQueryStackPreviousPageCalledButAlreadyAtFirstPage, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, parseHttpErrorCodeToMessageDe, parseHttpErrorCodeToMessageEn, parseHttpErrorCodeToTitleDe, parseHttpErrorCodeToTitleEn, pathParamsMissingInRouteFunctionError, provideInfinityQueryResponseDelay, provideQueryClientForDevtools, queryArrayComputed, queryComputed, queryComputedTillTruthy, queryExecute, queryFeatureUsedMultipleTimes, querySequence, querySequenceAlreadyRunning, queryStackTotalQueriesAndExpectedQueriesMismatch, queryStackWithArgsUsed, queryStackWithResponseUpdateUsed, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, queryStateErrorSignal, queryStateLoadingSignal, queryStateResponseSignal, queryStateSignal, removeFrom, request, resetExecuteState, resetPageOnError, serializeBody, setupQueryDependencies, setupQueryExecuteState, setupQueryState, shouldAutoExecuteGqlQuery, shouldAutoExecuteQuery, shouldCacheQuery, shouldRetryRequest, silenceMissingWithArgsFeatureErrorUsedButWithArgsPresent, skipPaginationPageParamCalculator, splitQueryConfig, switchQueryCollectionState, switchQueryState, takeUntilResponse, toQuerySignal, toQuerySubject, tokensNotAvailableInsideAuthAndExec, transformArrayResponse, transformExecStateToQueryState, transformGql, transformMethod, transformPaginatedResponse, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray, uncacheableRequestHasAllowCacheParam, uncacheableRequestHasCacheKeyParam, v2BuildQueryCacheKey, v2ExtractExpiresInSeconds, v2ShouldCacheQuery, v2ShouldRetryRequest, validateWithQuery, validateWithV2Query, withArgs, withArgsQueryFeatureMissingButRouteIsFunction, withAuthenticationQuery, withAutoRefresh, withAutoRefreshUsedInManualQuery, withAutoRefreshUsedOnUnsupportedHttpMethod, withErrorHandling, withInactivityLogout, withLogging, withPersistentAuth, withPolling, withPollingUsedOnUnsupportedHttpMethod, withRefreshQuery, withResponseUpdate, withSuccessHandling, withTokenExpirationWarning, withTokenRevocation, withTracking, wrapAsObservableSignal };
8181
+ export { BasicAuthProvider, BearerAuthFeatureType, BooleanArrayQueryField, CLEAR_QUERY_ARGS, CustomHeaderAuthProvider, DateArrayQueryField, DateQueryField, EntityStore, INFINITY_QUERY_TOKEN, InfinityQuery, InfinityQueryDirective, InfinityQueryTriggerDirective, LegacyQuery, LegacyQueryCreator, NumberArrayQueryField, ParseHttpErrorCodeToMessageDePipe, ParseHttpErrorCodeToMessageEnPipe, ParseHttpErrorCodeToTitleDePipe, ParseHttpErrorCodeToTitleEnPipe, QUERY_CLIENT_DEVTOOLS_TOKEN, QueryDevtoolsComponent, QueryDirective, QueryError, QueryFeatureType, QueryField, QueryForm, QueryRuntimeErrorCode, QueryShortNamePipe, QueryStore, SERVER_ERROR_KIND, SERVER_VIOLATION_ERROR_KIND, SPEED_BUFFER_TIME_IN_MS, SearchQueryField, SortQueryField, StringArrayQueryField, V2BearerAuthProvider, V2Query, V2QueryClient, V2QueryCreator, addQueryContainerHandling, applyQueryFeatures, authExtractTokensResponseMissingAccessToken, authExtractTokensResponseMissingRefreshToken, authExtractTokensResponseNotObject, authProviderFeatureUsedMultipleTimes, buildErrorMessage, buildQueryCacheKey, buildQueryString, buildRoute, buildTimestampFromSeconds, castQueryCreatorTypes, circularQueryDependency, circularQueryDependencyChecker, computeQueryAuthHeader, computeQueryBody, computeQueryHeaders, computeQueryMethod, computeQueryQueryParams, consumeSuppressQueryStackDevtools, contentfulGqlLikePaginationAdapter, createBaseQuery, createBaseQueryCreator, createBearerAuthProvider, createDeleteQuery, createExecuteFn, createGetQuery, createGqlExecuteFn, createGqlMutationViaGet, createGqlMutationViaPost, createGqlQuery, createGqlQueryCreator, createGqlQueryViaGet, createGqlQueryViaPost, createHttpRequest, createInfinityQueryConfig, createLegacyQueryCreator, createPagedQueryStack, createPatchQuery, createPersistentAuthFeature, createPostQuery, createPutQuery, createQuery, createQueryClient, createQueryCollection, createQueryCollectionSignal, createQueryCollectionSubject, createQueryContext, createQueryCreator, createQueryErrorResponse, createQueryFeature, createQueryObject, createQueryRepository, createQuerySnapshotFn, createQueryStack, createSecureDeleteQuery, createSecureExecuteFactory, createSecureExecuteFn, createSecureGetQuery, createSecureGqlExecuteFn, createSecureGqlMutationViaGet, createSecureGqlMutationViaPost, createSecureGqlQuery, createSecureGqlQueryCreator, createSecureGqlQueryViaGet, createSecureGqlQueryViaPost, createSecurePatchQuery, createSecurePostQuery, createSecurePutQuery, createSecureQuery, createSecureQueryCreator, createTrackingFeature, createWebSocketClient, decryptBearer, deepFreeze, def, detectContentTypeHeader, dynLikePaginationAdapter, effectComputed, ethletePaginationAdapter, executeUntilSettled, extractExpiresInSeconds, extractFormViolations, extractQuery, fakePaginationAdapter, filterFailure, filterNull, filterQueryStates, filterSuccess, forEachHeader, getDefaultHeaders, getQueryClientName, getQueryFeatureUsage, getResponseUrl, ggLikePaginationAdapter, gql, gqlDataPropertyMissingInResponse, hasHeader, ignoreAutoRefresh, injectInfinityQueryResponseDelay, injectQueryContext, insertFrom, invalidBaseRouteError, invalidBodyError, invalidRouteError, invalidStateInsideSecureExecuteFactory, isAutoRefresh, isBasicAuthProvider, isBearerAuthProvider, isClassValidatorError, isCreateGqlQueryOptions, isCustomHeaderAuthProvider, isEmptyString, isGqlQueryConfig, isLegacyQuery, isNaN$1 as isNaN, isQuery, isQueryCollection, isQueryDevtoolsEnabled, isQueryErrorResponse, isQueryStateCancelled, isQueryStateFailure, isQueryStateLoading, isQueryStatePrepared, isQueryStateSuccess, isRequestError, isSymfonyError, isSymfonyFormViolationListError, isSymfonyListError, isSymfonyPagerfantaOutOfRangeError, mapToPaginated, mapViolationsToFormErrors, maybeExecute, mergeHeaders, nestedEffect, pagedQueryStackNextPageCalledWithoutPreviousPage, pagedQueryStackPageBiggerThanTotalPages, pagedQueryStackPreviousPageCalledButAlreadyAtFirstPage, paginatedEntityValueUpdater, parseAllXhrResponseHeaders, parseHttpErrorCodeToMessageDe, parseHttpErrorCodeToMessageEn, parseHttpErrorCodeToTitleDe, parseHttpErrorCodeToTitleEn, pathParamsMissingInRouteFunctionError, provideInfinityQueryResponseDelay, provideQueryClientForDevtools, provideQueryDevtools, queryArrayComputed, queryComputed, queryComputedTillTruthy, queryDevtoolsEntries, queryExecute, queryFeatureUsedMultipleTimes, querySequence, querySequenceAlreadyRunning, queryStackTotalQueriesAndExpectedQueriesMismatch, queryStackWithArgsUsed, queryStackWithResponseUpdateUsed, queryStateAlreadyHasKeyError, queryStateCannotTransformError, queryStateDoesNotContainKeyError, queryStateErrorSignal, queryStateLoadingSignal, queryStateResponseSignal, queryStateSignal, registerQueryDevtoolsEntry, removeFrom, request, resetExecuteState, resetPageOnError, serializeBody, setupQueryDependencies, setupQueryExecuteState, setupQueryState, shouldAutoExecuteGqlQuery, shouldAutoExecuteQuery, shouldCacheQuery, shouldRetryRequest, silenceMissingWithArgsFeatureErrorUsedButWithArgsPresent, skipPaginationPageParamCalculator, splitQueryConfig, stringifyQueryRoute, suppressNextQueryStackDevtools, switchQueryCollectionState, switchQueryState, takeUntilResponse, toQuerySignal, toQuerySubject, tokensNotAvailableInsideAuthAndExec, transformArrayResponse, transformExecStateToQueryState, transformGql, transformMethod, transformPaginatedResponse, transformToBoolean, transformToBooleanArray, transformToDate, transformToDateArray, transformToNumber, transformToNumberArray, transformToSort, transformToSortQueryParam, transformToString, transformToStringArray, uncacheableRequestHasAllowCacheParam, uncacheableRequestHasCacheKeyParam, v2BuildQueryCacheKey, v2ExtractExpiresInSeconds, v2ShouldCacheQuery, v2ShouldRetryRequest, validateWithQuery, validateWithV2Query, withArgs, withArgsQueryFeatureMissingButRouteIsFunction, withAuthenticationQuery, withAutoRefresh, withAutoRefreshUsedInManualQuery, withAutoRefreshUsedOnUnsupportedHttpMethod, withErrorHandling, withInactivityLogout, withLogging, withPersistentAuth, withPolling, withPollingUsedOnUnsupportedHttpMethod, withRefreshQuery, withResponseUpdate, withSuccessHandling, withTokenExpirationWarning, withTokenRevocation, withTracking, wrapAsObservableSignal };
7901
8182
  //# sourceMappingURL=ethlete-query.mjs.map