@rozenite/tanstack-query-plugin 1.7.0-rc.1 → 1.7.0

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.
@@ -5,9 +5,7 @@ import {
5
5
  QueryObserver,
6
6
  onlineManager,
7
7
  } from '@tanstack/react-query';
8
- import {
9
- applyTanStackQueryDevtoolsAction,
10
- } from '../../devtools-actions';
8
+ import { applyTanStackQueryDevtoolsAction } from '../../devtools-actions';
11
9
  import {
12
10
  createTanStackQueryAgentController,
13
11
  serializeForAgent,
@@ -30,7 +28,7 @@ const createQueryClient = () =>
30
28
 
31
29
  const subscribeController = (
32
30
  queryClient: QueryClient,
33
- controller: ReturnType<typeof createTanStackQueryAgentController>
31
+ controller: ReturnType<typeof createTanStackQueryAgentController>,
34
32
  ) => {
35
33
  const unsubscribeQuery = queryClient
36
34
  .getQueryCache()
@@ -58,7 +56,7 @@ const createMutation = (
58
56
  context?: unknown;
59
57
  failureCount?: number;
60
58
  failureReason?: Error | null;
61
- }
59
+ },
62
60
  ) => {
63
61
  return queryClient.getMutationCache().build(
64
62
  queryClient,
@@ -78,7 +76,7 @@ const createMutation = (
78
76
  status: options?.status ?? 'success',
79
77
  submittedAt: options?.submittedAt ?? Date.now(),
80
78
  variables: options?.variables,
81
- } as any
79
+ } as any,
82
80
  ) as Mutation<unknown, Error, unknown, unknown>;
83
81
  };
84
82
 
@@ -126,8 +124,10 @@ describe('tanstack query agent controller', () => {
126
124
  controller.listQueries({
127
125
  limit: 1,
128
126
  cursor: firstPage.page.nextCursor,
129
- })
130
- ).toThrow('Cursor does not match the requested listing. Run the command again.');
127
+ }),
128
+ ).toThrow(
129
+ 'Cursor does not match the requested listing. Run the command again.',
130
+ );
131
131
 
132
132
  unsubscribe();
133
133
  });
@@ -147,8 +147,10 @@ describe('tanstack query agent controller', () => {
147
147
  controller.listQueries({
148
148
  limit: 1,
149
149
  cursor: firstPage.page.nextCursor,
150
- })
151
- ).toThrow('Cursor does not match the requested listing. Run the command again.');
150
+ }),
151
+ ).toThrow(
152
+ 'Cursor does not match the requested listing. Run the command again.',
153
+ );
152
154
 
153
155
  queryClient.setQueryData(['third'], { value: 3 });
154
156
  queryClient.setQueryData(['fourth'], { value: 4 });
@@ -159,8 +161,10 @@ describe('tanstack query agent controller', () => {
159
161
  controller.listQueries({
160
162
  limit: 1,
161
163
  cursor: secondPageSeed.page.nextCursor,
162
- })
163
- ).toThrow('Cursor does not match the requested listing. Run the command again.');
164
+ }),
165
+ ).toThrow(
166
+ 'Cursor does not match the requested listing. Run the command again.',
167
+ );
164
168
 
165
169
  unsubscribe();
166
170
  });
@@ -194,8 +198,10 @@ describe('tanstack query agent controller', () => {
194
198
  controller.listMutations({
195
199
  limit: 1,
196
200
  cursor: firstPage.page.nextCursor,
197
- })
198
- ).toThrow('Cursor does not match the requested listing. Run the command again.');
201
+ }),
202
+ ).toThrow(
203
+ 'Cursor does not match the requested listing. Run the command again.',
204
+ );
199
205
 
200
206
  const mutation = queryClient.getMutationCache().getAll()[0];
201
207
  queryClient.getMutationCache().remove(mutation);
@@ -207,8 +213,10 @@ describe('tanstack query agent controller', () => {
207
213
  controller.listMutations({
208
214
  limit: 1,
209
215
  cursor: secondPageSeed.page.nextCursor,
210
- })
211
- ).toThrow('Cursor does not match the requested listing. Run the command again.');
216
+ }),
217
+ ).toThrow(
218
+ 'Cursor does not match the requested listing. Run the command again.',
219
+ );
212
220
 
213
221
  unsubscribe();
214
222
  });
@@ -234,8 +242,9 @@ describe('tanstack query agent controller', () => {
234
242
  queryFn,
235
243
  });
236
244
 
237
- const queryHash = queryClient.getQueryCache().find({ queryKey: ['todos', 1] })!
238
- .queryHash;
245
+ const queryHash = queryClient
246
+ .getQueryCache()
247
+ .find({ queryKey: ['todos', 1] })!.queryHash;
239
248
  const details = controller.getQueryDetails({ queryHash });
240
249
 
241
250
  expect(details.query).toMatchObject({
@@ -299,9 +308,9 @@ describe('tanstack query agent controller', () => {
299
308
  },
300
309
  });
301
310
 
302
- expect(() =>
303
- controller.getMutationDetails({ mutationId: 9999 })
304
- ).toThrow('Unknown mutationId "9999"');
311
+ expect(() => controller.getMutationDetails({ mutationId: 9999 })).toThrow(
312
+ 'Unknown mutationId "9999"',
313
+ );
305
314
 
306
315
  unsubscribe();
307
316
  });
@@ -310,9 +319,9 @@ describe('tanstack query agent controller', () => {
310
319
  const queryClient = createQueryClient();
311
320
  const controller = createTanStackQueryAgentController(queryClient);
312
321
 
313
- expect(() =>
314
- controller.getQueryDetails({ queryHash: 'missing' })
315
- ).toThrow('Unknown queryHash "missing"');
322
+ expect(() => controller.getQueryDetails({ queryHash: 'missing' })).toThrow(
323
+ 'Unknown queryHash "missing"',
324
+ );
316
325
  });
317
326
 
318
327
  it('gets and sets the online manager status', () => {
@@ -461,6 +470,37 @@ describe('tanstack query agent actions', () => {
461
470
  });
462
471
  });
463
472
 
473
+ it('sets query data through the shared UI dispatcher', async () => {
474
+ const queryClient = createQueryClient();
475
+
476
+ await queryClient.fetchQuery({
477
+ queryKey: ['editable-query'],
478
+ queryFn: async () => ({ value: 'initial' }),
479
+ initialData: { value: 'initial' },
480
+ });
481
+
482
+ const query = queryClient.getQueryCache().find({
483
+ queryKey: ['editable-query'],
484
+ })!;
485
+
486
+ const result = await applyTanStackQueryDevtoolsAction(queryClient, {
487
+ type: 'SET_QUERY_DATA',
488
+ queryHash: query.queryHash,
489
+ metadata: {
490
+ data: { value: 'changed' },
491
+ },
492
+ });
493
+
494
+ expect(result).toMatchObject({
495
+ applied: true,
496
+ action: 'SET_QUERY_DATA',
497
+ queryHash: query.queryHash,
498
+ });
499
+ expect(queryClient.getQueryData(['editable-query'])).toEqual({
500
+ value: 'changed',
501
+ });
502
+ });
503
+
464
504
  it('clears mutation cache through the shared UI/agent dispatcher', async () => {
465
505
  const queryClient = createQueryClient();
466
506
  createMutation(queryClient, {
@@ -501,8 +541,6 @@ describe('serializeForAgent', () => {
501
541
  ok: true,
502
542
  self: '[circular]',
503
543
  });
504
- expect(serializeForAgent(new Example())).toBe(
505
- '[non-serializable:Example]'
506
- );
544
+ expect(serializeForAgent(new Example())).toBe('[non-serializable:Example]');
507
545
  });
508
546
  });
@@ -7,6 +7,9 @@ type QueryScopedActionInput = {
7
7
  'CLEAR_MUTATION_CACHE' | 'CLEAR_QUERY_CACHE'
8
8
  >;
9
9
  queryHash: string;
10
+ metadata?: {
11
+ data?: unknown;
12
+ };
10
13
  };
11
14
 
12
15
  type CacheScopedActionInput = {
@@ -33,7 +36,7 @@ const getActiveQuery = (queryClient: QueryClient, queryHash?: string) => {
33
36
 
34
37
  export const applyTanStackQueryDevtoolsAction = async (
35
38
  queryClient: QueryClient,
36
- input: TanStackQueryDevtoolsActionInput
39
+ input: TanStackQueryDevtoolsActionInput,
37
40
  ) => {
38
41
  switch (input.type) {
39
42
  case 'CLEAR_QUERY_CACHE': {
@@ -49,8 +52,9 @@ export const applyTanStackQueryDevtoolsAction = async (
49
52
  }
50
53
 
51
54
  case 'CLEAR_MUTATION_CACHE': {
52
- const mutationCountBefore =
53
- queryClient.getMutationCache().getAll().length;
55
+ const mutationCountBefore = queryClient
56
+ .getMutationCache()
57
+ .getAll().length;
54
58
  queryClient.getMutationCache().clear();
55
59
  return {
56
60
  applied: true,
@@ -61,6 +65,16 @@ export const applyTanStackQueryDevtoolsAction = async (
61
65
  };
62
66
  }
63
67
 
68
+ case 'SET_QUERY_DATA': {
69
+ const activeQuery = getActiveQuery(queryClient, input.queryHash);
70
+ queryClient.setQueryData(activeQuery.queryKey, input.metadata?.data);
71
+ return {
72
+ applied: true,
73
+ action: input.type,
74
+ queryHash: activeQuery.queryHash,
75
+ };
76
+ }
77
+
64
78
  case 'TRIGGER_ERROR': {
65
79
  const activeQuery = getActiveQuery(queryClient, input.queryHash);
66
80
  const previousQueryOptions = activeQuery.options;
@@ -5,7 +5,7 @@ import { applyTanStackQueryDevtoolsAction } from './devtools-actions';
5
5
 
6
6
  export const useHandleDevToolsMessages = (
7
7
  queryClient: QueryClient,
8
- client: TanStackQueryPluginClient | null
8
+ client: TanStackQueryPluginClient | null,
9
9
  ) => {
10
10
  useEffect(() => {
11
11
  if (!client) {
@@ -14,16 +14,19 @@ export const useHandleDevToolsMessages = (
14
14
 
15
15
  const subscription = client.onMessage(
16
16
  'devtools-action',
17
- ({ type, queryHash }) => {
18
- void applyTanStackQueryDevtoolsAction(queryClient, { type, queryHash })
19
- .catch((error) => {
20
- const message =
21
- error instanceof Error ? error.message : String(error);
22
- console.warn(
23
- `[Rozenite, tanstack-query-plugin] Failed to apply devtools action "${type}": ${message}`
24
- );
25
- });
26
- }
17
+ ({ type, queryHash, metadata }) => {
18
+ void applyTanStackQueryDevtoolsAction(queryClient, {
19
+ type,
20
+ queryHash,
21
+ metadata,
22
+ }).catch((error) => {
23
+ const message =
24
+ error instanceof Error ? error.message : String(error);
25
+ console.warn(
26
+ `[Rozenite, tanstack-query-plugin] Failed to apply devtools action "${type}": ${message}`,
27
+ );
28
+ });
29
+ },
27
30
  );
28
31
 
29
32
  return () => {
@@ -14,6 +14,7 @@ import type {
14
14
  SerializableObserver,
15
15
  PartialQueryState,
16
16
  } from './types';
17
+ import { applyRemoteQueryState, instrumentQuery } from './query-data-sync';
17
18
 
18
19
  const mockQueryFn = () => {
19
20
  return Promise.resolve(null);
@@ -22,7 +23,7 @@ const mockQueryFn = () => {
22
23
  const hydrateObservers = (
23
24
  client: QueryClient,
24
25
  queryHash: string,
25
- dehydratedObservers: SerializableObserver[]
26
+ dehydratedObservers: SerializableObserver[],
26
27
  ) => {
27
28
  const query = client.getQueryCache().get(queryHash);
28
29
 
@@ -50,7 +51,7 @@ const hydrateObservers = (
50
51
 
51
52
  const observer = new QueryObserver(
52
53
  client,
53
- hydratedOptions as QueryObserverOptions
54
+ hydratedOptions as QueryObserverOptions,
54
55
  );
55
56
  query.addObserver(observer);
56
57
  });
@@ -58,7 +59,7 @@ const hydrateObservers = (
58
59
 
59
60
  const hydrateMutation = (
60
61
  client: QueryClient,
61
- dehydratedMutation: SerializableMutation
62
+ dehydratedMutation: SerializableMutation,
62
63
  ) => {
63
64
  const mutationCache = client.getMutationCache();
64
65
  const { options, state } = dehydratedMutation;
@@ -79,7 +80,7 @@ const hydrateMutation = (
79
80
 
80
81
  const hydrateQuery = (
81
82
  client: QueryClient,
82
- dehydratedQuery: SerializableQuery
83
+ dehydratedQuery: SerializableQuery,
83
84
  ) => {
84
85
  const queryCache = client.getQueryCache();
85
86
  const { queryKey, state, queryHash, observers } = dehydratedQuery;
@@ -94,7 +95,7 @@ const hydrateQuery = (
94
95
  query.state.dataUpdatedAt < state.dataUpdatedAt ||
95
96
  query.state.fetchStatus !== state.fetchStatus
96
97
  ) {
97
- query.setState({
98
+ applyRemoteQueryState(query, {
98
99
  ...hydratedState,
99
100
  data,
100
101
  });
@@ -117,20 +118,22 @@ const hydrateQuery = (
117
118
  {
118
119
  ...hydratedState,
119
120
  data,
120
- }
121
+ },
121
122
  );
122
123
  }
123
124
 
125
+ instrumentQuery(query);
126
+
124
127
  hydrateObservers(client, queryHash, observers);
125
128
  };
126
129
 
127
130
  export const hydrateQueryClient = (
128
131
  client: QueryClient,
129
- dehydratedState: SerializableQueryClient
132
+ dehydratedState: SerializableQueryClient,
130
133
  ): void => {
131
134
  // Hydrate mutations
132
135
  dehydratedState.mutations.forEach((mutation) =>
133
- hydrateMutation(client, mutation)
136
+ hydrateMutation(client, mutation),
134
137
  );
135
138
 
136
139
  // Hydrate queries
@@ -148,7 +151,7 @@ export const applyQueryEvent = (
148
151
  | 'observerResultsUpdated'
149
152
  | 'observerOptionsUpdated',
150
153
  data: SerializableQuery | PartialQueryState,
151
- action?: string
154
+ action?: string,
152
155
  ): void => {
153
156
  const queryCache = queryClient.getQueryCache();
154
157
 
@@ -186,7 +189,7 @@ export const applyQueryEvent = (
186
189
  // New function to handle action-based partial state updates
187
190
  export const applyPartialQueryState = (
188
191
  queryClient: QueryClient,
189
- data: PartialQueryState
192
+ data: PartialQueryState,
190
193
  ): void => {
191
194
  const queryCache = queryClient.getQueryCache();
192
195
  const query = queryCache.get(data.queryHash);
@@ -199,7 +202,7 @@ export const applyPartialQueryState = (
199
202
 
200
203
  // Apply the partial state changes
201
204
  if (data.state) {
202
- query.setState(data.state);
205
+ applyRemoteQueryState(query, data.state);
203
206
  }
204
207
  };
205
208
 
@@ -213,7 +216,7 @@ export const applyMutationEvent = (
213
216
  | 'observerRemoved'
214
217
  | 'observerResultsUpdated'
215
218
  | 'observerOptionsUpdated',
216
- data: SerializableMutation
219
+ data: SerializableMutation,
217
220
  ): void => {
218
221
  const mutationCache = queryClient.getMutationCache();
219
222
 
@@ -244,7 +247,7 @@ export const applyQueryObserverEvent = (
244
247
  data: {
245
248
  queryHash: string;
246
249
  observers: SerializableObserver[];
247
- }
250
+ },
248
251
  ): void => {
249
252
  hydrateObservers(queryClient, data.queryHash, data.observers);
250
253
  };
@@ -15,6 +15,9 @@ export type TanStackQueryPluginEventMap = {
15
15
  'devtools-action': {
16
16
  type: DevToolsActionType;
17
17
  queryHash: string;
18
+ metadata?: {
19
+ data?: unknown;
20
+ };
18
21
  };
19
22
  'request-initial-data': unknown;
20
23
  'sync-data': {
@@ -0,0 +1,93 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { QueryClient } from '@tanstack/react-query';
3
+ import {
4
+ applyRemoteQueryState,
5
+ instrumentQuery,
6
+ instrumentQueryClient,
7
+ } from './query-data-sync';
8
+
9
+ const createQueryClient = () =>
10
+ new QueryClient({
11
+ defaultOptions: {
12
+ queries: {
13
+ retry: false,
14
+ gcTime: Infinity,
15
+ },
16
+ },
17
+ });
18
+
19
+ describe('query data sync instrumentation', () => {
20
+ it('emits query data updates for data-only setState edits', () => {
21
+ const queryClient = createQueryClient();
22
+ const handler = vi.fn();
23
+
24
+ queryClient.setQueryData(['edited'], { value: 1 });
25
+ const query = queryClient.getQueryCache().find({ queryKey: ['edited'] })!;
26
+
27
+ instrumentQuery(query, handler);
28
+
29
+ query.setState({
30
+ ...query.state,
31
+ data: { value: 2 },
32
+ });
33
+
34
+ expect(handler).toHaveBeenCalledTimes(1);
35
+ expect(handler).toHaveBeenCalledWith(
36
+ expect.objectContaining({
37
+ data: { value: 2 },
38
+ }),
39
+ );
40
+ });
41
+
42
+ it('emits query data updates for setQueryData user edits', () => {
43
+ const queryClient = createQueryClient();
44
+ const handler = vi.fn();
45
+
46
+ instrumentQueryClient(queryClient, handler);
47
+
48
+ queryClient.setQueryData(['edited'], { value: 1 });
49
+
50
+ expect(handler).toHaveBeenCalledTimes(1);
51
+ expect(handler).toHaveBeenCalledWith(
52
+ expect.objectContaining({
53
+ data: { value: 1 },
54
+ }),
55
+ );
56
+ });
57
+
58
+ it('does not emit query data updates for non-data state changes', () => {
59
+ const queryClient = createQueryClient();
60
+ const handler = vi.fn();
61
+
62
+ queryClient.setQueryData(['edited'], { value: 1 });
63
+ const query = queryClient.getQueryCache().find({ queryKey: ['edited'] })!;
64
+
65
+ instrumentQuery(query, handler);
66
+
67
+ query.setState({
68
+ data: undefined,
69
+ status: 'pending',
70
+ fetchStatus: 'fetching',
71
+ });
72
+
73
+ expect(handler).not.toHaveBeenCalled();
74
+ });
75
+
76
+ it('does not emit query data updates for remote state application', () => {
77
+ const queryClient = createQueryClient();
78
+ const handler = vi.fn();
79
+
80
+ queryClient.setQueryData(['edited'], { value: 1 });
81
+ const query = queryClient.getQueryCache().find({ queryKey: ['edited'] })!;
82
+
83
+ instrumentQuery(query, handler);
84
+
85
+ applyRemoteQueryState(query, {
86
+ ...query.state,
87
+ data: { value: 2 },
88
+ });
89
+
90
+ expect(handler).not.toHaveBeenCalled();
91
+ expect(query.state.data).toEqual({ value: 2 });
92
+ });
93
+ });
@@ -0,0 +1,156 @@
1
+ import {
2
+ Query,
3
+ QueryClient,
4
+ QueryKey,
5
+ QueryState,
6
+ } from '@tanstack/react-query';
7
+
8
+ type QuerySetState = Query['setState'];
9
+ type QueryClientSetQueryData = QueryClient['setQueryData'];
10
+
11
+ type SyncQueryDataPayload = {
12
+ queryHash: string;
13
+ data: unknown;
14
+ };
15
+
16
+ type QueryDataSyncHandler = (payload: SyncQueryDataPayload) => void;
17
+
18
+ const originalQuerySetStateMap = new WeakMap<Query, QuerySetState>();
19
+ const originalSetQueryDataMap = new WeakMap<
20
+ QueryClient,
21
+ QueryClientSetQueryData
22
+ >();
23
+ const instrumentedQueryClients = new WeakSet<QueryClient>();
24
+ const instrumentedQueries = new WeakSet<Query>();
25
+ const queryClientHandlers = new WeakMap<
26
+ QueryClient,
27
+ QueryDataSyncHandler | undefined
28
+ >();
29
+ const queryHandlers = new WeakMap<Query, QueryDataSyncHandler | undefined>();
30
+
31
+ const getOriginalQuerySetState = (query: Query): QuerySetState => {
32
+ return originalQuerySetStateMap.get(query) ?? query.setState.bind(query);
33
+ };
34
+
35
+ const emitIfDataChanged = (
36
+ query: Query,
37
+ previousData: unknown,
38
+ handler?: QueryDataSyncHandler,
39
+ ) => {
40
+ if (!handler || Object.is(previousData, query.state.data)) {
41
+ return;
42
+ }
43
+
44
+ handler({
45
+ queryHash: query.queryHash,
46
+ data: query.state.data,
47
+ });
48
+ };
49
+
50
+ const isDataOnlyStateUpdate = (
51
+ previousState: QueryState,
52
+ nextState: Partial<QueryState>,
53
+ ) => {
54
+ if (!('data' in nextState)) {
55
+ return false;
56
+ }
57
+
58
+ const changedKeys = Object.keys(nextState).filter((key) => {
59
+ const typedKey = key as keyof QueryState;
60
+ return !Object.is(previousState[typedKey], nextState[typedKey]);
61
+ }) as Array<keyof QueryState>;
62
+
63
+ return changedKeys.every((key) => key === 'data');
64
+ };
65
+
66
+ export const applyRemoteQueryState = (
67
+ query: Query,
68
+ state: Partial<QueryState>,
69
+ ) => {
70
+ const originalSetState = getOriginalQuerySetState(query);
71
+ originalSetState(state);
72
+ };
73
+
74
+ export const instrumentQuery = (
75
+ query: Query,
76
+ handler?: QueryDataSyncHandler,
77
+ ) => {
78
+ queryHandlers.set(query, handler);
79
+
80
+ if (instrumentedQueries.has(query)) {
81
+ return query;
82
+ }
83
+
84
+ const originalSetState = query.setState.bind(query);
85
+ originalQuerySetStateMap.set(query, originalSetState);
86
+
87
+ query.setState = ((state) => {
88
+ const shouldEmit = isDataOnlyStateUpdate(query.state, state);
89
+ const previousData = query.state.data;
90
+ const result = originalSetState(state);
91
+
92
+ if (shouldEmit) {
93
+ emitIfDataChanged(query, previousData, queryHandlers.get(query));
94
+ }
95
+
96
+ return result;
97
+ }) as QuerySetState;
98
+
99
+ instrumentedQueries.add(query);
100
+ return query;
101
+ };
102
+
103
+ const resolveQueryHash = (queryClient: QueryClient, queryKey: QueryKey) => {
104
+ return queryClient.getQueryCache().find({ queryKey })?.queryHash;
105
+ };
106
+
107
+ export const instrumentQueryClient = (
108
+ queryClient: QueryClient,
109
+ handler?: QueryDataSyncHandler,
110
+ ) => {
111
+ queryClientHandlers.set(queryClient, handler);
112
+
113
+ if (instrumentedQueryClients.has(queryClient)) {
114
+ queryClient
115
+ .getQueryCache()
116
+ .getAll()
117
+ .forEach((query) => {
118
+ instrumentQuery(query, handler);
119
+ });
120
+ return queryClient;
121
+ }
122
+
123
+ const originalSetQueryData = queryClient.setQueryData.bind(queryClient);
124
+ originalSetQueryDataMap.set(queryClient, originalSetQueryData);
125
+
126
+ queryClient.setQueryData = ((queryKey, updater, options) => {
127
+ const result = originalSetQueryData(queryKey, updater, options);
128
+ const query = queryClient.getQueryCache().find({ queryKey });
129
+ const activeQueryClientHandler = queryClientHandlers.get(queryClient);
130
+
131
+ if (query) {
132
+ instrumentQuery(query, activeQueryClientHandler);
133
+ const queryHash = resolveQueryHash(queryClient, queryKey);
134
+ const activeHandler = queryHandlers.get(query);
135
+
136
+ if (activeHandler && queryHash) {
137
+ activeHandler({
138
+ queryHash,
139
+ data: query.state.data,
140
+ });
141
+ }
142
+ }
143
+
144
+ return result;
145
+ }) as QueryClientSetQueryData;
146
+
147
+ queryClient
148
+ .getQueryCache()
149
+ .getAll()
150
+ .forEach((query) => {
151
+ instrumentQuery(query, handler);
152
+ });
153
+
154
+ instrumentedQueryClients.add(queryClient);
155
+ return queryClient;
156
+ };
@@ -37,6 +37,7 @@ export type SerializableQueryClient = {
37
37
 
38
38
  export type DevToolsActionType =
39
39
  | 'REFETCH'
40
+ | 'SET_QUERY_DATA'
40
41
  | 'INVALIDATE'
41
42
  | 'RESET'
42
43
  | 'REMOVE'
@@ -1,3 +1,4 @@
1
+ import { useEffect } from 'react';
1
2
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
2
3
  import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools/production';
3
4
  import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
@@ -6,12 +7,23 @@ import { useSyncInitialData } from './useSyncInitialData';
6
7
  import { useSyncDevToolsEvents } from './useSyncDevToolsEvents';
7
8
  import { useSyncOnlineStatus } from '../shared/useSyncOnlineStatus';
8
9
  import { useHandleSyncMessages } from './useHandleSyncMessages';
10
+ import { instrumentQueryClient } from '../shared/query-data-sync';
9
11
 
10
12
  const App = () => {
11
13
  const client = useRozeniteDevToolsClient<TanStackQueryPluginEventMap>({
12
14
  pluginId: '@rozenite/tanstack-query-plugin',
13
15
  });
14
16
 
17
+ useEffect(() => {
18
+ instrumentQueryClient(queryClient, ({ queryHash, data }) => {
19
+ client?.send('devtools-action', {
20
+ type: 'SET_QUERY_DATA',
21
+ queryHash,
22
+ metadata: { data },
23
+ });
24
+ });
25
+ }, [client]);
26
+
15
27
  useSyncInitialData(client);
16
28
 
17
29
  useSyncDevToolsEvents(client);