@rozenite/tanstack-query-plugin 1.13.0 → 2.1.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.
- package/CHANGELOG.md +22 -0
- package/dist/devtools/assets/{CXEL7IU7-DmbowaBr.js → CXEL7IU7-BWccRGN3.js} +1 -1
- package/dist/devtools/assets/{tanstack-query-DRBLkSCy.js → tanstack-query-CbF_imft.js} +13 -13
- package/dist/devtools/tanstack-query.html +1 -1
- package/dist/react-native/chunks/useTanStackQueryDevTools.require.cjs +1 -1
- package/dist/react-native/chunks/useTanStackQueryDevTools.require.js +165 -173
- package/dist/rozenite.json +1 -1
- package/dist/sdk/index.cjs +1 -1
- package/dist/sdk/index.js +65 -33
- package/package.json +30 -34
- package/sdk.ts +1 -4
- package/src/react-native/agent/__tests__/tanstack-query-agent.test.ts +32 -31
- package/src/react-native/agent/tanstack-query-agent.ts +33 -97
- package/src/react-native/agent/useTanStackQueryAgentTools.ts +2 -7
- package/src/react-native/devtools-actions.ts +3 -10
- package/src/react-native/useHandleDevToolsMessages.ts +12 -16
- package/src/react-native/useHandleInitialData.ts +8 -1
- package/src/react-native/useSyncTanStackCache.ts +7 -22
- package/src/shared/agent-tools.ts +59 -44
- package/src/shared/dehydrate.ts +1 -3
- package/src/shared/hydrate.ts +11 -21
- package/src/shared/messaging.ts +8 -2
- package/src/shared/query-data-sync.test.ts +1 -5
- package/src/shared/query-data-sync.ts +8 -35
- package/src/shared/useSyncOnlineStatus.ts +4 -9
- package/src/ui/useHandleSyncMessages.ts +23 -31
- package/src/ui/useSyncDevToolsEvents.ts +4 -13
- package/src/ui/useSyncInitialData.test.tsx +76 -0
- package/src/ui/useSyncInitialData.ts +17 -4
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import { useEffect, useMemo } from 'react';
|
|
2
2
|
import { QueryClient } from '@tanstack/react-query';
|
|
3
3
|
import { useRozenitePluginAgentTool } from '@rozenite/agent-bridge';
|
|
4
|
-
import {
|
|
5
|
-
createTanStackQueryAgentController,
|
|
6
|
-
} from './tanstack-query-agent';
|
|
4
|
+
import { createTanStackQueryAgentController } from './tanstack-query-agent';
|
|
7
5
|
import {
|
|
8
6
|
TANSTACK_QUERY_AGENT_PLUGIN_ID,
|
|
9
7
|
tanstackQueryToolDefinitions,
|
|
10
8
|
} from '../../shared/agent-tools';
|
|
11
9
|
|
|
12
10
|
export const useTanStackQueryAgentTools = (queryClient: QueryClient) => {
|
|
13
|
-
const controller = useMemo(
|
|
14
|
-
() => createTanStackQueryAgentController(queryClient),
|
|
15
|
-
[queryClient]
|
|
16
|
-
);
|
|
11
|
+
const controller = useMemo(() => createTanStackQueryAgentController(queryClient), [queryClient]);
|
|
17
12
|
|
|
18
13
|
useEffect(() => {
|
|
19
14
|
const unsubscribeQueryCache = queryClient
|
|
@@ -2,10 +2,7 @@ import { QueryClient } from '@tanstack/react-query';
|
|
|
2
2
|
import { DevToolsActionType } from '../shared/types';
|
|
3
3
|
|
|
4
4
|
type QueryScopedActionInput = {
|
|
5
|
-
type: Exclude<
|
|
6
|
-
DevToolsActionType,
|
|
7
|
-
'CLEAR_MUTATION_CACHE' | 'CLEAR_QUERY_CACHE'
|
|
8
|
-
>;
|
|
5
|
+
type: Exclude<DevToolsActionType, 'CLEAR_MUTATION_CACHE' | 'CLEAR_QUERY_CACHE'>;
|
|
9
6
|
queryHash: string;
|
|
10
7
|
metadata?: {
|
|
11
8
|
data?: unknown;
|
|
@@ -17,9 +14,7 @@ type CacheScopedActionInput = {
|
|
|
17
14
|
queryHash?: string;
|
|
18
15
|
};
|
|
19
16
|
|
|
20
|
-
export type TanStackQueryDevtoolsActionInput =
|
|
21
|
-
| QueryScopedActionInput
|
|
22
|
-
| CacheScopedActionInput;
|
|
17
|
+
export type TanStackQueryDevtoolsActionInput = QueryScopedActionInput | CacheScopedActionInput;
|
|
23
18
|
|
|
24
19
|
const getActiveQuery = (queryClient: QueryClient, queryHash?: string) => {
|
|
25
20
|
if (!queryHash) {
|
|
@@ -52,9 +47,7 @@ export const applyTanStackQueryDevtoolsAction = async (
|
|
|
52
47
|
}
|
|
53
48
|
|
|
54
49
|
case 'CLEAR_MUTATION_CACHE': {
|
|
55
|
-
const mutationCountBefore = queryClient
|
|
56
|
-
.getMutationCache()
|
|
57
|
-
.getAll().length;
|
|
50
|
+
const mutationCountBefore = queryClient.getMutationCache().getAll().length;
|
|
58
51
|
queryClient.getMutationCache().clear();
|
|
59
52
|
return {
|
|
60
53
|
applied: true,
|
|
@@ -12,22 +12,18 @@ export const useHandleDevToolsMessages = (
|
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
const subscription = client.onMessage(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
);
|
|
28
|
-
});
|
|
29
|
-
},
|
|
30
|
-
);
|
|
15
|
+
const subscription = client.onMessage('devtools-action', ({ type, queryHash, metadata }) => {
|
|
16
|
+
void applyTanStackQueryDevtoolsAction(queryClient, {
|
|
17
|
+
type,
|
|
18
|
+
queryHash,
|
|
19
|
+
metadata,
|
|
20
|
+
}).catch((error) => {
|
|
21
|
+
const message = 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
|
+
});
|
|
31
27
|
|
|
32
28
|
return () => {
|
|
33
29
|
subscription.remove();
|
|
@@ -5,7 +5,7 @@ import { dehydrateQueryClient } from '../shared/dehydrate';
|
|
|
5
5
|
|
|
6
6
|
export const useHandleInitialData = (
|
|
7
7
|
queryClient: QueryClient,
|
|
8
|
-
client: TanStackQueryPluginClient | null
|
|
8
|
+
client: TanStackQueryPluginClient | null,
|
|
9
9
|
) => {
|
|
10
10
|
useEffect(() => {
|
|
11
11
|
if (!client) {
|
|
@@ -17,6 +17,13 @@ export const useHandleInitialData = (
|
|
|
17
17
|
client.send('sync-data', { data: dehydratedState });
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
+
// This hook runs last in `useTanStackQueryDevTools`, so by the time the
|
|
21
|
+
// panel reacts to this every handler is listening. The panel is recreated on
|
|
22
|
+
// every app reload and asks for the cache as soon as it boots, which usually
|
|
23
|
+
// beats the app's React tree to the punch; without this its only request is
|
|
24
|
+
// dropped and the panel stays empty until the app is restarted.
|
|
25
|
+
client.send('device-ready', {});
|
|
26
|
+
|
|
20
27
|
return () => {
|
|
21
28
|
subscription.remove();
|
|
22
29
|
};
|
|
@@ -6,20 +6,14 @@ import {
|
|
|
6
6
|
import { useEffect, useMemo, useRef } from 'react';
|
|
7
7
|
import equal from 'fast-deep-equal';
|
|
8
8
|
import { TanStackQueryPluginClient } from '../shared/messaging';
|
|
9
|
-
import {
|
|
10
|
-
dehydrateQuery,
|
|
11
|
-
dehydrateMutation,
|
|
12
|
-
dehydrateObservers,
|
|
13
|
-
} from '../shared/dehydrate';
|
|
9
|
+
import { dehydrateQuery, dehydrateMutation, dehydrateObservers } from '../shared/dehydrate';
|
|
14
10
|
import { SerializableObserver, PartialQueryState } from '../shared/types';
|
|
15
11
|
|
|
16
12
|
export const useSyncTanStackCache = (
|
|
17
13
|
queryClient: QueryClient,
|
|
18
|
-
client: TanStackQueryPluginClient | null
|
|
14
|
+
client: TanStackQueryPluginClient | null,
|
|
19
15
|
) => {
|
|
20
|
-
const previousObserversRef = useRef<Map<string, SerializableObserver[]>>(
|
|
21
|
-
new Map()
|
|
22
|
-
);
|
|
16
|
+
const previousObserversRef = useRef<Map<string, SerializableObserver[]>>(new Map());
|
|
23
17
|
|
|
24
18
|
const handler = useMemo(() => {
|
|
25
19
|
return (event: QueryCacheNotifyEvent | MutationCacheNotifyEvent): void => {
|
|
@@ -187,9 +181,7 @@ export const useSyncTanStackCache = (
|
|
|
187
181
|
type === 'observerOptionsUpdated'
|
|
188
182
|
) {
|
|
189
183
|
const dehydratedObservers = dehydrateObservers(query);
|
|
190
|
-
const previousObservers = previousObserversRef.current.get(
|
|
191
|
-
query.queryHash
|
|
192
|
-
);
|
|
184
|
+
const previousObservers = previousObserversRef.current.get(query.queryHash);
|
|
193
185
|
|
|
194
186
|
// For observerOptionsUpdated, only send if the observers actually changed
|
|
195
187
|
if (type === 'observerOptionsUpdated' && previousObservers) {
|
|
@@ -199,10 +191,7 @@ export const useSyncTanStackCache = (
|
|
|
199
191
|
}
|
|
200
192
|
}
|
|
201
193
|
|
|
202
|
-
previousObserversRef.current.set(
|
|
203
|
-
query.queryHash,
|
|
204
|
-
dehydratedObservers
|
|
205
|
-
);
|
|
194
|
+
previousObserversRef.current.set(query.queryHash, dehydratedObservers);
|
|
206
195
|
|
|
207
196
|
client.send('sync-query-event', {
|
|
208
197
|
type,
|
|
@@ -231,12 +220,8 @@ export const useSyncTanStackCache = (
|
|
|
231
220
|
return;
|
|
232
221
|
}
|
|
233
222
|
|
|
234
|
-
const mutationCacheSubscription = queryClient
|
|
235
|
-
|
|
236
|
-
.subscribe(handler);
|
|
237
|
-
const queryCacheSubscription = queryClient
|
|
238
|
-
.getQueryCache()
|
|
239
|
-
.subscribe(handler);
|
|
223
|
+
const mutationCacheSubscription = queryClient.getMutationCache().subscribe(handler);
|
|
224
|
+
const queryCacheSubscription = queryClient.getQueryCache().subscribe(handler);
|
|
240
225
|
|
|
241
226
|
return () => {
|
|
242
227
|
mutationCacheSubscription();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
defineAgentToolContract,
|
|
3
|
+
definePaginatedAgentToolContract,
|
|
3
4
|
type AgentToolContract,
|
|
4
5
|
type JSONSchema7,
|
|
5
6
|
} from '@rozenite/agent-shared';
|
|
@@ -17,10 +18,9 @@ export type TanStackQueryAgentQueryHashInput = {
|
|
|
17
18
|
queryHash: string;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
|
-
export type TanStackQueryAgentQueryToggleInput =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
};
|
|
21
|
+
export type TanStackQueryAgentQueryToggleInput = TanStackQueryAgentQueryHashInput & {
|
|
22
|
+
enabled: boolean;
|
|
23
|
+
};
|
|
24
24
|
|
|
25
25
|
export type TanStackQueryAgentMutationIdInput = {
|
|
26
26
|
mutationId: number;
|
|
@@ -219,8 +219,7 @@ export const tanstackQueryToolDefinitions = {
|
|
|
219
219
|
TanStackQueryGetCacheSummaryResult
|
|
220
220
|
>({
|
|
221
221
|
name: 'get-cache-summary',
|
|
222
|
-
description:
|
|
223
|
-
'Return aggregate TanStack Query cache health and count information.',
|
|
222
|
+
description: 'Return aggregate TanStack Query cache health and count information.',
|
|
224
223
|
inputSchema: emptyInputSchema,
|
|
225
224
|
}),
|
|
226
225
|
getOnlineStatus: defineAgentToolContract<
|
|
@@ -236,8 +235,7 @@ export const tanstackQueryToolDefinitions = {
|
|
|
236
235
|
TanStackQuerySetOnlineStatusResult
|
|
237
236
|
>({
|
|
238
237
|
name: 'set-online-status',
|
|
239
|
-
description:
|
|
240
|
-
'Set the TanStack Query onlineManager status for testing offline/online behavior.',
|
|
238
|
+
description: 'Set the TanStack Query onlineManager status for testing offline/online behavior.',
|
|
241
239
|
inputSchema: {
|
|
242
240
|
type: 'object',
|
|
243
241
|
properties: {
|
|
@@ -249,7 +247,7 @@ export const tanstackQueryToolDefinitions = {
|
|
|
249
247
|
required: ['online'],
|
|
250
248
|
},
|
|
251
249
|
}),
|
|
252
|
-
listQueries:
|
|
250
|
+
listQueries: definePaginatedAgentToolContract<
|
|
253
251
|
TanStackQueryListQueriesArgs,
|
|
254
252
|
TanStackQueryListQueriesResult
|
|
255
253
|
>({
|
|
@@ -259,24 +257,36 @@ export const tanstackQueryToolDefinitions = {
|
|
|
259
257
|
type: 'object',
|
|
260
258
|
properties: paginationProperties,
|
|
261
259
|
},
|
|
260
|
+
pagination: {
|
|
261
|
+
kind: 'cursor',
|
|
262
|
+
fields: [
|
|
263
|
+
'queryHash',
|
|
264
|
+
'queryKey',
|
|
265
|
+
'status',
|
|
266
|
+
'fetchStatus',
|
|
267
|
+
'observersCount',
|
|
268
|
+
'isInvalidated',
|
|
269
|
+
'dataUpdatedAt',
|
|
270
|
+
'errorUpdatedAt',
|
|
271
|
+
'hasData',
|
|
272
|
+
'hasError',
|
|
273
|
+
],
|
|
274
|
+
defaultFields: ['queryHash', 'queryKey', 'status', 'fetchStatus', 'hasError'],
|
|
275
|
+
},
|
|
262
276
|
}),
|
|
263
277
|
getQueryDetails: defineAgentToolContract<
|
|
264
278
|
TanStackQueryGetQueryDetailsArgs,
|
|
265
279
|
TanStackQueryGetQueryDetailsResult
|
|
266
280
|
>({
|
|
267
281
|
name: 'get-query-details',
|
|
268
|
-
description:
|
|
269
|
-
'Return a JSON-safe TanStack Query query snapshot and observer summary.',
|
|
282
|
+
description: 'Return a JSON-safe TanStack Query query snapshot and observer summary.',
|
|
270
283
|
inputSchema: {
|
|
271
284
|
type: 'object',
|
|
272
285
|
properties: queryActionProperties,
|
|
273
286
|
required: ['queryHash'],
|
|
274
287
|
},
|
|
275
288
|
}),
|
|
276
|
-
refetchQuery: defineAgentToolContract<
|
|
277
|
-
TanStackQueryRefetchQueryArgs,
|
|
278
|
-
TanStackQueryActionResult
|
|
279
|
-
>({
|
|
289
|
+
refetchQuery: defineAgentToolContract<TanStackQueryRefetchQueryArgs, TanStackQueryActionResult>({
|
|
280
290
|
name: 'refetch-query',
|
|
281
291
|
description: 'Refetch a TanStack Query query by queryHash.',
|
|
282
292
|
inputSchema: {
|
|
@@ -298,32 +308,30 @@ export const tanstackQueryToolDefinitions = {
|
|
|
298
308
|
...queryActionProperties,
|
|
299
309
|
enabled: {
|
|
300
310
|
type: 'boolean',
|
|
301
|
-
description:
|
|
302
|
-
'Whether the loading-state simulation should be enabled.',
|
|
311
|
+
description: 'Whether the loading-state simulation should be enabled.',
|
|
303
312
|
},
|
|
304
313
|
},
|
|
305
314
|
required: ['queryHash', 'enabled'],
|
|
306
315
|
},
|
|
307
316
|
}),
|
|
308
|
-
setQueryError: defineAgentToolContract<
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
description: 'Whether the error-state simulation should be enabled.',
|
|
317
|
+
setQueryError: defineAgentToolContract<TanStackQuerySetQueryErrorArgs, TanStackQueryActionResult>(
|
|
318
|
+
{
|
|
319
|
+
name: 'set-query-error',
|
|
320
|
+
description:
|
|
321
|
+
'Enable or disable TanStack Query error-state simulation for a query by queryHash.',
|
|
322
|
+
inputSchema: {
|
|
323
|
+
type: 'object',
|
|
324
|
+
properties: {
|
|
325
|
+
...queryActionProperties,
|
|
326
|
+
enabled: {
|
|
327
|
+
type: 'boolean',
|
|
328
|
+
description: 'Whether the error-state simulation should be enabled.',
|
|
329
|
+
},
|
|
322
330
|
},
|
|
331
|
+
required: ['queryHash', 'enabled'],
|
|
323
332
|
},
|
|
324
|
-
required: ['queryHash', 'enabled'],
|
|
325
333
|
},
|
|
326
|
-
|
|
334
|
+
),
|
|
327
335
|
invalidateQuery: defineAgentToolContract<
|
|
328
336
|
TanStackQueryInvalidateQueryArgs,
|
|
329
337
|
TanStackQueryActionResult
|
|
@@ -336,10 +344,7 @@ export const tanstackQueryToolDefinitions = {
|
|
|
336
344
|
required: ['queryHash'],
|
|
337
345
|
},
|
|
338
346
|
}),
|
|
339
|
-
resetQuery: defineAgentToolContract<
|
|
340
|
-
TanStackQueryResetQueryArgs,
|
|
341
|
-
TanStackQueryActionResult
|
|
342
|
-
>({
|
|
347
|
+
resetQuery: defineAgentToolContract<TanStackQueryResetQueryArgs, TanStackQueryActionResult>({
|
|
343
348
|
name: 'reset-query',
|
|
344
349
|
description: 'Reset a TanStack Query query by queryHash.',
|
|
345
350
|
inputSchema: {
|
|
@@ -348,10 +353,7 @@ export const tanstackQueryToolDefinitions = {
|
|
|
348
353
|
required: ['queryHash'],
|
|
349
354
|
},
|
|
350
355
|
}),
|
|
351
|
-
removeQuery: defineAgentToolContract<
|
|
352
|
-
TanStackQueryRemoveQueryArgs,
|
|
353
|
-
TanStackQueryActionResult
|
|
354
|
-
>({
|
|
356
|
+
removeQuery: defineAgentToolContract<TanStackQueryRemoveQueryArgs, TanStackQueryActionResult>({
|
|
355
357
|
name: 'remove-query',
|
|
356
358
|
description: 'Remove a TanStack Query query from the cache by queryHash.',
|
|
357
359
|
inputSchema: {
|
|
@@ -368,7 +370,7 @@ export const tanstackQueryToolDefinitions = {
|
|
|
368
370
|
description: 'Clear the full TanStack Query query cache.',
|
|
369
371
|
inputSchema: emptyInputSchema,
|
|
370
372
|
}),
|
|
371
|
-
listMutations:
|
|
373
|
+
listMutations: definePaginatedAgentToolContract<
|
|
372
374
|
TanStackQueryListMutationsArgs,
|
|
373
375
|
TanStackQueryListMutationsResult
|
|
374
376
|
>({
|
|
@@ -378,14 +380,27 @@ export const tanstackQueryToolDefinitions = {
|
|
|
378
380
|
type: 'object',
|
|
379
381
|
properties: paginationProperties,
|
|
380
382
|
},
|
|
383
|
+
pagination: {
|
|
384
|
+
kind: 'cursor',
|
|
385
|
+
fields: [
|
|
386
|
+
'mutationId',
|
|
387
|
+
'mutationKey',
|
|
388
|
+
'status',
|
|
389
|
+
'isPaused',
|
|
390
|
+
'submittedAt',
|
|
391
|
+
'failureCount',
|
|
392
|
+
'hasData',
|
|
393
|
+
'hasError',
|
|
394
|
+
],
|
|
395
|
+
defaultFields: ['mutationId', 'mutationKey', 'status', 'hasError'],
|
|
396
|
+
},
|
|
381
397
|
}),
|
|
382
398
|
getMutationDetails: defineAgentToolContract<
|
|
383
399
|
TanStackQueryGetMutationDetailsArgs,
|
|
384
400
|
TanStackQueryGetMutationDetailsResult
|
|
385
401
|
>({
|
|
386
402
|
name: 'get-mutation-details',
|
|
387
|
-
description:
|
|
388
|
-
'Return a JSON-safe TanStack Query mutation snapshot for a mutationId.',
|
|
403
|
+
description: 'Return a JSON-safe TanStack Query mutation snapshot for a mutationId.',
|
|
389
404
|
inputSchema: {
|
|
390
405
|
type: 'object',
|
|
391
406
|
properties: mutationActionProperties,
|
package/src/shared/dehydrate.ts
CHANGED
|
@@ -32,9 +32,7 @@ export const dehydrateMutation = (mutation: Mutation): SerializableMutation => {
|
|
|
32
32
|
};
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
export const dehydrateQueryClient = (
|
|
36
|
-
queryClient: QueryClient
|
|
37
|
-
): SerializableQueryClient => {
|
|
35
|
+
export const dehydrateQueryClient = (queryClient: QueryClient): SerializableQueryClient => {
|
|
38
36
|
return {
|
|
39
37
|
queries: queryClient.getQueryCache().getAll().map(dehydrateQuery),
|
|
40
38
|
mutations: queryClient.getMutationCache().getAll().map(dehydrateMutation),
|
package/src/shared/hydrate.ts
CHANGED
|
@@ -49,26 +49,24 @@ const hydrateObservers = (
|
|
|
49
49
|
|
|
50
50
|
hydratedOptions.queryFn = mockQueryFn;
|
|
51
51
|
|
|
52
|
-
const observer = new QueryObserver(
|
|
53
|
-
client,
|
|
54
|
-
hydratedOptions as QueryObserverOptions,
|
|
55
|
-
);
|
|
52
|
+
const observer = new QueryObserver(client, hydratedOptions as QueryObserverOptions);
|
|
56
53
|
query.addObserver(observer);
|
|
57
54
|
});
|
|
58
55
|
};
|
|
59
56
|
|
|
60
|
-
const hydrateMutation = (
|
|
61
|
-
client: QueryClient,
|
|
62
|
-
dehydratedMutation: SerializableMutation,
|
|
63
|
-
) => {
|
|
57
|
+
const hydrateMutation = (client: QueryClient, dehydratedMutation: SerializableMutation) => {
|
|
64
58
|
const mutationCache = client.getMutationCache();
|
|
65
59
|
const { options, state } = dehydratedMutation;
|
|
66
60
|
|
|
67
61
|
const existingMutation = mutationCache.find({
|
|
68
62
|
mutationKey: options.mutationKey,
|
|
69
63
|
});
|
|
70
|
-
const hydratedState: MutationState<unknown, Error, void, unknown> =
|
|
71
|
-
|
|
64
|
+
const hydratedState: MutationState<unknown, Error, void, unknown> = state as MutationState<
|
|
65
|
+
unknown,
|
|
66
|
+
Error,
|
|
67
|
+
void,
|
|
68
|
+
unknown
|
|
69
|
+
>;
|
|
72
70
|
const hydratedOptions: MutationOptions = options;
|
|
73
71
|
|
|
74
72
|
if (existingMutation) {
|
|
@@ -78,10 +76,7 @@ const hydrateMutation = (
|
|
|
78
76
|
mutationCache.build(client, hydratedOptions, hydratedState);
|
|
79
77
|
};
|
|
80
78
|
|
|
81
|
-
const hydrateQuery = (
|
|
82
|
-
client: QueryClient,
|
|
83
|
-
dehydratedQuery: SerializableQuery,
|
|
84
|
-
) => {
|
|
79
|
+
const hydrateQuery = (client: QueryClient, dehydratedQuery: SerializableQuery) => {
|
|
85
80
|
const queryCache = client.getQueryCache();
|
|
86
81
|
const { queryKey, state, queryHash, observers } = dehydratedQuery;
|
|
87
82
|
|
|
@@ -132,9 +127,7 @@ export const hydrateQueryClient = (
|
|
|
132
127
|
dehydratedState: SerializableQueryClient,
|
|
133
128
|
): void => {
|
|
134
129
|
// Hydrate mutations
|
|
135
|
-
dehydratedState.mutations.forEach((mutation) =>
|
|
136
|
-
hydrateMutation(client, mutation),
|
|
137
|
-
);
|
|
130
|
+
dehydratedState.mutations.forEach((mutation) => hydrateMutation(client, mutation));
|
|
138
131
|
|
|
139
132
|
// Hydrate queries
|
|
140
133
|
dehydratedState.queries.forEach((query) => hydrateQuery(client, query));
|
|
@@ -187,10 +180,7 @@ export const applyQueryEvent = (
|
|
|
187
180
|
};
|
|
188
181
|
|
|
189
182
|
// New function to handle action-based partial state updates
|
|
190
|
-
export const applyPartialQueryState = (
|
|
191
|
-
queryClient: QueryClient,
|
|
192
|
-
data: PartialQueryState,
|
|
193
|
-
): void => {
|
|
183
|
+
export const applyPartialQueryState = (queryClient: QueryClient, data: PartialQueryState): void => {
|
|
194
184
|
const queryCache = queryClient.getQueryCache();
|
|
195
185
|
const query = queryCache.get(data.queryHash);
|
|
196
186
|
|
package/src/shared/messaging.ts
CHANGED
|
@@ -19,6 +19,13 @@ export type TanStackQueryPluginEventMap = {
|
|
|
19
19
|
data?: unknown;
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* Announced by the device once it is listening for panel messages. The panel
|
|
24
|
+
* is recreated on every app reload and asks for the cache immediately, which
|
|
25
|
+
* can land before the app's React tree has mounted the plugin; this lets the
|
|
26
|
+
* panel ask again instead of staying empty until the app is restarted.
|
|
27
|
+
*/
|
|
28
|
+
'device-ready': unknown;
|
|
22
29
|
'request-initial-data': unknown;
|
|
23
30
|
'sync-data': {
|
|
24
31
|
data: SerializableQueryClient;
|
|
@@ -53,5 +60,4 @@ export type TanStackQueryPluginEventMap = {
|
|
|
53
60
|
};
|
|
54
61
|
};
|
|
55
62
|
|
|
56
|
-
export type TanStackQueryPluginClient =
|
|
57
|
-
RozeniteDevToolsClient<TanStackQueryPluginEventMap>;
|
|
63
|
+
export type TanStackQueryPluginClient = RozeniteDevToolsClient<TanStackQueryPluginEventMap>;
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
2
|
import { QueryClient } from '@tanstack/react-query';
|
|
3
|
-
import {
|
|
4
|
-
applyRemoteQueryState,
|
|
5
|
-
instrumentQuery,
|
|
6
|
-
instrumentQueryClient,
|
|
7
|
-
} from './query-data-sync';
|
|
3
|
+
import { applyRemoteQueryState, instrumentQuery, instrumentQueryClient } from './query-data-sync';
|
|
8
4
|
|
|
9
5
|
const createQueryClient = () =>
|
|
10
6
|
new QueryClient({
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Query,
|
|
3
|
-
QueryClient,
|
|
4
|
-
QueryKey,
|
|
5
|
-
QueryState,
|
|
6
|
-
} from '@tanstack/react-query';
|
|
1
|
+
import { Query, QueryClient, QueryKey, QueryState } from '@tanstack/react-query';
|
|
7
2
|
|
|
8
3
|
type QuerySetState = Query['setState'];
|
|
9
4
|
type QueryClientSetQueryData = QueryClient['setQueryData'];
|
|
@@ -16,27 +11,17 @@ type SyncQueryDataPayload = {
|
|
|
16
11
|
type QueryDataSyncHandler = (payload: SyncQueryDataPayload) => void;
|
|
17
12
|
|
|
18
13
|
const originalQuerySetStateMap = new WeakMap<Query, QuerySetState>();
|
|
19
|
-
const originalSetQueryDataMap = new WeakMap<
|
|
20
|
-
QueryClient,
|
|
21
|
-
QueryClientSetQueryData
|
|
22
|
-
>();
|
|
14
|
+
const originalSetQueryDataMap = new WeakMap<QueryClient, QueryClientSetQueryData>();
|
|
23
15
|
const instrumentedQueryClients = new WeakSet<QueryClient>();
|
|
24
16
|
const instrumentedQueries = new WeakSet<Query>();
|
|
25
|
-
const queryClientHandlers = new WeakMap<
|
|
26
|
-
QueryClient,
|
|
27
|
-
QueryDataSyncHandler | undefined
|
|
28
|
-
>();
|
|
17
|
+
const queryClientHandlers = new WeakMap<QueryClient, QueryDataSyncHandler | undefined>();
|
|
29
18
|
const queryHandlers = new WeakMap<Query, QueryDataSyncHandler | undefined>();
|
|
30
19
|
|
|
31
20
|
const getOriginalQuerySetState = (query: Query): QuerySetState => {
|
|
32
21
|
return originalQuerySetStateMap.get(query) ?? query.setState.bind(query);
|
|
33
22
|
};
|
|
34
23
|
|
|
35
|
-
const emitIfDataChanged = (
|
|
36
|
-
query: Query,
|
|
37
|
-
previousData: unknown,
|
|
38
|
-
handler?: QueryDataSyncHandler,
|
|
39
|
-
) => {
|
|
24
|
+
const emitIfDataChanged = (query: Query, previousData: unknown, handler?: QueryDataSyncHandler) => {
|
|
40
25
|
if (!handler || Object.is(previousData, query.state.data)) {
|
|
41
26
|
return;
|
|
42
27
|
}
|
|
@@ -47,10 +32,7 @@ const emitIfDataChanged = (
|
|
|
47
32
|
});
|
|
48
33
|
};
|
|
49
34
|
|
|
50
|
-
const isDataOnlyStateUpdate = (
|
|
51
|
-
previousState: QueryState,
|
|
52
|
-
nextState: Partial<QueryState>,
|
|
53
|
-
) => {
|
|
35
|
+
const isDataOnlyStateUpdate = (previousState: QueryState, nextState: Partial<QueryState>) => {
|
|
54
36
|
if (!('data' in nextState)) {
|
|
55
37
|
return false;
|
|
56
38
|
}
|
|
@@ -63,18 +45,12 @@ const isDataOnlyStateUpdate = (
|
|
|
63
45
|
return changedKeys.every((key) => key === 'data');
|
|
64
46
|
};
|
|
65
47
|
|
|
66
|
-
export const applyRemoteQueryState = (
|
|
67
|
-
query: Query,
|
|
68
|
-
state: Partial<QueryState>,
|
|
69
|
-
) => {
|
|
48
|
+
export const applyRemoteQueryState = (query: Query, state: Partial<QueryState>) => {
|
|
70
49
|
const originalSetState = getOriginalQuerySetState(query);
|
|
71
50
|
originalSetState(state);
|
|
72
51
|
};
|
|
73
52
|
|
|
74
|
-
export const instrumentQuery = (
|
|
75
|
-
query: Query,
|
|
76
|
-
handler?: QueryDataSyncHandler,
|
|
77
|
-
) => {
|
|
53
|
+
export const instrumentQuery = (query: Query, handler?: QueryDataSyncHandler) => {
|
|
78
54
|
queryHandlers.set(query, handler);
|
|
79
55
|
|
|
80
56
|
if (instrumentedQueries.has(query)) {
|
|
@@ -104,10 +80,7 @@ const resolveQueryHash = (queryClient: QueryClient, queryKey: QueryKey) => {
|
|
|
104
80
|
return queryClient.getQueryCache().find({ queryKey })?.queryHash;
|
|
105
81
|
};
|
|
106
82
|
|
|
107
|
-
export const instrumentQueryClient = (
|
|
108
|
-
queryClient: QueryClient,
|
|
109
|
-
handler?: QueryDataSyncHandler,
|
|
110
|
-
) => {
|
|
83
|
+
export const instrumentQueryClient = (queryClient: QueryClient, handler?: QueryDataSyncHandler) => {
|
|
111
84
|
queryClientHandlers.set(queryClient, handler);
|
|
112
85
|
|
|
113
86
|
if (instrumentedQueryClients.has(queryClient)) {
|
|
@@ -2,9 +2,7 @@ import { useEffect } from 'react';
|
|
|
2
2
|
import { onlineManager } from '@tanstack/react-query';
|
|
3
3
|
import { TanStackQueryPluginClient } from './messaging';
|
|
4
4
|
|
|
5
|
-
export const useSyncOnlineStatus = (
|
|
6
|
-
client: TanStackQueryPluginClient | null
|
|
7
|
-
) => {
|
|
5
|
+
export const useSyncOnlineStatus = (client: TanStackQueryPluginClient | null) => {
|
|
8
6
|
useEffect(() => {
|
|
9
7
|
if (!client) {
|
|
10
8
|
return;
|
|
@@ -14,12 +12,9 @@ export const useSyncOnlineStatus = (
|
|
|
14
12
|
client.send('online-status-changed', { online });
|
|
15
13
|
});
|
|
16
14
|
|
|
17
|
-
const onlineMessageSubscription = client.onMessage(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
onlineManager.setOnline(online);
|
|
21
|
-
}
|
|
22
|
-
);
|
|
15
|
+
const onlineMessageSubscription = client.onMessage('online-status-changed', ({ online }) => {
|
|
16
|
+
onlineManager.setOnline(online);
|
|
17
|
+
});
|
|
23
18
|
|
|
24
19
|
return () => {
|
|
25
20
|
onlineManagerSubscription();
|