@rozenite/tanstack-query-plugin 1.0.0-alpha.0 → 1.0.0-alpha.2
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/dist/assets/CXEL7IU7-BCih8F8R.js +1172 -0
- package/dist/assets/tanstack-query-By949uAm.js +48 -0
- package/dist/react-native.cjs +1 -1
- package/dist/react-native.js +155 -83
- package/dist/tanstack-query.html +1 -1
- package/package.json +2 -2
- package/src/react-native/useHandleDevToolsMessages.ts +120 -0
- package/src/react-native/useHandleInitialData.ts +25 -0
- package/src/react-native/useSyncTanStackCache.ts +33 -0
- package/src/react-native/useTanStackQueryDevTools.ts +14 -208
- package/src/shared/dehydrate.ts +40 -0
- package/src/shared/hydrate.ts +106 -0
- package/src/shared/messaging.ts +19 -0
- package/src/shared/types.ts +43 -0
- package/src/shared/useSyncOnlineStatus.ts +30 -0
- package/src/ui/tanstack-query.tsx +21 -184
- package/src/ui/useHandleSyncMessages.ts +24 -0
- package/src/ui/useSyncDevToolsEvents.ts +55 -0
- package/src/ui/useSyncInitialData.ts +14 -0
- package/dist/assets/tanstack-query-CXp_Psxe.js +0 -48
|
@@ -1,214 +1,20 @@
|
|
|
1
1
|
import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
| 'TRIGGER_ERROR'
|
|
11
|
-
| 'RESTORE_ERROR'
|
|
12
|
-
| 'TRIGGER_LOADING'
|
|
13
|
-
| 'RESTORE_LOADING'
|
|
14
|
-
| 'CLEAR_MUTATION_CACHE'
|
|
15
|
-
| 'CLEAR_QUERY_CACHE';
|
|
16
|
-
|
|
17
|
-
interface DevToolsEventDetail {
|
|
18
|
-
type: DevToolsActionType;
|
|
19
|
-
queryHash?: string;
|
|
20
|
-
mutationId?: number;
|
|
21
|
-
metadata?: Record<string, unknown>;
|
|
22
|
-
requestId?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
type DevToolsEventMap = {
|
|
26
|
-
"DEVTOOLS_TO_DEVICE": DevToolsEventDetail;
|
|
27
|
-
"DEVICE_TO_DEVTOOLS": QueryCacheNotifyEvent | MutationCacheNotifyEvent;
|
|
28
|
-
"DEVICE_TO_DEVTOOLS_ACK": { requestId: string; success: boolean };
|
|
29
|
-
"DEVICE_TO_DEVTOOLS_INITIAL_DATA": { queries: Query[]; mutations: Mutation[] };
|
|
30
|
-
"DEVTOOLS_TO_DEVICE_INITIAL_DATA_REQUEST": unknown;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const useTanStackQueryDevTools = (queryClient: QueryClient) => {
|
|
34
|
-
const client = useRozeniteDevToolsClient<DevToolsEventMap>({
|
|
2
|
+
import { TanStackQueryPluginEventMap } from '../shared/messaging';
|
|
3
|
+
import { useSyncOnlineStatus } from '../shared/useSyncOnlineStatus';
|
|
4
|
+
import { useHandleDevToolsMessages } from './useHandleDevToolsMessages';
|
|
5
|
+
import { useSyncTanStackCache } from './useSyncTanStackCache';
|
|
6
|
+
import { useHandleInitialData } from './useHandleInitialData';
|
|
7
|
+
|
|
8
|
+
export const useTanStackQueryDevTools = () => {
|
|
9
|
+
const client = useRozeniteDevToolsClient<TanStackQueryPluginEventMap>({
|
|
35
10
|
pluginId: '@rozenite/tanstack-query-plugin',
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
if (!client) return;
|
|
40
|
-
|
|
41
|
-
const subscription = client.onMessage("DEVTOOLS_TO_DEVICE_INITIAL_DATA_REQUEST", () => {
|
|
42
|
-
client.send("DEVICE_TO_DEVTOOLS_INITIAL_DATA", {
|
|
43
|
-
queries: queryClient.getQueryCache().getAll(),
|
|
44
|
-
mutations: queryClient.getMutationCache().getAll(),
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
return () => subscription.remove();
|
|
49
|
-
}, [client, queryClient]);
|
|
50
|
-
|
|
51
|
-
// Track pending DevTools requests that are waiting for acknowledgment
|
|
52
|
-
const pendingDevToolsRequests = useRef<Set<string>>(new Set());
|
|
53
|
-
|
|
54
|
-
const handleEvent = useCallback((event: DevToolsEventDetail) => {
|
|
55
|
-
const getQuery = (hash: string): Query | undefined => {
|
|
56
|
-
return queryClient.getQueryCache().getAll().find(q => q.queryHash === hash);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const onEvent = (event: DevToolsEventDetail): void => {
|
|
60
|
-
const { type, queryHash, metadata, requestId } = event;
|
|
61
|
-
|
|
62
|
-
if (type === 'REFETCH' && queryHash) {
|
|
63
|
-
getQuery(queryHash)?.fetch();
|
|
64
|
-
if (requestId) {
|
|
65
|
-
pendingDevToolsRequests.current.add(requestId);
|
|
66
|
-
// Acknowledge immediately after the fetch is initiated
|
|
67
|
-
client?.send("DEVICE_TO_DEVTOOLS_ACK", { requestId, success: true });
|
|
68
|
-
pendingDevToolsRequests.current.delete(requestId);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (type === 'INVALIDATE' && queryHash) {
|
|
72
|
-
const query = getQuery(queryHash);
|
|
73
|
-
if (query) {
|
|
74
|
-
queryClient.invalidateQueries({ queryKey: query.queryKey });
|
|
75
|
-
}
|
|
76
|
-
if (requestId) {
|
|
77
|
-
client?.send("DEVICE_TO_DEVTOOLS_ACK", { requestId, success: true });
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (type === 'RESET' && queryHash) {
|
|
81
|
-
const query = getQuery(queryHash);
|
|
82
|
-
if (query) {
|
|
83
|
-
queryClient.resetQueries({ queryKey: query.queryKey });
|
|
84
|
-
}
|
|
85
|
-
if (requestId) {
|
|
86
|
-
client?.send("DEVICE_TO_DEVTOOLS_ACK", { requestId, success: true });
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
if (type === 'REMOVE' && queryHash) {
|
|
90
|
-
const query = getQuery(queryHash);
|
|
91
|
-
if (query) {
|
|
92
|
-
queryClient.removeQueries({ queryKey: query.queryKey });
|
|
93
|
-
}
|
|
94
|
-
if (requestId) {
|
|
95
|
-
client?.send("DEVICE_TO_DEVTOOLS_ACK", { requestId, success: true });
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (type === 'TRIGGER_LOADING' && queryHash) {
|
|
99
|
-
const query = getQuery(queryHash);
|
|
100
|
-
|
|
101
|
-
if (query) {
|
|
102
|
-
// Set state to loading/pending (simulate fetch in progress)
|
|
103
|
-
query.setState({
|
|
104
|
-
...query.state,
|
|
105
|
-
fetchStatus: 'fetching',
|
|
106
|
-
status: 'pending',
|
|
107
|
-
error: null,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
if (requestId) {
|
|
111
|
-
pendingDevToolsRequests.current.add(requestId);
|
|
112
|
-
// Acknowledge immediately after the state change is applied
|
|
113
|
-
client?.send("DEVICE_TO_DEVTOOLS_ACK", { requestId, success: true });
|
|
114
|
-
pendingDevToolsRequests.current.delete(requestId);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (type === 'RESTORE_LOADING' && queryHash) {
|
|
119
|
-
const query = getQuery(queryHash);
|
|
120
|
-
if (query) {
|
|
121
|
-
// Set state to idle/success (simulate fetch complete)
|
|
122
|
-
query.setState({
|
|
123
|
-
...query.state,
|
|
124
|
-
fetchStatus: 'idle',
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
if (requestId) {
|
|
128
|
-
pendingDevToolsRequests.current.add(requestId);
|
|
129
|
-
// Acknowledge immediately after the state change is applied
|
|
130
|
-
client?.send("DEVICE_TO_DEVTOOLS_ACK", { requestId, success: true });
|
|
131
|
-
pendingDevToolsRequests.current.delete(requestId);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
if (type === 'TRIGGER_ERROR' && queryHash) {
|
|
136
|
-
const query = getQuery(queryHash);
|
|
137
|
-
if (query) {
|
|
138
|
-
query.setState({
|
|
139
|
-
...query.state,
|
|
140
|
-
fetchStatus: 'idle',
|
|
141
|
-
status: 'error',
|
|
142
|
-
error: metadata?.error as Error || new Error('Forced error via devtools'),
|
|
143
|
-
errorUpdateCount: (query.state.errorUpdateCount ?? 0) + 1,
|
|
144
|
-
errorUpdatedAt: Date.now(),
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
if (requestId) {
|
|
148
|
-
pendingDevToolsRequests.current.add(requestId);
|
|
149
|
-
// Acknowledge immediately after the state change is applied
|
|
150
|
-
client?.send("DEVICE_TO_DEVTOOLS_ACK", { requestId, success: true });
|
|
151
|
-
pendingDevToolsRequests.current.delete(requestId);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (type === 'RESTORE_ERROR' && queryHash) {
|
|
156
|
-
const query = getQuery(queryHash);
|
|
157
|
-
if (query) {
|
|
158
|
-
queryClient.resetQueries({ queryKey: query.queryKey });
|
|
159
|
-
}
|
|
160
|
-
if (requestId) {
|
|
161
|
-
client?.send("DEVICE_TO_DEVTOOLS_ACK", { requestId, success: true });
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
if (type === 'CLEAR_MUTATION_CACHE') {
|
|
165
|
-
queryClient.getMutationCache().clear();
|
|
166
|
-
if (requestId) {
|
|
167
|
-
client?.send("DEVICE_TO_DEVTOOLS_ACK", { requestId, success: true });
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
if (type === 'CLEAR_QUERY_CACHE') {
|
|
171
|
-
queryClient.clear();
|
|
172
|
-
if (requestId) {
|
|
173
|
-
client?.send("DEVICE_TO_DEVTOOLS_ACK", { requestId, success: true });
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
onEvent(event);
|
|
179
|
-
}, [queryClient, client]);
|
|
180
|
-
|
|
181
|
-
useEffect(() => {
|
|
182
|
-
if (!client) return;
|
|
183
|
-
|
|
184
|
-
const subscription = client.onMessage("DEVTOOLS_TO_DEVICE", handleEvent);
|
|
185
|
-
return () => subscription.remove();
|
|
186
|
-
}, [handleEvent, client]);
|
|
11
|
+
});
|
|
187
12
|
|
|
188
|
-
|
|
189
|
-
if (!client) return;
|
|
13
|
+
useSyncOnlineStatus(client);
|
|
190
14
|
|
|
191
|
-
|
|
192
|
-
// Don't send events for queries that have pending DevTools requests
|
|
193
|
-
if (pendingDevToolsRequests.current.size > 0) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
client.send("DEVICE_TO_DEVTOOLS", event);
|
|
198
|
-
});
|
|
199
|
-
}, [client, queryClient]);
|
|
15
|
+
useHandleDevToolsMessages(client);
|
|
200
16
|
|
|
201
|
-
|
|
202
|
-
useEffect(() => {
|
|
203
|
-
if (!client) return;
|
|
17
|
+
useSyncTanStackCache(client);
|
|
204
18
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (pendingDevToolsRequests.current.size > 0) {
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
client.send("DEVICE_TO_DEVTOOLS", event);
|
|
212
|
-
});
|
|
213
|
-
}, [client, queryClient]);
|
|
214
|
-
}
|
|
19
|
+
useHandleInitialData(client);
|
|
20
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Query, Mutation, QueryClient } from '@tanstack/react-query';
|
|
2
|
+
import type {
|
|
3
|
+
SerializableQuery,
|
|
4
|
+
SerializableMutation,
|
|
5
|
+
SerializableObserver,
|
|
6
|
+
SerializableQueryClient,
|
|
7
|
+
} from './types';
|
|
8
|
+
|
|
9
|
+
export const dehydrateQuery = (query: Query): SerializableQuery => {
|
|
10
|
+
const dehydratedObservers: SerializableObserver[] = query.observers.map(
|
|
11
|
+
(observer) => ({
|
|
12
|
+
queryHash: query.queryHash,
|
|
13
|
+
options: observer.options,
|
|
14
|
+
})
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
state: query.state,
|
|
19
|
+
queryKey: query.queryKey,
|
|
20
|
+
queryHash: query.queryHash,
|
|
21
|
+
observers: dehydratedObservers,
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const dehydrateMutation = (mutation: Mutation): SerializableMutation => {
|
|
26
|
+
return {
|
|
27
|
+
mutationId: mutation.mutationId,
|
|
28
|
+
state: mutation.state,
|
|
29
|
+
options: mutation.options,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const dehydrateQueryClient = (
|
|
34
|
+
queryClient: QueryClient
|
|
35
|
+
): SerializableQueryClient => {
|
|
36
|
+
return {
|
|
37
|
+
queries: queryClient.getQueryCache().getAll().map(dehydrateQuery),
|
|
38
|
+
mutations: queryClient.getMutationCache().getAll().map(dehydrateMutation),
|
|
39
|
+
};
|
|
40
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InfiniteQueryObserverOptions,
|
|
3
|
+
MutationOptions,
|
|
4
|
+
MutationState,
|
|
5
|
+
QueryClient,
|
|
6
|
+
QueryObserver,
|
|
7
|
+
QueryObserverOptions,
|
|
8
|
+
QueryState,
|
|
9
|
+
} from '@tanstack/react-query';
|
|
10
|
+
import { SerializableQueryClient } from './types';
|
|
11
|
+
|
|
12
|
+
const mockQueryFn = () => {
|
|
13
|
+
return Promise.resolve(null);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const hydrateQueryClient = (
|
|
17
|
+
client: QueryClient,
|
|
18
|
+
dehydratedState: SerializableQueryClient
|
|
19
|
+
): void => {
|
|
20
|
+
const queryCache = client.getQueryCache();
|
|
21
|
+
const mutationCache = client.getMutationCache();
|
|
22
|
+
|
|
23
|
+
// Sync mutations
|
|
24
|
+
dehydratedState.mutations.forEach(({ options, state }) => {
|
|
25
|
+
const existingMutation = mutationCache.find({
|
|
26
|
+
mutationKey: options.mutationKey,
|
|
27
|
+
});
|
|
28
|
+
const hydratedState: MutationState<unknown, Error, void, unknown> =
|
|
29
|
+
state as MutationState<unknown, Error, void, unknown>;
|
|
30
|
+
const hydratedOptions: MutationOptions = options;
|
|
31
|
+
|
|
32
|
+
if (existingMutation) {
|
|
33
|
+
mutationCache.remove(existingMutation);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
mutationCache.build(client, hydratedOptions, hydratedState);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Hydrate queries
|
|
40
|
+
dehydratedState.queries.forEach(
|
|
41
|
+
({ queryKey, state, queryHash, observers }) => {
|
|
42
|
+
let query = queryCache.get(queryHash);
|
|
43
|
+
const data = state.data;
|
|
44
|
+
const hydratedState: QueryState = state;
|
|
45
|
+
|
|
46
|
+
// Do not hydrate if an existing query exists with newer data
|
|
47
|
+
if (query) {
|
|
48
|
+
if (
|
|
49
|
+
query.state.dataUpdatedAt < state.dataUpdatedAt ||
|
|
50
|
+
query.state.fetchStatus !== state.fetchStatus
|
|
51
|
+
) {
|
|
52
|
+
query.setState({
|
|
53
|
+
...hydratedState,
|
|
54
|
+
data,
|
|
55
|
+
});
|
|
56
|
+
query.setOptions({
|
|
57
|
+
...query.options,
|
|
58
|
+
queryFn: mockQueryFn,
|
|
59
|
+
retry: 0,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
// Restore query
|
|
64
|
+
query = queryCache.build(
|
|
65
|
+
client,
|
|
66
|
+
{
|
|
67
|
+
...client.getDefaultOptions().hydrate?.queries,
|
|
68
|
+
queryKey,
|
|
69
|
+
queryHash,
|
|
70
|
+
queryFn: mockQueryFn,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
...hydratedState,
|
|
74
|
+
data,
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
query.observers.forEach((observer) => {
|
|
80
|
+
query.removeObserver(observer);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
observers.forEach((observerState) => {
|
|
84
|
+
const hydratedOptions:
|
|
85
|
+
| InfiniteQueryObserverOptions
|
|
86
|
+
| QueryObserverOptions = observerState.options;
|
|
87
|
+
|
|
88
|
+
if ('initialPageParam' in hydratedOptions) {
|
|
89
|
+
delete hydratedOptions.initialPageParam;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if ('behavior' in hydratedOptions) {
|
|
93
|
+
delete hydratedOptions.behavior;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
hydratedOptions.queryFn = mockQueryFn;
|
|
97
|
+
|
|
98
|
+
const observer = new QueryObserver(
|
|
99
|
+
client,
|
|
100
|
+
hydratedOptions as QueryObserverOptions
|
|
101
|
+
);
|
|
102
|
+
query.addObserver(observer);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { RozeniteDevToolsClient } from '@rozenite/plugin-bridge';
|
|
2
|
+
import { DevToolsActionType, SerializableQueryClient } from './types';
|
|
3
|
+
|
|
4
|
+
export type TanStackQueryPluginEventMap = {
|
|
5
|
+
'online-status-changed': {
|
|
6
|
+
online: boolean;
|
|
7
|
+
};
|
|
8
|
+
'devtools-action': {
|
|
9
|
+
type: DevToolsActionType;
|
|
10
|
+
queryHash: string;
|
|
11
|
+
};
|
|
12
|
+
'request-initial-data': unknown;
|
|
13
|
+
'sync-data': {
|
|
14
|
+
data: SerializableQueryClient;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type TanStackQueryPluginClient =
|
|
19
|
+
RozeniteDevToolsClient<TanStackQueryPluginEventMap>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
QueryKey,
|
|
3
|
+
MutationState,
|
|
4
|
+
QueryState,
|
|
5
|
+
QueryObserverOptions,
|
|
6
|
+
InfiniteQueryObserverOptions,
|
|
7
|
+
MutationOptions,
|
|
8
|
+
} from '@tanstack/react-query';
|
|
9
|
+
|
|
10
|
+
export type SerializableQuery = {
|
|
11
|
+
queryHash: string;
|
|
12
|
+
state: QueryState;
|
|
13
|
+
queryKey: QueryKey;
|
|
14
|
+
observers: SerializableObserver[];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type SerializableMutation = {
|
|
18
|
+
mutationId: number;
|
|
19
|
+
options: MutationOptions;
|
|
20
|
+
state: MutationState;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type SerializableObserver = {
|
|
24
|
+
queryHash: string;
|
|
25
|
+
options: QueryObserverOptions | InfiniteQueryObserverOptions;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type SerializableQueryClient = {
|
|
29
|
+
queries: SerializableQuery[];
|
|
30
|
+
mutations: SerializableMutation[];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type DevToolsActionType =
|
|
34
|
+
| 'REFETCH'
|
|
35
|
+
| 'INVALIDATE'
|
|
36
|
+
| 'RESET'
|
|
37
|
+
| 'REMOVE'
|
|
38
|
+
| 'TRIGGER_ERROR'
|
|
39
|
+
| 'RESTORE_ERROR'
|
|
40
|
+
| 'TRIGGER_LOADING'
|
|
41
|
+
| 'RESTORE_LOADING'
|
|
42
|
+
| 'CLEAR_MUTATION_CACHE'
|
|
43
|
+
| 'CLEAR_QUERY_CACHE';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { onlineManager } from '@tanstack/react-query';
|
|
3
|
+
import { TanStackQueryPluginClient } from './messaging';
|
|
4
|
+
|
|
5
|
+
export const useSyncOnlineStatus = (
|
|
6
|
+
client: TanStackQueryPluginClient | null
|
|
7
|
+
) => {
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!client) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const onlineManagerSubscription = onlineManager.subscribe((online) => {
|
|
14
|
+
// client.send('online-status-changed', { online });
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const onlineMessageSubscription = client.onMessage(
|
|
18
|
+
'online-status-changed',
|
|
19
|
+
({ online }) => {
|
|
20
|
+
console.log('changed from ', onlineManager.isOnline(), 'to', online);
|
|
21
|
+
// onlineManager.setOnline(online);
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return () => {
|
|
26
|
+
onlineManagerSubscription();
|
|
27
|
+
onlineMessageSubscription.remove();
|
|
28
|
+
};
|
|
29
|
+
}, [client]);
|
|
30
|
+
};
|
|
@@ -1,197 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools';
|
|
1
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
2
|
+
import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools/production';
|
|
3
3
|
import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
type DevToolsEventMap = {
|
|
18
|
-
"DEVTOOLS_TO_DEVICE": unknown;
|
|
19
|
-
"DEVICE_TO_DEVTOOLS": QueryCacheNotifyEvent | MutationCacheNotifyEvent;
|
|
20
|
-
"DEVICE_TO_DEVTOOLS_ACK": { requestId: string; success: boolean };
|
|
21
|
-
"DEVICE_TO_DEVTOOLS_INITIAL_DATA": { queries: Query[]; mutations: Mutation[] };
|
|
22
|
-
"DEVTOOLS_TO_DEVICE_INITIAL_DATA_REQUEST": unknown;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const Wrapped = () => {
|
|
26
|
-
const client = useRozeniteDevToolsClient<DevToolsEventMap>({
|
|
4
|
+
import { TanStackQueryPluginEventMap } from '../shared/messaging';
|
|
5
|
+
import { useSyncInitialData } from './useSyncInitialData';
|
|
6
|
+
import { useSyncDevToolsEvents } from './useSyncDevToolsEvents';
|
|
7
|
+
import { useSyncOnlineStatus } from '../shared/useSyncOnlineStatus';
|
|
8
|
+
import { useHandleSyncMessages } from './useHandleSyncMessages';
|
|
9
|
+
|
|
10
|
+
const App = () => {
|
|
11
|
+
const client = useRozeniteDevToolsClient<TanStackQueryPluginEventMap>({
|
|
27
12
|
pluginId: '@rozenite/tanstack-query-plugin',
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
// Track pending acknowledgments to prevent feedback loops
|
|
31
|
-
const pendingAcknowledgment = useRef<Set<string>>(new Set());
|
|
32
|
-
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
if (!client) return;
|
|
35
|
-
client.send("DEVTOOLS_TO_DEVICE_INITIAL_DATA_REQUEST", null);
|
|
36
|
-
}, [client]);
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
if (!client) return;
|
|
13
|
+
});
|
|
40
14
|
|
|
41
|
-
|
|
42
|
-
const detail = (event as CustomEvent).detail;
|
|
43
|
-
|
|
44
|
-
// Generate a unique request ID for this DevTools action
|
|
45
|
-
const requestId = `devtools-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
46
|
-
|
|
47
|
-
// Mark that we're waiting for acknowledgment
|
|
48
|
-
pendingAcknowledgment.current.add(requestId);
|
|
49
|
-
|
|
50
|
-
// Add the request ID to the event detail
|
|
51
|
-
const eventWithRequestId = {
|
|
52
|
-
...detail,
|
|
53
|
-
requestId,
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
client.send("DEVTOOLS_TO_DEVICE", eventWithRequestId);
|
|
57
|
-
};
|
|
15
|
+
useSyncInitialData(client);
|
|
58
16
|
|
|
59
|
-
|
|
60
|
-
return () => window.removeEventListener('@tanstack/query-devtools-event', handleEvent);
|
|
61
|
-
}, [client])
|
|
17
|
+
useSyncDevToolsEvents(client);
|
|
62
18
|
|
|
63
|
-
|
|
64
|
-
if (!client) return;
|
|
19
|
+
useSyncOnlineStatus(client);
|
|
65
20
|
|
|
66
|
-
|
|
67
|
-
// Remove the request from pending acknowledgments
|
|
68
|
-
pendingAcknowledgment.current.delete(ack.requestId);
|
|
69
|
-
});
|
|
21
|
+
useHandleSyncMessages(client);
|
|
70
22
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (pendingAcknowledgment.current.size > 0) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if ('query' in event) {
|
|
78
|
-
const { query, type } = event as QueryCacheNotifyEvent;
|
|
79
|
-
const queryCache = queryClient.getQueryCache();
|
|
80
|
-
|
|
81
|
-
if (type === 'updated') {
|
|
82
|
-
const existingQuery = queryCache.get(query.queryHash);
|
|
83
|
-
if (existingQuery) {
|
|
84
|
-
existingQuery.setState(query.state);
|
|
85
|
-
} else {
|
|
86
|
-
queryCache.build(
|
|
87
|
-
queryClient,
|
|
88
|
-
{
|
|
89
|
-
queryKey: query.queryKey,
|
|
90
|
-
queryHash: query.queryHash,
|
|
91
|
-
},
|
|
92
|
-
query.state
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
} else if (type === 'added') {
|
|
96
|
-
const existingQuery = queryCache.get(query.queryHash);
|
|
97
|
-
if (!existingQuery) {
|
|
98
|
-
// Only add if it doesn't already exist
|
|
99
|
-
queryCache.build(
|
|
100
|
-
queryClient,
|
|
101
|
-
{
|
|
102
|
-
queryKey: query.queryKey,
|
|
103
|
-
queryHash: query.queryHash,
|
|
104
|
-
},
|
|
105
|
-
query.state
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
} else if (type === 'removed') {
|
|
109
|
-
const existingQuery = queryCache.get(query.queryHash);
|
|
110
|
-
if (existingQuery) {
|
|
111
|
-
queryCache.remove(existingQuery);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
} else if ('mutation' in event) {
|
|
115
|
-
const { mutation, type } = event as MutationCacheNotifyEvent;
|
|
116
|
-
const mutationCache = queryClient.getMutationCache();
|
|
117
|
-
|
|
118
|
-
if (type === 'added') {
|
|
119
|
-
const existingMutation = mutationCache.find({ mutationKey: mutation.options.mutationKey });
|
|
120
|
-
if (existingMutation) {
|
|
121
|
-
mutationCache.remove(existingMutation);
|
|
122
|
-
}
|
|
23
|
+
return <ReactQueryDevtoolsPanel />;
|
|
24
|
+
};
|
|
123
25
|
|
|
124
|
-
|
|
125
|
-
queryClient,
|
|
126
|
-
mutation.options,
|
|
127
|
-
mutation.state
|
|
128
|
-
);
|
|
129
|
-
} else if (type === 'removed') {
|
|
130
|
-
const existingMutation = mutationCache.find({ mutationKey: mutation.options.mutationKey });
|
|
131
|
-
if (existingMutation) {
|
|
132
|
-
mutationCache.remove(existingMutation);
|
|
133
|
-
}
|
|
134
|
-
} else if (type === 'updated') {
|
|
135
|
-
const existingMutation = mutationCache.find({ mutationKey: mutation.options.mutationKey });
|
|
136
|
-
|
|
137
|
-
if (existingMutation) {
|
|
138
|
-
mutationCache.remove(existingMutation);
|
|
139
|
-
mutationCache.build(
|
|
140
|
-
queryClient,
|
|
141
|
-
mutation.options,
|
|
142
|
-
mutation.state
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
const initialDataSubscription = client.onMessage("DEVICE_TO_DEVTOOLS_INITIAL_DATA", (event) => {
|
|
150
|
-
// Clear existing data first
|
|
151
|
-
queryClient.clear();
|
|
152
|
-
queryClient.getMutationCache().clear();
|
|
153
|
-
|
|
154
|
-
// Restore queries
|
|
155
|
-
const queryCache = queryClient.getQueryCache();
|
|
156
|
-
event.queries.forEach(query => {
|
|
157
|
-
queryCache.build(
|
|
158
|
-
queryClient,
|
|
159
|
-
{
|
|
160
|
-
queryKey: query.queryKey,
|
|
161
|
-
queryHash: query.queryHash,
|
|
162
|
-
},
|
|
163
|
-
query.state
|
|
164
|
-
);
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
// Restore mutations
|
|
168
|
-
const mutationCache = queryClient.getMutationCache();
|
|
169
|
-
event.mutations.forEach(mutation => {
|
|
170
|
-
mutationCache.build(
|
|
171
|
-
queryClient,
|
|
172
|
-
mutation.options,
|
|
173
|
-
mutation.state
|
|
174
|
-
);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
return () => {
|
|
179
|
-
subscription.remove();
|
|
180
|
-
ackSubscription.remove();
|
|
181
|
-
initialDataSubscription.remove();
|
|
182
|
-
};
|
|
183
|
-
}, [client, queryClient])
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return (
|
|
187
|
-
<ReactQueryDevtoolsPanel />
|
|
188
|
-
)
|
|
189
|
-
}
|
|
26
|
+
const queryClient = new QueryClient();
|
|
190
27
|
|
|
191
28
|
export default function TanStackQueryPanel() {
|
|
192
29
|
return (
|
|
193
30
|
<QueryClientProvider client={queryClient}>
|
|
194
|
-
<
|
|
31
|
+
<App />
|
|
195
32
|
</QueryClientProvider>
|
|
196
|
-
)
|
|
197
|
-
}
|
|
33
|
+
);
|
|
34
|
+
}
|