@rozenite/tanstack-query-plugin 1.0.0-alpha.0 → 1.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +2 -2
  2. package/dist/assets/CXEL7IU7-BTFA0aeQ.js +1172 -0
  3. package/dist/assets/tanstack-query-DWTo8DT_.js +48 -0
  4. package/dist/react-native.cjs +1 -1
  5. package/dist/react-native.d.ts +1 -5
  6. package/dist/react-native.js +3 -86
  7. package/dist/rozenite.config.d.ts +7 -0
  8. package/dist/rozenite.json +1 -1
  9. package/dist/src/react-native/useHandleDevToolsMessages.d.ts +3 -0
  10. package/dist/src/react-native/useHandleInitialData.d.ts +3 -0
  11. package/dist/src/react-native/useSyncTanStackCache.d.ts +3 -0
  12. package/dist/src/react-native/useTanStackQueryDevTools.d.ts +2 -0
  13. package/dist/src/shared/dehydrate.d.ts +6 -0
  14. package/dist/src/shared/hydrate.d.ts +10 -0
  15. package/dist/src/shared/messaging.d.ts +34 -0
  16. package/dist/src/shared/types.d.ts +25 -0
  17. package/dist/src/shared/useSyncOnlineStatus.d.ts +2 -0
  18. package/dist/src/ui/tanstack-query.d.ts +1 -0
  19. package/dist/src/ui/useHandleSyncMessages.d.ts +2 -0
  20. package/dist/src/ui/useSyncDevToolsEvents.d.ts +2 -0
  21. package/dist/src/ui/useSyncInitialData.d.ts +2 -0
  22. package/dist/tanstack-query.html +1 -1
  23. package/dist/useTanstackQueryDevTools.cjs +1 -0
  24. package/dist/useTanstackQueryDevTools.js +312 -0
  25. package/package.json +14 -9
  26. package/project.json +12 -0
  27. package/react-native.ts +2 -2
  28. package/src/react-native/useHandleDevToolsMessages.ts +119 -0
  29. package/src/react-native/useHandleInitialData.ts +24 -0
  30. package/src/react-native/useSyncTanStackCache.ts +246 -0
  31. package/src/react-native/useTanstackQueryDevTools.ts +21 -0
  32. package/src/shared/dehydrate.ts +42 -0
  33. package/src/shared/hydrate.ts +250 -0
  34. package/src/shared/messaging.ts +54 -0
  35. package/src/shared/types.ts +48 -0
  36. package/src/shared/useSyncOnlineStatus.ts +29 -0
  37. package/src/ui/tanstack-query.tsx +21 -184
  38. package/src/ui/useHandleSyncMessages.ts +66 -0
  39. package/src/ui/useSyncDevToolsEvents.ts +55 -0
  40. package/src/ui/useSyncInitialData.ts +14 -0
  41. package/tsconfig.json +13 -6
  42. package/tsconfig.tsbuildinfo +1 -0
  43. package/dist/assets/tanstack-query-CXp_Psxe.js +0 -48
  44. package/src/react-native/useTanStackQueryDevTools.ts +0 -214
@@ -0,0 +1,54 @@
1
+ import type { RozeniteDevToolsClient } from '@rozenite/plugin-bridge';
2
+ import {
3
+ DevToolsActionType,
4
+ SerializableQueryClient,
5
+ SerializableQuery,
6
+ SerializableMutation,
7
+ SerializableObserver,
8
+ PartialQueryState,
9
+ } from './types';
10
+
11
+ export type TanStackQueryPluginEventMap = {
12
+ 'online-status-changed': {
13
+ online: boolean;
14
+ };
15
+ 'devtools-action': {
16
+ type: DevToolsActionType;
17
+ queryHash: string;
18
+ };
19
+ 'request-initial-data': unknown;
20
+ 'sync-data': {
21
+ data: SerializableQueryClient;
22
+ };
23
+ 'sync-query-event':
24
+ | {
25
+ type: 'added' | 'removed';
26
+ data: SerializableQuery;
27
+ }
28
+ | {
29
+ type: 'updated';
30
+ action?: string; // Add action type for optimization
31
+ data: SerializableQuery | PartialQueryState; // Support both full and partial state
32
+ }
33
+ | {
34
+ type: 'observerAdded' | 'observerRemoved' | 'observerOptionsUpdated';
35
+ data: {
36
+ queryHash: string;
37
+ observers: SerializableObserver[];
38
+ };
39
+ };
40
+ 'sync-mutation-event': {
41
+ type:
42
+ | 'added'
43
+ | 'updated'
44
+ | 'removed'
45
+ | 'observerAdded'
46
+ | 'observerRemoved'
47
+ | 'observerResultsUpdated'
48
+ | 'observerOptionsUpdated';
49
+ data: SerializableMutation;
50
+ };
51
+ };
52
+
53
+ export type TanStackQueryPluginClient =
54
+ RozeniteDevToolsClient<TanStackQueryPluginEventMap>;
@@ -0,0 +1,48 @@
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 PartialQueryState = {
18
+ queryHash: string;
19
+ state: Partial<QueryState>;
20
+ };
21
+
22
+ export type SerializableMutation = {
23
+ mutationId: number;
24
+ options: MutationOptions;
25
+ state: MutationState;
26
+ };
27
+
28
+ export type SerializableObserver = {
29
+ queryHash: string;
30
+ options: QueryObserverOptions | InfiniteQueryObserverOptions;
31
+ };
32
+
33
+ export type SerializableQueryClient = {
34
+ queries: SerializableQuery[];
35
+ mutations: SerializableMutation[];
36
+ };
37
+
38
+ export type DevToolsActionType =
39
+ | 'REFETCH'
40
+ | 'INVALIDATE'
41
+ | 'RESET'
42
+ | 'REMOVE'
43
+ | 'TRIGGER_ERROR'
44
+ | 'RESTORE_ERROR'
45
+ | 'TRIGGER_LOADING'
46
+ | 'RESTORE_LOADING'
47
+ | 'CLEAR_MUTATION_CACHE'
48
+ | 'CLEAR_QUERY_CACHE';
@@ -0,0 +1,29 @@
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
+ onlineManager.setOnline(online);
21
+ }
22
+ );
23
+
24
+ return () => {
25
+ onlineManagerSubscription();
26
+ onlineMessageSubscription.remove();
27
+ };
28
+ }, [client]);
29
+ };
@@ -1,197 +1,34 @@
1
- import { QueryCacheNotifyEvent, MutationCacheNotifyEvent, QueryClient, QueryClientProvider, Query, Mutation } from '@tanstack/react-query';
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 { useEffect, useRef } from 'react';
5
-
6
- const queryClient = new QueryClient({
7
- defaultOptions: {
8
- queries: {
9
- queryFn: async () => {
10
- // Prevent refetch from throwing an error
11
- return Promise.resolve(null);
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
- const handleEvent = (event: Event) => {
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
- window.addEventListener('@tanstack/query-devtools-event', handleEvent);
60
- return () => window.removeEventListener('@tanstack/query-devtools-event', handleEvent);
61
- }, [client])
17
+ useSyncDevToolsEvents(client);
62
18
 
63
- useEffect(() => {
64
- if (!client) return;
19
+ useSyncOnlineStatus(client);
65
20
 
66
- const ackSubscription = client.onMessage("DEVICE_TO_DEVTOOLS_ACK", (ack) => {
67
- // Remove the request from pending acknowledgments
68
- pendingAcknowledgment.current.delete(ack.requestId);
69
- });
21
+ useHandleSyncMessages(client);
70
22
 
71
- const subscription = client.onMessage("DEVICE_TO_DEVTOOLS", (event) => {
72
- // Don't reflect events if we're waiting for acknowledgments
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 style={{ height: '100%', width: '100%' }} />;
24
+ };
123
25
 
124
- mutationCache.build(
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
- <Wrapped />
31
+ <App />
195
32
  </QueryClientProvider>
196
- )
197
- }
33
+ );
34
+ }
@@ -0,0 +1,66 @@
1
+ import { useEffect } from 'react';
2
+ import { TanStackQueryPluginClient } from '../shared/messaging';
3
+ import { useQueryClient } from '@tanstack/react-query';
4
+ import {
5
+ hydrateQueryClient,
6
+ applyQueryEvent,
7
+ applyMutationEvent,
8
+ applyQueryObserverEvent,
9
+ } from '../shared/hydrate';
10
+
11
+ export const useHandleSyncMessages = (
12
+ client: TanStackQueryPluginClient | null
13
+ ) => {
14
+ const queryClient = useQueryClient();
15
+
16
+ useEffect(() => {
17
+ if (!client) {
18
+ return;
19
+ }
20
+
21
+ const querySubscription = client.onMessage(
22
+ 'sync-query-event',
23
+ (message) => {
24
+ const { type, data } = message;
25
+
26
+ if (type === 'added' || type === 'removed') {
27
+ applyQueryEvent(queryClient, type, data);
28
+ return;
29
+ }
30
+
31
+ if (type === 'updated') {
32
+ const action = 'action' in message ? message.action : undefined;
33
+ applyQueryEvent(queryClient, type, data, action);
34
+ return;
35
+ }
36
+
37
+ if (
38
+ type === 'observerAdded' ||
39
+ type === 'observerRemoved' ||
40
+ type === 'observerOptionsUpdated'
41
+ ) {
42
+ applyQueryObserverEvent(queryClient, data);
43
+ return;
44
+ }
45
+ }
46
+ );
47
+
48
+ const mutationSubscription = client.onMessage(
49
+ 'sync-mutation-event',
50
+ ({ type, data }) => {
51
+ applyMutationEvent(queryClient, type, data);
52
+ }
53
+ );
54
+
55
+ // Keep the full sync for initial data requests
56
+ const fullSyncSubscription = client.onMessage('sync-data', ({ data }) => {
57
+ hydrateQueryClient(queryClient, data);
58
+ });
59
+
60
+ return () => {
61
+ querySubscription.remove();
62
+ mutationSubscription.remove();
63
+ fullSyncSubscription.remove();
64
+ };
65
+ }, [client, queryClient]);
66
+ };
@@ -0,0 +1,55 @@
1
+ import { useQueryClient } from '@tanstack/react-query';
2
+ import { useEffect } from 'react';
3
+ import { TanStackQueryPluginClient } from '../shared/messaging';
4
+
5
+ export const useSyncDevToolsEvents = (
6
+ client: TanStackQueryPluginClient | null
7
+ ) => {
8
+ const queryClient = useQueryClient();
9
+
10
+ useEffect(() => {
11
+ if (!client) {
12
+ return;
13
+ }
14
+
15
+ const handleEvent = (event: Event) => {
16
+ const detail = (event as CustomEvent).detail;
17
+ const { type, queryHash } = detail;
18
+
19
+ // Get the query from cache if we have a hash
20
+ const query = queryHash
21
+ ? queryClient.getQueryCache().get(queryHash)
22
+ : undefined;
23
+ if (
24
+ !query &&
25
+ type !== 'CLEAR_QUERY_CACHE' &&
26
+ type !== 'CLEAR_MUTATION_CACHE'
27
+ ) {
28
+ return;
29
+ }
30
+
31
+ // Special handling for cache clear actions which don't require a query
32
+ if (type === 'CLEAR_QUERY_CACHE' || type === 'CLEAR_MUTATION_CACHE') {
33
+ client.send('devtools-action', {
34
+ type,
35
+ queryHash: '',
36
+ });
37
+ return;
38
+ }
39
+
40
+ // For all other actions, ensure we have a valid query
41
+ if (!query || !queryHash) {
42
+ return;
43
+ }
44
+
45
+ client.send('devtools-action', {
46
+ type,
47
+ queryHash: query.queryHash,
48
+ });
49
+ };
50
+
51
+ window.addEventListener('@tanstack/query-devtools-event', handleEvent);
52
+ return () =>
53
+ window.removeEventListener('@tanstack/query-devtools-event', handleEvent);
54
+ }, [client]);
55
+ };
@@ -0,0 +1,14 @@
1
+ import { useEffect } from 'react';
2
+ import { TanStackQueryPluginClient } from '../shared/messaging';
3
+
4
+ export const useSyncInitialData = (
5
+ client: TanStackQueryPluginClient | null
6
+ ) => {
7
+ useEffect(() => {
8
+ if (!client) {
9
+ return;
10
+ }
11
+
12
+ client.send('request-initial-data', {});
13
+ }, [client]);
14
+ };
package/tsconfig.json CHANGED
@@ -16,10 +16,17 @@
16
16
  "noEmit": true,
17
17
  "jsx": "react-jsx"
18
18
  },
19
- "include": [
20
- "src/**/*",
21
- "react-native.ts",
22
- "rozenite.config.ts"
23
- ],
24
- "exclude": ["node_modules", "dist", "build"]
19
+ "include": ["src/**/*", "react-native.ts", "rozenite.config.ts"],
20
+ "exclude": ["node_modules", "dist", "build"],
21
+ "references": [
22
+ {
23
+ "path": "../plugin-bridge"
24
+ },
25
+ {
26
+ "path": "../cli"
27
+ },
28
+ {
29
+ "path": "../vite-plugin"
30
+ }
31
+ ]
25
32
  }
@@ -0,0 +1 @@
1
+ {"root":["./src/react-native/usehandledevtoolsmessages.ts","./src/react-native/usehandleinitialdata.ts","./src/react-native/usesynctanstackcache.ts","./src/react-native/usetanstackquerydevtools.ts","./src/shared/dehydrate.ts","./src/shared/hydrate.ts","./src/shared/messaging.ts","./src/shared/types.ts","./src/shared/usesynconlinestatus.ts","./src/ui/tanstack-query.tsx","./src/ui/usehandlesyncmessages.ts","./src/ui/usesyncdevtoolsevents.ts","./src/ui/usesyncinitialdata.ts","./react-native.ts","./rozenite.config.ts"],"errors":true,"version":"5.8.3"}