@rozenite/tanstack-query-plugin 1.0.0-alpha.1 → 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 (41) 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 -150
  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 +2 -3
  29. package/src/react-native/useHandleInitialData.ts +2 -3
  30. package/src/react-native/useSyncTanStackCache.ts +223 -10
  31. package/src/react-native/{useTanStackQueryDevTools.ts → useTanstackQueryDevTools.ts} +5 -4
  32. package/src/shared/dehydrate.ts +8 -6
  33. package/src/shared/hydrate.ts +218 -74
  34. package/src/shared/messaging.ts +36 -1
  35. package/src/shared/types.ts +5 -0
  36. package/src/shared/useSyncOnlineStatus.ts +2 -3
  37. package/src/ui/tanstack-query.tsx +2 -2
  38. package/src/ui/useHandleSyncMessages.ts +45 -3
  39. package/tsconfig.json +13 -6
  40. package/tsconfig.tsbuildinfo +1 -0
  41. package/dist/assets/tanstack-query-4kxOTB8B.js +0 -48
@@ -7,100 +7,244 @@ import {
7
7
  QueryObserverOptions,
8
8
  QueryState,
9
9
  } from '@tanstack/react-query';
10
- import { SerializableQueryClient } from './types';
10
+ import type {
11
+ SerializableQuery,
12
+ SerializableMutation,
13
+ SerializableQueryClient,
14
+ SerializableObserver,
15
+ PartialQueryState,
16
+ } from './types';
11
17
 
12
18
  const mockQueryFn = () => {
13
19
  return Promise.resolve(null);
14
20
  };
15
21
 
16
- export const hydrateQueryClient = (
22
+ const hydrateObservers = (
17
23
  client: QueryClient,
18
- dehydratedState: SerializableQueryClient
19
- ): void => {
20
- const queryCache = client.getQueryCache();
21
- const mutationCache = client.getMutationCache();
24
+ queryHash: string,
25
+ dehydratedObservers: SerializableObserver[]
26
+ ) => {
27
+ const query = client.getQueryCache().get(queryHash);
28
+
29
+ if (!query) {
30
+ return;
31
+ }
32
+
33
+ query.observers.forEach((observer) => {
34
+ query.removeObserver(observer);
35
+ });
22
36
 
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);
37
+ dehydratedObservers.forEach((observerState) => {
38
+ const hydratedOptions: InfiniteQueryObserverOptions | QueryObserverOptions =
39
+ observerState.options;
40
+
41
+ if ('initialPageParam' in hydratedOptions) {
42
+ delete hydratedOptions.initialPageParam;
43
+ }
44
+
45
+ if ('behavior' in hydratedOptions) {
46
+ delete hydratedOptions.behavior;
34
47
  }
35
48
 
36
- mutationCache.build(client, hydratedOptions, hydratedState);
49
+ hydratedOptions.queryFn = mockQueryFn;
50
+
51
+ const observer = new QueryObserver(
52
+ client,
53
+ hydratedOptions as QueryObserverOptions
54
+ );
55
+ query.addObserver(observer);
56
+ });
57
+ };
58
+
59
+ const hydrateMutation = (
60
+ client: QueryClient,
61
+ dehydratedMutation: SerializableMutation
62
+ ) => {
63
+ const mutationCache = client.getMutationCache();
64
+ const { options, state } = dehydratedMutation;
65
+
66
+ const existingMutation = mutationCache.find({
67
+ mutationKey: options.mutationKey,
37
68
  });
69
+ const hydratedState: MutationState<unknown, Error, void, unknown> =
70
+ state as MutationState<unknown, Error, void, unknown>;
71
+ const hydratedOptions: MutationOptions = options;
72
+
73
+ if (existingMutation) {
74
+ mutationCache.remove(existingMutation);
75
+ }
76
+
77
+ mutationCache.build(client, hydratedOptions, hydratedState);
78
+ };
79
+
80
+ const hydrateQuery = (
81
+ client: QueryClient,
82
+ dehydratedQuery: SerializableQuery
83
+ ) => {
84
+ const queryCache = client.getQueryCache();
85
+ const { queryKey, state, queryHash, observers } = dehydratedQuery;
86
+
87
+ let query = queryCache.get(queryHash);
88
+ const data = state.data;
89
+ const hydratedState: QueryState = state;
90
+
91
+ // Do not hydrate if an existing query exists with newer data
92
+ if (query) {
93
+ if (
94
+ query.state.dataUpdatedAt < state.dataUpdatedAt ||
95
+ query.state.fetchStatus !== state.fetchStatus
96
+ ) {
97
+ query.setState({
98
+ ...hydratedState,
99
+ data,
100
+ });
101
+ query.setOptions({
102
+ ...query.options,
103
+ queryFn: mockQueryFn,
104
+ retry: 0,
105
+ });
106
+ }
107
+ } else {
108
+ // Restore query
109
+ query = queryCache.build(
110
+ client,
111
+ {
112
+ ...client.getDefaultOptions().hydrate?.queries,
113
+ queryKey,
114
+ queryHash,
115
+ queryFn: mockQueryFn,
116
+ },
117
+ {
118
+ ...hydratedState,
119
+ data,
120
+ }
121
+ );
122
+ }
123
+
124
+ hydrateObservers(client, queryHash, observers);
125
+ };
126
+
127
+ export const hydrateQueryClient = (
128
+ client: QueryClient,
129
+ dehydratedState: SerializableQueryClient
130
+ ): void => {
131
+ // Hydrate mutations
132
+ dehydratedState.mutations.forEach((mutation) =>
133
+ hydrateMutation(client, mutation)
134
+ );
38
135
 
39
136
  // 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;
137
+ dehydratedState.queries.forEach((query) => hydrateQuery(client, query));
138
+ };
45
139
 
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
- }
140
+ export const applyQueryEvent = (
141
+ queryClient: QueryClient,
142
+ type:
143
+ | 'added'
144
+ | 'updated'
145
+ | 'removed'
146
+ | 'observerAdded'
147
+ | 'observerRemoved'
148
+ | 'observerResultsUpdated'
149
+ | 'observerOptionsUpdated',
150
+ data: SerializableQuery | PartialQueryState,
151
+ action?: string
152
+ ): void => {
153
+ const queryCache = queryClient.getQueryCache();
154
+
155
+ switch (type) {
156
+ case 'added': {
157
+ hydrateQuery(queryClient, data as SerializableQuery);
158
+ break;
159
+ }
160
+ case 'updated': {
161
+ if (action && 'state' in data && !('queryKey' in data)) {
162
+ // Handle action-based partial state update
163
+ applyPartialQueryState(queryClient, data as PartialQueryState);
62
164
  } 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
- );
165
+ // Handle full query update (backward compatibility)
166
+ hydrateQuery(queryClient, data as SerializableQuery);
77
167
  }
168
+ break;
169
+ }
170
+ case 'observerAdded':
171
+ case 'observerRemoved':
172
+ case 'observerOptionsUpdated': {
173
+ hydrateObservers(queryClient, data.queryHash, (data as any).observers);
174
+ break;
175
+ }
176
+ case 'removed': {
177
+ const query = queryCache.get(data.queryHash);
178
+ if (query) {
179
+ queryCache.remove(query);
180
+ }
181
+ break;
182
+ }
183
+ }
184
+ };
78
185
 
79
- query.observers.forEach((observer) => {
80
- query.removeObserver(observer);
81
- });
82
-
83
- observers.forEach((observerState) => {
84
- const hydratedOptions:
85
- | InfiniteQueryObserverOptions
86
- | QueryObserverOptions = observerState.options;
186
+ // New function to handle action-based partial state updates
187
+ export const applyPartialQueryState = (
188
+ queryClient: QueryClient,
189
+ data: PartialQueryState
190
+ ): void => {
191
+ const queryCache = queryClient.getQueryCache();
192
+ const query = queryCache.get(data.queryHash);
87
193
 
88
- if ('initialPageParam' in hydratedOptions) {
89
- delete hydratedOptions.initialPageParam;
90
- }
194
+ if (!query) {
195
+ // Query doesn't exist, we need to create it with minimal data
196
+ // This is a fallback for when we receive a partial update for a non-existent query
197
+ return;
198
+ }
91
199
 
92
- if ('behavior' in hydratedOptions) {
93
- delete hydratedOptions.behavior;
94
- }
200
+ // Apply the partial state changes
201
+ if (data.state) {
202
+ query.setState(data.state);
203
+ }
204
+ };
95
205
 
96
- hydratedOptions.queryFn = mockQueryFn;
206
+ export const applyMutationEvent = (
207
+ queryClient: QueryClient,
208
+ type:
209
+ | 'added'
210
+ | 'updated'
211
+ | 'removed'
212
+ | 'observerAdded'
213
+ | 'observerRemoved'
214
+ | 'observerResultsUpdated'
215
+ | 'observerOptionsUpdated',
216
+ data: SerializableMutation
217
+ ): void => {
218
+ const mutationCache = queryClient.getMutationCache();
97
219
 
98
- const observer = new QueryObserver(
99
- client,
100
- hydratedOptions as QueryObserverOptions
101
- );
102
- query.addObserver(observer);
220
+ switch (type) {
221
+ case 'added':
222
+ case 'updated':
223
+ case 'observerAdded':
224
+ case 'observerRemoved':
225
+ case 'observerResultsUpdated':
226
+ case 'observerOptionsUpdated': {
227
+ hydrateMutation(queryClient, data);
228
+ break;
229
+ }
230
+ case 'removed': {
231
+ const mutation = mutationCache.find({
232
+ mutationKey: data.options.mutationKey,
103
233
  });
234
+ if (mutation) {
235
+ mutationCache.remove(mutation);
236
+ }
237
+ break;
104
238
  }
105
- );
239
+ }
240
+ };
241
+
242
+ export const applyQueryObserverEvent = (
243
+ queryClient: QueryClient,
244
+ data: {
245
+ queryHash: string;
246
+ observers: SerializableObserver[];
247
+ }
248
+ ): void => {
249
+ hydrateObservers(queryClient, data.queryHash, data.observers);
106
250
  };
@@ -1,5 +1,12 @@
1
1
  import type { RozeniteDevToolsClient } from '@rozenite/plugin-bridge';
2
- import { DevToolsActionType, SerializableQueryClient } from './types';
2
+ import {
3
+ DevToolsActionType,
4
+ SerializableQueryClient,
5
+ SerializableQuery,
6
+ SerializableMutation,
7
+ SerializableObserver,
8
+ PartialQueryState,
9
+ } from './types';
3
10
 
4
11
  export type TanStackQueryPluginEventMap = {
5
12
  'online-status-changed': {
@@ -13,6 +20,34 @@ export type TanStackQueryPluginEventMap = {
13
20
  'sync-data': {
14
21
  data: SerializableQueryClient;
15
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
+ };
16
51
  };
17
52
 
18
53
  export type TanStackQueryPluginClient =
@@ -14,6 +14,11 @@ export type SerializableQuery = {
14
14
  observers: SerializableObserver[];
15
15
  };
16
16
 
17
+ export type PartialQueryState = {
18
+ queryHash: string;
19
+ state: Partial<QueryState>;
20
+ };
21
+
17
22
  export type SerializableMutation = {
18
23
  mutationId: number;
19
24
  options: MutationOptions;
@@ -11,14 +11,13 @@ export const useSyncOnlineStatus = (
11
11
  }
12
12
 
13
13
  const onlineManagerSubscription = onlineManager.subscribe((online) => {
14
- // client.send('online-status-changed', { online });
14
+ client.send('online-status-changed', { online });
15
15
  });
16
16
 
17
17
  const onlineMessageSubscription = client.onMessage(
18
18
  'online-status-changed',
19
19
  ({ online }) => {
20
- console.log('changed from ', onlineManager.isOnline(), 'to', online);
21
- // onlineManager.setOnline(online);
20
+ onlineManager.setOnline(online);
22
21
  }
23
22
  );
24
23
 
@@ -1,5 +1,5 @@
1
1
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
2
- import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools';
2
+ import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools/production';
3
3
  import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
4
4
  import { TanStackQueryPluginEventMap } from '../shared/messaging';
5
5
  import { useSyncInitialData } from './useSyncInitialData';
@@ -20,7 +20,7 @@ const App = () => {
20
20
 
21
21
  useHandleSyncMessages(client);
22
22
 
23
- return <ReactQueryDevtoolsPanel />;
23
+ return <ReactQueryDevtoolsPanel style={{ height: '100%', width: '100%' }} />;
24
24
  };
25
25
 
26
26
  const queryClient = new QueryClient();
@@ -1,7 +1,12 @@
1
1
  import { useEffect } from 'react';
2
2
  import { TanStackQueryPluginClient } from '../shared/messaging';
3
3
  import { useQueryClient } from '@tanstack/react-query';
4
- import { hydrateQueryClient } from '../shared/hydrate';
4
+ import {
5
+ hydrateQueryClient,
6
+ applyQueryEvent,
7
+ applyMutationEvent,
8
+ applyQueryObserverEvent,
9
+ } from '../shared/hydrate';
5
10
 
6
11
  export const useHandleSyncMessages = (
7
12
  client: TanStackQueryPluginClient | null
@@ -13,12 +18,49 @@ export const useHandleSyncMessages = (
13
18
  return;
14
19
  }
15
20
 
16
- const subscription = client.onMessage('sync-data', ({ data }) => {
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 }) => {
17
57
  hydrateQueryClient(queryClient, data);
18
58
  });
19
59
 
20
60
  return () => {
21
- subscription.remove();
61
+ querySubscription.remove();
62
+ mutationSubscription.remove();
63
+ fullSyncSubscription.remove();
22
64
  };
23
65
  }, [client, queryClient]);
24
66
  };
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"}