@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
package/package.json CHANGED
@@ -1,27 +1,32 @@
1
1
  {
2
2
  "name": "@rozenite/tanstack-query-plugin",
3
- "version": "1.0.0-alpha.1",
3
+ "version": "1.0.0-alpha.10",
4
4
  "description": "TanStack Query for Rozenite.",
5
5
  "type": "module",
6
6
  "main": "./dist/react-native.cjs",
7
7
  "module": "./dist/react-native.js",
8
8
  "types": "./dist/react-native.d.ts",
9
9
  "dependencies": {
10
- "@rozenite/plugin-bridge": "1.0.0-alpha.0"
10
+ "fast-deep-equal": "^3.1.3",
11
+ "@rozenite/plugin-bridge": "1.0.0-alpha.10"
11
12
  },
12
13
  "devDependencies": {
14
+ "@tanstack/react-query": "^5.0.0",
13
15
  "@tanstack/react-query-devtools": "^5.0.0",
16
+ "@types/react": "~18.3.12",
17
+ "react": "18.3.1",
18
+ "react-dom": "18.3.0",
19
+ "react-native": "0.76.0",
20
+ "react-native-web": "0.21.0",
14
21
  "typescript": "^5.7.3",
15
22
  "vite": "^6.0.0",
16
- "react": "*",
17
- "react-native": "*",
18
- "rozenite": "1.0.0-alpha.0",
19
- "@rozenite/vite-plugin": "1.0.0-alpha.1"
23
+ "rozenite": "1.0.0-alpha.10",
24
+ "@rozenite/vite-plugin": "1.0.0-alpha.10"
20
25
  },
21
26
  "peerDependencies": {
22
- "react": ">= 17.0.0",
23
- "react-native": ">= 0.74.0",
24
- "@tanstack/react-query": "^5.0.0"
27
+ "@tanstack/react-query": "^5.0.0",
28
+ "react": "*",
29
+ "react-native": "*"
25
30
  },
26
31
  "license": "MIT",
27
32
  "scripts": {
package/project.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
3
+ "name": "@rozenite/tanstack-query-plugin",
4
+ "targets": {
5
+ "build": {
6
+ "cache": true,
7
+ "dependsOn": ["^build"],
8
+ "inputs": ["{projectRoot}/src/**/*"],
9
+ "outputs": ["{projectRoot}/dist"]
10
+ }
11
+ }
12
+ }
package/react-native.ts CHANGED
@@ -1,8 +1,8 @@
1
-
2
1
  export let useTanStackQueryDevTools: typeof import('./src/react-native/useTanStackQueryDevTools').useTanStackQueryDevTools;
3
2
 
4
3
  if (process.env.NODE_ENV !== 'production') {
5
- useTanStackQueryDevTools = require('./src/react-native/useTanStackQueryDevTools').useTanStackQueryDevTools;
4
+ useTanStackQueryDevTools =
5
+ require('./src/react-native/useTanStackQueryDevTools').useTanStackQueryDevTools;
6
6
  } else {
7
7
  useTanStackQueryDevTools = () => ({ isConnected: false });
8
8
  }
@@ -1,12 +1,11 @@
1
1
  import { useEffect } from 'react';
2
- import { useQueryClient } from '@tanstack/react-query';
2
+ import { QueryClient } from '@tanstack/react-query';
3
3
  import { TanStackQueryPluginClient } from '../shared/messaging';
4
4
 
5
5
  export const useHandleDevToolsMessages = (
6
+ queryClient: QueryClient,
6
7
  client: TanStackQueryPluginClient | null
7
8
  ) => {
8
- const queryClient = useQueryClient();
9
-
10
9
  useEffect(() => {
11
10
  if (!client) {
12
11
  return;
@@ -1,13 +1,12 @@
1
1
  import { useEffect } from 'react';
2
2
  import { TanStackQueryPluginClient } from '../shared/messaging';
3
- import { useQueryClient } from '@tanstack/react-query';
3
+ import { QueryClient } from '@tanstack/react-query';
4
4
  import { dehydrateQueryClient } from '../shared/dehydrate';
5
5
 
6
6
  export const useHandleInitialData = (
7
+ queryClient: QueryClient,
7
8
  client: TanStackQueryPluginClient | null
8
9
  ) => {
9
- const queryClient = useQueryClient();
10
-
11
10
  useEffect(() => {
12
11
  if (!client) {
13
12
  return;
@@ -1,23 +1,236 @@
1
- import { useQueryClient } from '@tanstack/react-query';
2
- import { useEffect } from 'react';
1
+ import {
2
+ QueryClient,
3
+ QueryCacheNotifyEvent,
4
+ MutationCacheNotifyEvent,
5
+ } from '@tanstack/react-query';
6
+ import { useEffect, useMemo, useRef } from 'react';
7
+ import equal from 'fast-deep-equal';
3
8
  import { TanStackQueryPluginClient } from '../shared/messaging';
4
- import { dehydrateQueryClient } from '../shared/dehydrate';
9
+ import {
10
+ dehydrateQuery,
11
+ dehydrateMutation,
12
+ dehydrateObservers,
13
+ } from '../shared/dehydrate';
14
+ import { SerializableObserver, PartialQueryState } from '../shared/types';
5
15
 
6
16
  export const useSyncTanStackCache = (
17
+ queryClient: QueryClient,
7
18
  client: TanStackQueryPluginClient | null
8
19
  ) => {
9
- const queryClient = useQueryClient();
20
+ const previousObserversRef = useRef<Map<string, SerializableObserver[]>>(
21
+ new Map()
22
+ );
23
+
24
+ const handler = useMemo(() => {
25
+ return (event: QueryCacheNotifyEvent | MutationCacheNotifyEvent): void => {
26
+ if (!client) {
27
+ return;
28
+ }
29
+
30
+ if (event.type === 'observerResultsUpdated') {
31
+ // We don't need to sync this type of events.
32
+ return;
33
+ }
34
+
35
+ if ('query' in event) {
36
+ const { query, type } = event;
37
+
38
+ if (type === 'added' || type === 'removed') {
39
+ if (type === 'removed') {
40
+ // We don't need to store observers for removed queries.
41
+ previousObserversRef.current.delete(query.queryHash);
42
+ }
43
+
44
+ const dehydratedQuery = dehydrateQuery(query);
45
+ client.send('sync-query-event', { type, data: dehydratedQuery });
46
+ return;
47
+ }
48
+
49
+ if (type === 'updated' && 'action' in event) {
50
+ const action = event.action;
51
+
52
+ switch (action.type) {
53
+ case 'fetch': {
54
+ // Only need loading state and fetch metadata
55
+ const fetchData: PartialQueryState = {
56
+ queryHash: query.queryHash,
57
+ state: {
58
+ status: query.state.status,
59
+ fetchStatus: query.state.fetchStatus,
60
+ fetchMeta: query.state.fetchMeta,
61
+ dataUpdatedAt: query.state.dataUpdatedAt,
62
+ errorUpdatedAt: query.state.errorUpdatedAt,
63
+ },
64
+ };
65
+ client.send('sync-query-event', {
66
+ type: 'updated',
67
+ action: 'fetch',
68
+ data: fetchData,
69
+ });
70
+ break;
71
+ }
72
+
73
+ case 'success': {
74
+ // Only need new data and success state
75
+ const successData: PartialQueryState = {
76
+ queryHash: query.queryHash,
77
+ state: {
78
+ status: query.state.status,
79
+ data: query.state.data,
80
+ dataUpdatedAt: query.state.dataUpdatedAt,
81
+ error: query.state.error,
82
+ errorUpdatedAt: query.state.errorUpdatedAt,
83
+ fetchStatus: query.state.fetchStatus,
84
+ },
85
+ };
86
+ client.send('sync-query-event', {
87
+ type: 'updated',
88
+ action: 'success',
89
+ data: successData,
90
+ });
91
+ break;
92
+ }
93
+
94
+ case 'error': {
95
+ // Only need error information
96
+ const errorData: PartialQueryState = {
97
+ queryHash: query.queryHash,
98
+ state: {
99
+ status: query.state.status,
100
+ error: query.state.error,
101
+ errorUpdatedAt: query.state.errorUpdatedAt,
102
+ fetchStatus: query.state.fetchStatus,
103
+ },
104
+ };
105
+ client.send('sync-query-event', {
106
+ type: 'updated',
107
+ action: 'error',
108
+ data: errorData,
109
+ });
110
+ break;
111
+ }
112
+
113
+ case 'setState': {
114
+ // Only need the specific state changes
115
+ const setStateData: PartialQueryState = {
116
+ queryHash: query.queryHash,
117
+ state: action.state, // Only the changed state parts
118
+ };
119
+ client.send('sync-query-event', {
120
+ type: 'updated',
121
+ action: 'setState',
122
+ data: setStateData,
123
+ });
124
+ break;
125
+ }
126
+
127
+ case 'invalidate': {
128
+ // Only need invalidation flag
129
+ const invalidateData: PartialQueryState = {
130
+ queryHash: query.queryHash,
131
+ state: {
132
+ isInvalidated: query.state.isInvalidated,
133
+ },
134
+ };
135
+ client.send('sync-query-event', {
136
+ type: 'updated',
137
+ action: 'invalidate',
138
+ data: invalidateData,
139
+ });
140
+ break;
141
+ }
142
+
143
+ case 'pause': {
144
+ // Need to sync the paused fetch status
145
+ const pauseData: PartialQueryState = {
146
+ queryHash: query.queryHash,
147
+ state: {
148
+ fetchStatus: query.state.fetchStatus,
149
+ },
150
+ };
151
+ client.send('sync-query-event', {
152
+ type: 'updated',
153
+ action: 'pause',
154
+ data: pauseData,
155
+ });
156
+ break;
157
+ }
158
+
159
+ case 'continue': {
160
+ // Need to sync the resumed fetch status
161
+ const continueData: PartialQueryState = {
162
+ queryHash: query.queryHash,
163
+ state: {
164
+ fetchStatus: query.state.fetchStatus,
165
+ },
166
+ };
167
+ client.send('sync-query-event', {
168
+ type: 'updated',
169
+ action: 'continue',
170
+ data: continueData,
171
+ });
172
+ break;
173
+ }
174
+
175
+ default: {
176
+ // Fallback to full data for unknown actions
177
+ const dehydratedQuery = dehydrateQuery(query);
178
+ client.send('sync-query-event', { type, data: dehydratedQuery });
179
+ }
180
+ }
181
+ return;
182
+ }
183
+
184
+ if (
185
+ type === 'observerAdded' ||
186
+ type === 'observerRemoved' ||
187
+ type === 'observerOptionsUpdated'
188
+ ) {
189
+ const dehydratedObservers = dehydrateObservers(query);
190
+ const previousObservers = previousObserversRef.current.get(
191
+ query.queryHash
192
+ );
193
+
194
+ // For observerOptionsUpdated, only send if the observers actually changed
195
+ if (type === 'observerOptionsUpdated' && previousObservers) {
196
+ if (equal(previousObservers, dehydratedObservers)) {
197
+ // No meaningful change, skip sending
198
+ return;
199
+ }
200
+ }
201
+
202
+ previousObserversRef.current.set(
203
+ query.queryHash,
204
+ dehydratedObservers
205
+ );
206
+
207
+ client.send('sync-query-event', {
208
+ type,
209
+ data: {
210
+ queryHash: query.queryHash,
211
+ observers: dehydratedObservers,
212
+ },
213
+ });
214
+ return;
215
+ }
216
+ }
217
+
218
+ const { mutation, type } = event;
219
+ if (mutation) {
220
+ const dehydratedMutation = dehydrateMutation(mutation);
221
+ client.send('sync-mutation-event', {
222
+ type,
223
+ data: dehydratedMutation,
224
+ });
225
+ }
226
+ };
227
+ }, [client]);
10
228
 
11
229
  useEffect(() => {
12
230
  if (!client) {
13
231
  return;
14
232
  }
15
233
 
16
- const handler = (): void => {
17
- const dehydratedState = dehydrateQueryClient(queryClient);
18
- client.send('sync-data', { data: dehydratedState });
19
- };
20
-
21
234
  const mutationCacheSubscription = queryClient
22
235
  .getMutationCache()
23
236
  .subscribe(handler);
@@ -29,5 +242,5 @@ export const useSyncTanStackCache = (
29
242
  mutationCacheSubscription();
30
243
  queryCacheSubscription();
31
244
  };
32
- }, [client, queryClient]);
245
+ }, [client, queryClient, handler]);
33
246
  };
@@ -1,3 +1,4 @@
1
+ import { QueryClient } from '@tanstack/react-query';
1
2
  import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
2
3
  import { TanStackQueryPluginEventMap } from '../shared/messaging';
3
4
  import { useSyncOnlineStatus } from '../shared/useSyncOnlineStatus';
@@ -5,16 +6,16 @@ import { useHandleDevToolsMessages } from './useHandleDevToolsMessages';
5
6
  import { useSyncTanStackCache } from './useSyncTanStackCache';
6
7
  import { useHandleInitialData } from './useHandleInitialData';
7
8
 
8
- export const useTanStackQueryDevTools = () => {
9
+ export const useTanStackQueryDevTools = (queryClient: QueryClient) => {
9
10
  const client = useRozeniteDevToolsClient<TanStackQueryPluginEventMap>({
10
11
  pluginId: '@rozenite/tanstack-query-plugin',
11
12
  });
12
13
 
13
14
  useSyncOnlineStatus(client);
14
15
 
15
- useHandleDevToolsMessages(client);
16
+ useHandleDevToolsMessages(queryClient, client);
16
17
 
17
- useSyncTanStackCache(client);
18
+ useSyncTanStackCache(queryClient, client);
18
19
 
19
- useHandleInitialData(client);
20
+ useHandleInitialData(queryClient, client);
20
21
  };
@@ -6,13 +6,15 @@ import type {
6
6
  SerializableQueryClient,
7
7
  } from './types';
8
8
 
9
+ export const dehydrateObservers = (query: Query): SerializableObserver[] => {
10
+ return query.observers.map((observer) => ({
11
+ queryHash: query.queryHash,
12
+ options: observer.options,
13
+ }));
14
+ };
15
+
9
16
  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
- );
17
+ const dehydratedObservers: SerializableObserver[] = dehydrateObservers(query);
16
18
 
17
19
  return {
18
20
  state: query.state,