@rozenite/tanstack-query-plugin 1.0.0-alpha.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.
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("@rozenite/plugin-bridge"),O=require("react"),D=u=>{const e=d.useRozeniteDevToolsClient({pluginId:"@rozenite/tanstack-query-plugin"});O.useEffect(()=>{if(!e)return;const c=e.onMessage("DEVTOOLS_TO_DEVICE_INITIAL_DATA_REQUEST",()=>{e.send("DEVICE_TO_DEVTOOLS_INITIAL_DATA",{queries:u.getQueryCache().getAll(),mutations:u.getMutationCache().getAll()})});return()=>c.remove()},[e,u]);const o=O.useRef(new Set),a=O.useCallback(c=>{const n=T=>u.getQueryCache().getAll().find(E=>E.queryHash===T);(T=>{var f;const{type:E,queryHash:t,metadata:_,requestId:s}=T;if(E==="REFETCH"&&t&&((f=n(t))==null||f.fetch(),s&&(o.current.add(s),e==null||e.send("DEVICE_TO_DEVTOOLS_ACK",{requestId:s,success:!0}),o.current.delete(s))),E==="INVALIDATE"&&t){const r=n(t);r&&u.invalidateQueries({queryKey:r.queryKey}),s&&(e==null||e.send("DEVICE_TO_DEVTOOLS_ACK",{requestId:s,success:!0}))}if(E==="RESET"&&t){const r=n(t);r&&u.resetQueries({queryKey:r.queryKey}),s&&(e==null||e.send("DEVICE_TO_DEVTOOLS_ACK",{requestId:s,success:!0}))}if(E==="REMOVE"&&t){const r=n(t);r&&u.removeQueries({queryKey:r.queryKey}),s&&(e==null||e.send("DEVICE_TO_DEVTOOLS_ACK",{requestId:s,success:!0}))}if(E==="TRIGGER_LOADING"&&t){const r=n(t);r&&(r.setState({...r.state,fetchStatus:"fetching",status:"pending",error:null}),s&&(o.current.add(s),e==null||e.send("DEVICE_TO_DEVTOOLS_ACK",{requestId:s,success:!0}),o.current.delete(s)))}if(E==="RESTORE_LOADING"&&t){const r=n(t);r&&(r.setState({...r.state,fetchStatus:"idle"}),s&&(o.current.add(s),e==null||e.send("DEVICE_TO_DEVTOOLS_ACK",{requestId:s,success:!0}),o.current.delete(s)))}if(E==="TRIGGER_ERROR"&&t){const r=n(t);r&&(r.setState({...r.state,fetchStatus:"idle",status:"error",error:(_==null?void 0:_.error)||new Error("Forced error via devtools"),errorUpdateCount:(r.state.errorUpdateCount??0)+1,errorUpdatedAt:Date.now()}),s&&(o.current.add(s),e==null||e.send("DEVICE_TO_DEVTOOLS_ACK",{requestId:s,success:!0}),o.current.delete(s)))}if(E==="RESTORE_ERROR"&&t){const r=n(t);r&&u.resetQueries({queryKey:r.queryKey}),s&&(e==null||e.send("DEVICE_TO_DEVTOOLS_ACK",{requestId:s,success:!0}))}E==="CLEAR_MUTATION_CACHE"&&(u.getMutationCache().clear(),s&&(e==null||e.send("DEVICE_TO_DEVTOOLS_ACK",{requestId:s,success:!0}))),E==="CLEAR_QUERY_CACHE"&&(u.clear(),s&&(e==null||e.send("DEVICE_TO_DEVTOOLS_ACK",{requestId:s,success:!0})))})(c)},[u,e]);O.useEffect(()=>{if(!e)return;const c=e.onMessage("DEVTOOLS_TO_DEVICE",a);return()=>c.remove()},[a,e]),O.useEffect(()=>{if(e)return u.getQueryCache().subscribe(c=>{o.current.size>0||e.send("DEVICE_TO_DEVTOOLS",c)})},[e,u]),O.useEffect(()=>{if(e)return u.getMutationCache().subscribe(c=>{o.current.size>0||e.send("DEVICE_TO_DEVTOOLS",c)})},[e,u])};exports.useTanStackQueryDevTools=void 0;process.env.NODE_ENV!=="production"?exports.useTanStackQueryDevTools=D:exports.useTanStackQueryDevTools=()=>({isConnected:!1});
@@ -0,0 +1,5 @@
1
+ import { useTanStackQueryDevTools as useTanStackQueryDevTools_2 } from './src/react-native/useTanStackQueryDevTools';
2
+
3
+ export declare let useTanStackQueryDevTools: useTanStackQueryDevTools_2;
4
+
5
+ export { }
@@ -0,0 +1,88 @@
1
+ import { useRozeniteDevToolsClient as D } from "@rozenite/plugin-bridge";
2
+ import { useEffect as _, useRef as i, useCallback as V } from "react";
3
+ const I = (u) => {
4
+ const e = D({
5
+ pluginId: "@rozenite/tanstack-query-plugin"
6
+ });
7
+ _(() => {
8
+ if (!e) return;
9
+ const n = e.onMessage("DEVTOOLS_TO_DEVICE_INITIAL_DATA_REQUEST", () => {
10
+ e.send("DEVICE_TO_DEVTOOLS_INITIAL_DATA", {
11
+ queries: u.getQueryCache().getAll(),
12
+ mutations: u.getMutationCache().getAll()
13
+ });
14
+ });
15
+ return () => n.remove();
16
+ }, [e, u]);
17
+ const o = i(/* @__PURE__ */ new Set()), a = V((n) => {
18
+ const O = (c) => u.getQueryCache().getAll().find((E) => E.queryHash === c);
19
+ ((c) => {
20
+ var f;
21
+ const { type: E, queryHash: t, metadata: T, requestId: s } = c;
22
+ if (E === "REFETCH" && t && ((f = O(t)) == null || f.fetch(), s && (o.current.add(s), e == null || e.send("DEVICE_TO_DEVTOOLS_ACK", { requestId: s, success: !0 }), o.current.delete(s))), E === "INVALIDATE" && t) {
23
+ const r = O(t);
24
+ r && u.invalidateQueries({ queryKey: r.queryKey }), s && (e == null || e.send("DEVICE_TO_DEVTOOLS_ACK", { requestId: s, success: !0 }));
25
+ }
26
+ if (E === "RESET" && t) {
27
+ const r = O(t);
28
+ r && u.resetQueries({ queryKey: r.queryKey }), s && (e == null || e.send("DEVICE_TO_DEVTOOLS_ACK", { requestId: s, success: !0 }));
29
+ }
30
+ if (E === "REMOVE" && t) {
31
+ const r = O(t);
32
+ r && u.removeQueries({ queryKey: r.queryKey }), s && (e == null || e.send("DEVICE_TO_DEVTOOLS_ACK", { requestId: s, success: !0 }));
33
+ }
34
+ if (E === "TRIGGER_LOADING" && t) {
35
+ const r = O(t);
36
+ r && (r.setState({
37
+ ...r.state,
38
+ fetchStatus: "fetching",
39
+ status: "pending",
40
+ error: null
41
+ }), s && (o.current.add(s), e == null || e.send("DEVICE_TO_DEVTOOLS_ACK", { requestId: s, success: !0 }), o.current.delete(s)));
42
+ }
43
+ if (E === "RESTORE_LOADING" && t) {
44
+ const r = O(t);
45
+ r && (r.setState({
46
+ ...r.state,
47
+ fetchStatus: "idle"
48
+ }), s && (o.current.add(s), e == null || e.send("DEVICE_TO_DEVTOOLS_ACK", { requestId: s, success: !0 }), o.current.delete(s)));
49
+ }
50
+ if (E === "TRIGGER_ERROR" && t) {
51
+ const r = O(t);
52
+ r && (r.setState({
53
+ ...r.state,
54
+ fetchStatus: "idle",
55
+ status: "error",
56
+ error: (T == null ? void 0 : T.error) || new Error("Forced error via devtools"),
57
+ errorUpdateCount: (r.state.errorUpdateCount ?? 0) + 1,
58
+ errorUpdatedAt: Date.now()
59
+ }), s && (o.current.add(s), e == null || e.send("DEVICE_TO_DEVTOOLS_ACK", { requestId: s, success: !0 }), o.current.delete(s)));
60
+ }
61
+ if (E === "RESTORE_ERROR" && t) {
62
+ const r = O(t);
63
+ r && u.resetQueries({ queryKey: r.queryKey }), s && (e == null || e.send("DEVICE_TO_DEVTOOLS_ACK", { requestId: s, success: !0 }));
64
+ }
65
+ E === "CLEAR_MUTATION_CACHE" && (u.getMutationCache().clear(), s && (e == null || e.send("DEVICE_TO_DEVTOOLS_ACK", { requestId: s, success: !0 }))), E === "CLEAR_QUERY_CACHE" && (u.clear(), s && (e == null || e.send("DEVICE_TO_DEVTOOLS_ACK", { requestId: s, success: !0 })));
66
+ })(n);
67
+ }, [u, e]);
68
+ _(() => {
69
+ if (!e) return;
70
+ const n = e.onMessage("DEVTOOLS_TO_DEVICE", a);
71
+ return () => n.remove();
72
+ }, [a, e]), _(() => {
73
+ if (e)
74
+ return u.getQueryCache().subscribe((n) => {
75
+ o.current.size > 0 || e.send("DEVICE_TO_DEVTOOLS", n);
76
+ });
77
+ }, [e, u]), _(() => {
78
+ if (e)
79
+ return u.getMutationCache().subscribe((n) => {
80
+ o.current.size > 0 || e.send("DEVICE_TO_DEVTOOLS", n);
81
+ });
82
+ }, [e, u]);
83
+ };
84
+ let d;
85
+ process.env.NODE_ENV !== "production" ? d = I : d = () => ({ isConnected: !1 });
86
+ export {
87
+ d as useTanStackQueryDevTools
88
+ };
@@ -0,0 +1 @@
1
+ {"name":"@rozenite/tanstack-query-plugin","version":"1.0.0-alpha.1","description":"TanStack Query for Rozenite.","panels":[{"name":"Tanstack Query","source":"/tanstack-query.html"}]}
@@ -0,0 +1,30 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>tanstack-query Panel</title>
7
+ <style>
8
+ html,
9
+ body {
10
+ height: 100%;
11
+ }
12
+
13
+ body {
14
+ overflow: hidden;
15
+ }
16
+
17
+ #root {
18
+ display: flex;
19
+ height: 100%;
20
+ }
21
+ </style>
22
+ <script>
23
+ var __ROZENITE_PANEL__ = true;
24
+ </script>
25
+ <script type="module" crossorigin src="./assets/tanstack-query-CXp_Psxe.js"></script>
26
+ </head>
27
+ <body>
28
+ <div id="root"></div>
29
+ </body>
30
+ </html>
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@rozenite/tanstack-query-plugin",
3
+ "version": "1.0.0-alpha.0",
4
+ "description": "TanStack Query for Rozenite.",
5
+ "type": "module",
6
+ "main": "./dist/react-native.cjs",
7
+ "module": "./dist/react-native.js",
8
+ "types": "./dist/react-native.d.ts",
9
+ "dependencies": {
10
+ "@rozenite/plugin-bridge": "1.0.0-alpha.0"
11
+ },
12
+ "devDependencies": {
13
+ "@tanstack/react-query-devtools": "^5.0.0",
14
+ "typescript": "^5.7.3",
15
+ "vite": "^6.0.0",
16
+ "react": "*",
17
+ "react-native": "*",
18
+ "rozenite": "1.0.0-alpha.2",
19
+ "@rozenite/vite-plugin": "1.0.0-alpha.1"
20
+ },
21
+ "peerDependencies": {
22
+ "react": ">= 17.0.0",
23
+ "react-native": ">= 0.74.0",
24
+ "@tanstack/react-query": "^5.0.0"
25
+ },
26
+ "license": "MIT",
27
+ "scripts": {
28
+ "build": "rozenite build",
29
+ "dev": "rozenite dev"
30
+ }
31
+ }
@@ -0,0 +1,8 @@
1
+
2
+ export let useTanStackQueryDevTools: typeof import('./src/react-native/useTanStackQueryDevTools').useTanStackQueryDevTools;
3
+
4
+ if (process.env.NODE_ENV !== 'production') {
5
+ useTanStackQueryDevTools = require('./src/react-native/useTanStackQueryDevTools').useTanStackQueryDevTools;
6
+ } else {
7
+ useTanStackQueryDevTools = () => ({ isConnected: false });
8
+ }
@@ -0,0 +1,8 @@
1
+ export default {
2
+ panels: [
3
+ {
4
+ name: 'Tanstack Query',
5
+ source: './src/ui/tanstack-query.tsx',
6
+ },
7
+ ],
8
+ };
@@ -0,0 +1,214 @@
1
+ import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
2
+ import type { QueryCacheNotifyEvent, MutationCacheNotifyEvent, QueryClient, Query, Mutation } from '@tanstack/react-query';
3
+ import { useCallback, useEffect, useRef } from 'react';
4
+
5
+ type DevToolsActionType =
6
+ | 'REFETCH'
7
+ | 'INVALIDATE'
8
+ | 'RESET'
9
+ | 'REMOVE'
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>({
35
+ 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]);
187
+
188
+ useEffect(() => {
189
+ if (!client) return;
190
+
191
+ return queryClient.getQueryCache().subscribe((event) => {
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]);
200
+
201
+ // Subscribe to mutation cache events
202
+ useEffect(() => {
203
+ if (!client) return;
204
+
205
+ return queryClient.getMutationCache().subscribe((event) => {
206
+ // Don't send events for mutations that have pending DevTools requests
207
+ if (pendingDevToolsRequests.current.size > 0) {
208
+ return;
209
+ }
210
+
211
+ client.send("DEVICE_TO_DEVTOOLS", event);
212
+ });
213
+ }, [client, queryClient]);
214
+ }
@@ -0,0 +1,197 @@
1
+ import { QueryCacheNotifyEvent, MutationCacheNotifyEvent, QueryClient, QueryClientProvider, Query, Mutation } from '@tanstack/react-query';
2
+ import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools';
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>({
27
+ 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;
40
+
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
+ };
58
+
59
+ window.addEventListener('@tanstack/query-devtools-event', handleEvent);
60
+ return () => window.removeEventListener('@tanstack/query-devtools-event', handleEvent);
61
+ }, [client])
62
+
63
+ useEffect(() => {
64
+ if (!client) return;
65
+
66
+ const ackSubscription = client.onMessage("DEVICE_TO_DEVTOOLS_ACK", (ack) => {
67
+ // Remove the request from pending acknowledgments
68
+ pendingAcknowledgment.current.delete(ack.requestId);
69
+ });
70
+
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
+ }
123
+
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
+ }
190
+
191
+ export default function TanStackQueryPanel() {
192
+ return (
193
+ <QueryClientProvider client={queryClient}>
194
+ <Wrapped />
195
+ </QueryClientProvider>
196
+ )
197
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "esModuleInterop": true,
8
+ "allowSyntheticDefaultImports": true,
9
+ "strict": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "noFallthroughCasesInSwitch": true,
12
+ "module": "ESNext",
13
+ "moduleResolution": "bundler",
14
+ "resolveJsonModule": true,
15
+ "isolatedModules": true,
16
+ "noEmit": true,
17
+ "jsx": "react-jsx"
18
+ },
19
+ "include": [
20
+ "src/**/*",
21
+ "react-native.ts",
22
+ "rozenite.config.ts"
23
+ ],
24
+ "exclude": ["node_modules", "dist", "build"]
25
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,20 @@
1
+ /// <reference types='vitest' />
2
+ import { defineConfig } from 'vite';
3
+ import { rozenitePlugin } from '@rozenite/vite-plugin';
4
+
5
+ export default defineConfig({
6
+ root: __dirname,
7
+ plugins: [rozenitePlugin()],
8
+ base: './',
9
+ build: {
10
+ outDir: './dist',
11
+ emptyOutDir: false,
12
+ reportCompressedSize: false,
13
+ minify: true,
14
+ sourcemap: false,
15
+ },
16
+ server: {
17
+ port: 3000,
18
+ open: true,
19
+ },
20
+ });