@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.
- package/LICENSE +20 -0
- package/README.md +108 -0
- package/dist/assets/tanstack-query-CXp_Psxe.js +48 -0
- package/dist/react-native.cjs +1 -0
- package/dist/react-native.d.ts +5 -0
- package/dist/react-native.js +88 -0
- package/dist/rozenite.json +1 -0
- package/dist/tanstack-query.html +30 -0
- package/package.json +31 -0
- package/react-native.ts +8 -0
- package/rozenite.config.ts +8 -0
- package/src/react-native/useTanStackQueryDevTools.ts +214 -0
- package/src/ui/tanstack-query.tsx +197 -0
- package/tsconfig.json +25 -0
- package/vite.config.ts +20 -0
|
@@ -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,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
|
+
}
|
package/react-native.ts
ADDED
|
@@ -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,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
|
+
});
|