@buoy-gg/react-query 7.0.21 → 7.0.23
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.
|
@@ -55,6 +55,81 @@ function queryLabel(queryKey, queryHash) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
const ITEM_RENDER_BYTE_LIMIT = 256 * 1024;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A query `error` (and `fetchFailureReason`) usually holds the live
|
|
61
|
+
* Axios/fetch error: `request` points at the XHR, which is cyclic and would
|
|
62
|
+
* fail the whole snapshot's serialization. Only name + message survive —
|
|
63
|
+
* that's all a restored error state needs.
|
|
64
|
+
*/
|
|
65
|
+
function toStoredError(value) {
|
|
66
|
+
if (value == null) return value ?? null;
|
|
67
|
+
if (typeof value === "object") {
|
|
68
|
+
const err = value;
|
|
69
|
+
const name = typeof err.name === "string" ? err.name : undefined;
|
|
70
|
+
const message = typeof err.message === "string" ? err.message : undefined;
|
|
71
|
+
if (name !== undefined || message !== undefined) {
|
|
72
|
+
return {
|
|
73
|
+
...(name !== undefined ? {
|
|
74
|
+
name
|
|
75
|
+
} : {}),
|
|
76
|
+
...(message !== undefined ? {
|
|
77
|
+
message
|
|
78
|
+
} : {})
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Would the Time Machine vault be able to store this value? */
|
|
86
|
+
function isStorable(value) {
|
|
87
|
+
if (value === undefined) return true;
|
|
88
|
+
try {
|
|
89
|
+
(0, _sharedUi.superJsonSerialize)(value);
|
|
90
|
+
return true;
|
|
91
|
+
} catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* The queries as a SNAPSHOT sees them — raw.
|
|
98
|
+
*
|
|
99
|
+
* Deliberately NOT `dehydrateQueryClient()`: that is the WIRE form, which
|
|
100
|
+
* swaps any payload over 16KB for a `DATA_ON_DEVICE` marker so the dashboard
|
|
101
|
+
* stays inside its emit budget. Snapshots live on-device in persistentStorage
|
|
102
|
+
* with no such budget, and restoring a marker would write the placeholder
|
|
103
|
+
* object into the live cache — the app then renders `{__buoyDataOnDevice}` as
|
|
104
|
+
* if it were its data and crashes on the first field it reads.
|
|
105
|
+
*/
|
|
106
|
+
function captureQueries(client) {
|
|
107
|
+
const warnings = [];
|
|
108
|
+
const queries = [];
|
|
109
|
+
for (const query of client.getQueryCache().getAll()) {
|
|
110
|
+
const label = queryLabel(query.queryKey, query.queryHash);
|
|
111
|
+
if (!isStorable(query.state.data)) {
|
|
112
|
+
warnings.push(`query ${label}: data can't be serialized (circular reference?) — not captured`);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
queries.push({
|
|
116
|
+
queryKey: query.queryKey,
|
|
117
|
+
queryHash: query.queryHash,
|
|
118
|
+
...(query.meta && isStorable(query.meta) ? {
|
|
119
|
+
meta: query.meta
|
|
120
|
+
} : {}),
|
|
121
|
+
state: normalizeState({
|
|
122
|
+
...query.state,
|
|
123
|
+
error: toStoredError(query.state.error),
|
|
124
|
+
fetchFailureReason: toStoredError(query.state.fetchFailureReason)
|
|
125
|
+
})
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
queries,
|
|
130
|
+
warnings
|
|
131
|
+
};
|
|
132
|
+
}
|
|
58
133
|
function createQuerySnapshotProvider(queryClient) {
|
|
59
134
|
return {
|
|
60
135
|
id: "query",
|
|
@@ -66,21 +141,15 @@ function createQuerySnapshotProvider(queryClient) {
|
|
|
66
141
|
async capture() {
|
|
67
142
|
const {
|
|
68
143
|
queries,
|
|
69
|
-
|
|
70
|
-
} = (
|
|
71
|
-
const
|
|
72
|
-
if (
|
|
73
|
-
warnings.push(`${
|
|
144
|
+
warnings
|
|
145
|
+
} = captureQueries(queryClient);
|
|
146
|
+
const mutationCount = queryClient.getMutationCache().getAll().length;
|
|
147
|
+
if (mutationCount > 0) {
|
|
148
|
+
warnings.push(`${mutationCount} mutation(s) not captured (mutation functions cannot be restored)`);
|
|
74
149
|
}
|
|
75
150
|
return {
|
|
76
151
|
data: {
|
|
77
|
-
queries
|
|
78
|
-
observers: _observers,
|
|
79
|
-
...query
|
|
80
|
-
}) => ({
|
|
81
|
-
...query,
|
|
82
|
-
state: normalizeState(query.state)
|
|
83
|
-
}))
|
|
152
|
+
queries
|
|
84
153
|
},
|
|
85
154
|
warnings
|
|
86
155
|
};
|
|
@@ -112,6 +181,17 @@ function createQuerySnapshotProvider(queryClient) {
|
|
|
112
181
|
excludedHits += 1;
|
|
113
182
|
continue;
|
|
114
183
|
}
|
|
184
|
+
// Snapshots taken before the raw-capture fix hold a wire placeholder
|
|
185
|
+
// instead of the data. Writing that into the cache hands the app an
|
|
186
|
+
// object with none of its fields — leave the live query alone and say
|
|
187
|
+
// why, rather than "restoring" a value that crashes the screen.
|
|
188
|
+
if ((0, _dehydrate.isWireDataMarker)(snap.state.data)) {
|
|
189
|
+
result.skipped.push({
|
|
190
|
+
id: snap.queryHash,
|
|
191
|
+
reason: "captured as an on-device placeholder by an older Buoy — re-capture this restore point"
|
|
192
|
+
});
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
115
195
|
try {
|
|
116
196
|
const state = normalizeState(snap.state);
|
|
117
197
|
const existing = cache.get(snap.queryHash);
|
|
@@ -171,16 +251,24 @@ function createQuerySnapshotProvider(queryClient) {
|
|
|
171
251
|
async previewItems(target, base) {
|
|
172
252
|
const targetQueries = target?.queries ?? [];
|
|
173
253
|
const liveMode = base === undefined;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}) => q) : base?.queries ?? [];
|
|
254
|
+
// Live side goes through the same raw capture as a snapshot would, so a
|
|
255
|
+
// big query diffs as its real value instead of a wire placeholder.
|
|
256
|
+
const baseQueries = liveMode ? captureQueries(queryClient).queries : base?.queries ?? [];
|
|
178
257
|
const baseByHash = new Map(baseQueries.map(q => [q.queryHash, q]));
|
|
179
258
|
const targetByHash = new Map(targetQueries.map(q => [q.queryHash, q]));
|
|
180
259
|
const items = [];
|
|
181
260
|
const notes = [];
|
|
182
261
|
for (const q of targetQueries) {
|
|
183
262
|
const label = queryLabel(q.queryKey, q.queryHash);
|
|
263
|
+
if ((0, _dehydrate.isWireDataMarker)(q.state.data)) {
|
|
264
|
+
items.push({
|
|
265
|
+
key: q.queryHash,
|
|
266
|
+
label,
|
|
267
|
+
verdict: "wont-apply",
|
|
268
|
+
reason: "data stayed on the device when this was captured (older Buoy) — re-capture this restore point"
|
|
269
|
+
});
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
184
272
|
const baseQ = baseByHash.get(q.queryHash);
|
|
185
273
|
if (!baseQ) {
|
|
186
274
|
items.push({
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
* the mutation cache is cleared instead.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { registerStateSnapshotProvider } from "@buoy-gg/shared-ui";
|
|
20
|
+
import { registerStateSnapshotProvider, superJsonSerialize } from "@buoy-gg/shared-ui";
|
|
21
21
|
import { boundedDeepEqual, jsonLikelyLargerThan } from "@buoy-gg/shared-ui/dataViewer";
|
|
22
|
-
import {
|
|
22
|
+
import { isWireDataMarker } from "./dehydrate";
|
|
23
23
|
/** A restored query must never claim an in-flight fetch it doesn't have. */
|
|
24
24
|
function normalizeState(state) {
|
|
25
25
|
return {
|
|
@@ -50,6 +50,81 @@ function queryLabel(queryKey, queryHash) {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
const ITEM_RENDER_BYTE_LIMIT = 256 * 1024;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A query `error` (and `fetchFailureReason`) usually holds the live
|
|
56
|
+
* Axios/fetch error: `request` points at the XHR, which is cyclic and would
|
|
57
|
+
* fail the whole snapshot's serialization. Only name + message survive —
|
|
58
|
+
* that's all a restored error state needs.
|
|
59
|
+
*/
|
|
60
|
+
function toStoredError(value) {
|
|
61
|
+
if (value == null) return value ?? null;
|
|
62
|
+
if (typeof value === "object") {
|
|
63
|
+
const err = value;
|
|
64
|
+
const name = typeof err.name === "string" ? err.name : undefined;
|
|
65
|
+
const message = typeof err.message === "string" ? err.message : undefined;
|
|
66
|
+
if (name !== undefined || message !== undefined) {
|
|
67
|
+
return {
|
|
68
|
+
...(name !== undefined ? {
|
|
69
|
+
name
|
|
70
|
+
} : {}),
|
|
71
|
+
...(message !== undefined ? {
|
|
72
|
+
message
|
|
73
|
+
} : {})
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Would the Time Machine vault be able to store this value? */
|
|
81
|
+
function isStorable(value) {
|
|
82
|
+
if (value === undefined) return true;
|
|
83
|
+
try {
|
|
84
|
+
superJsonSerialize(value);
|
|
85
|
+
return true;
|
|
86
|
+
} catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The queries as a SNAPSHOT sees them — raw.
|
|
93
|
+
*
|
|
94
|
+
* Deliberately NOT `dehydrateQueryClient()`: that is the WIRE form, which
|
|
95
|
+
* swaps any payload over 16KB for a `DATA_ON_DEVICE` marker so the dashboard
|
|
96
|
+
* stays inside its emit budget. Snapshots live on-device in persistentStorage
|
|
97
|
+
* with no such budget, and restoring a marker would write the placeholder
|
|
98
|
+
* object into the live cache — the app then renders `{__buoyDataOnDevice}` as
|
|
99
|
+
* if it were its data and crashes on the first field it reads.
|
|
100
|
+
*/
|
|
101
|
+
function captureQueries(client) {
|
|
102
|
+
const warnings = [];
|
|
103
|
+
const queries = [];
|
|
104
|
+
for (const query of client.getQueryCache().getAll()) {
|
|
105
|
+
const label = queryLabel(query.queryKey, query.queryHash);
|
|
106
|
+
if (!isStorable(query.state.data)) {
|
|
107
|
+
warnings.push(`query ${label}: data can't be serialized (circular reference?) — not captured`);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
queries.push({
|
|
111
|
+
queryKey: query.queryKey,
|
|
112
|
+
queryHash: query.queryHash,
|
|
113
|
+
...(query.meta && isStorable(query.meta) ? {
|
|
114
|
+
meta: query.meta
|
|
115
|
+
} : {}),
|
|
116
|
+
state: normalizeState({
|
|
117
|
+
...query.state,
|
|
118
|
+
error: toStoredError(query.state.error),
|
|
119
|
+
fetchFailureReason: toStoredError(query.state.fetchFailureReason)
|
|
120
|
+
})
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
queries,
|
|
125
|
+
warnings
|
|
126
|
+
};
|
|
127
|
+
}
|
|
53
128
|
export function createQuerySnapshotProvider(queryClient) {
|
|
54
129
|
return {
|
|
55
130
|
id: "query",
|
|
@@ -61,21 +136,15 @@ export function createQuerySnapshotProvider(queryClient) {
|
|
|
61
136
|
async capture() {
|
|
62
137
|
const {
|
|
63
138
|
queries,
|
|
64
|
-
|
|
65
|
-
} =
|
|
66
|
-
const
|
|
67
|
-
if (
|
|
68
|
-
warnings.push(`${
|
|
139
|
+
warnings
|
|
140
|
+
} = captureQueries(queryClient);
|
|
141
|
+
const mutationCount = queryClient.getMutationCache().getAll().length;
|
|
142
|
+
if (mutationCount > 0) {
|
|
143
|
+
warnings.push(`${mutationCount} mutation(s) not captured (mutation functions cannot be restored)`);
|
|
69
144
|
}
|
|
70
145
|
return {
|
|
71
146
|
data: {
|
|
72
|
-
queries
|
|
73
|
-
observers: _observers,
|
|
74
|
-
...query
|
|
75
|
-
}) => ({
|
|
76
|
-
...query,
|
|
77
|
-
state: normalizeState(query.state)
|
|
78
|
-
}))
|
|
147
|
+
queries
|
|
79
148
|
},
|
|
80
149
|
warnings
|
|
81
150
|
};
|
|
@@ -107,6 +176,17 @@ export function createQuerySnapshotProvider(queryClient) {
|
|
|
107
176
|
excludedHits += 1;
|
|
108
177
|
continue;
|
|
109
178
|
}
|
|
179
|
+
// Snapshots taken before the raw-capture fix hold a wire placeholder
|
|
180
|
+
// instead of the data. Writing that into the cache hands the app an
|
|
181
|
+
// object with none of its fields — leave the live query alone and say
|
|
182
|
+
// why, rather than "restoring" a value that crashes the screen.
|
|
183
|
+
if (isWireDataMarker(snap.state.data)) {
|
|
184
|
+
result.skipped.push({
|
|
185
|
+
id: snap.queryHash,
|
|
186
|
+
reason: "captured as an on-device placeholder by an older Buoy — re-capture this restore point"
|
|
187
|
+
});
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
110
190
|
try {
|
|
111
191
|
const state = normalizeState(snap.state);
|
|
112
192
|
const existing = cache.get(snap.queryHash);
|
|
@@ -166,16 +246,24 @@ export function createQuerySnapshotProvider(queryClient) {
|
|
|
166
246
|
async previewItems(target, base) {
|
|
167
247
|
const targetQueries = target?.queries ?? [];
|
|
168
248
|
const liveMode = base === undefined;
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}) => q) : base?.queries ?? [];
|
|
249
|
+
// Live side goes through the same raw capture as a snapshot would, so a
|
|
250
|
+
// big query diffs as its real value instead of a wire placeholder.
|
|
251
|
+
const baseQueries = liveMode ? captureQueries(queryClient).queries : base?.queries ?? [];
|
|
173
252
|
const baseByHash = new Map(baseQueries.map(q => [q.queryHash, q]));
|
|
174
253
|
const targetByHash = new Map(targetQueries.map(q => [q.queryHash, q]));
|
|
175
254
|
const items = [];
|
|
176
255
|
const notes = [];
|
|
177
256
|
for (const q of targetQueries) {
|
|
178
257
|
const label = queryLabel(q.queryKey, q.queryHash);
|
|
258
|
+
if (isWireDataMarker(q.state.data)) {
|
|
259
|
+
items.push({
|
|
260
|
+
key: q.queryHash,
|
|
261
|
+
label,
|
|
262
|
+
verdict: "wont-apply",
|
|
263
|
+
reason: "data stayed on the device when this was captured (older Buoy) — re-capture this restore point"
|
|
264
|
+
});
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
179
267
|
const baseQ = baseByHash.get(q.queryHash);
|
|
180
268
|
if (!baseQ) {
|
|
181
269
|
items.push({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshotProvider.d.ts","sourceRoot":"","sources":["../../../../src/react-query/sync/snapshotProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,uBAAuB,CAAC;AACrE,OAAO,
|
|
1
|
+
{"version":3,"file":"snapshotProvider.d.ts","sourceRoot":"","sources":["../../../../src/react-query/sync/snapshotProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAGL,KAAK,qBAAqB,EAK3B,MAAM,oBAAoB,CAAC;AA8G5B,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,WAAW,GACvB,qBAAqB,CAwMvB;AAED,4EAA4E;AAC5E,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,WAAW,GACvB,MAAM,IAAI,CAEZ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/react-query",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.23",
|
|
4
4
|
"description": "TanStack Query devtools inside your React Native app — cache inspection, refetch & invalidate, offline toggle. Part of Buoy devtools.",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"**/snapshotProvider.ts"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@buoy-gg/floating-tools-core": "^7.0.
|
|
33
|
-
"@buoy-gg/shared-ui": "^7.0.
|
|
32
|
+
"@buoy-gg/floating-tools-core": "^7.0.23",
|
|
33
|
+
"@buoy-gg/shared-ui": "^7.0.23"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@tanstack/react-query": ">=5.0.0",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"bugs": {
|
|
76
76
|
"url": "https://github.com/LovesWorking/react-native-buoy/issues"
|
|
77
77
|
},
|
|
78
|
-
"homepage": "https://buoy.gg/tools/react-query",
|
|
78
|
+
"homepage": "https://buoy.gg/buoy/latest/docs/tools/react-query",
|
|
79
79
|
"publishConfig": {
|
|
80
80
|
"access": "public",
|
|
81
81
|
"tag": "latest"
|