@buoy-gg/react-query 7.0.17 → 7.0.19
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/lib/commonjs/react-query/sync/dehydrate.js +119 -11
- package/lib/commonjs/react-query/sync/reactQuerySyncAdapter.js +28 -1
- package/lib/commonjs/react-query/sync/snapshotProvider.js +109 -1
- package/lib/module/react-query/sync/dehydrate.js +113 -11
- package/lib/module/react-query/sync/reactQuerySyncAdapter.js +29 -2
- package/lib/module/react-query/sync/snapshotProvider.js +109 -1
- package/lib/typescript/react-query/sync/dehydrate.d.ts +33 -0
- package/lib/typescript/react-query/sync/dehydrate.d.ts.map +1 -1
- package/lib/typescript/react-query/sync/reactQuerySyncAdapter.d.ts +20 -1
- package/lib/typescript/react-query/sync/reactQuerySyncAdapter.d.ts.map +1 -1
- package/lib/typescript/react-query/sync/snapshotProvider.d.ts.map +1 -1
- package/package.json +9 -4
|
@@ -3,13 +3,96 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
exports.UNSERIALIZABLE_DATA = exports.SNAPSHOT_DATA_INLINE_LIMIT = exports.MAX_QUERY_DETAIL_BYTES = exports.DATA_ON_DEVICE = void 0;
|
|
7
|
+
exports.capQueryDetail = capQueryDetail;
|
|
6
8
|
exports.dehydrateQueryClient = dehydrateQueryClient;
|
|
9
|
+
exports.isDataOnDeviceMarker = isDataOnDeviceMarker;
|
|
10
|
+
exports.isUnserializableMarker = isUnserializableMarker;
|
|
11
|
+
exports.isWireDataMarker = isWireDataMarker;
|
|
12
|
+
exports.toWireData = toWireData;
|
|
13
|
+
exports.toWireError = toWireError;
|
|
14
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
7
15
|
/**
|
|
8
16
|
* Dehydration for external sync — ported from buoy-desktop's
|
|
9
17
|
* react-query-external-sync/hydration.ts so the desktop dashboard can
|
|
10
18
|
* hydrate an identical mirror of the device's QueryClient.
|
|
11
19
|
*/
|
|
12
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Sentinel used in WIRE-FORM snapshots in place of oversized query/mutation
|
|
23
|
+
* data. Same hazard as redux/zustand: a single cached payload can exceed the
|
|
24
|
+
* 2MB emit budget (dashboard goes stale) or freeze JSON.stringify. Dashboards
|
|
25
|
+
* fetch the real value via `getQueryData`.
|
|
26
|
+
*/
|
|
27
|
+
const DATA_ON_DEVICE = exports.DATA_ON_DEVICE = Object.freeze({
|
|
28
|
+
__buoyDataOnDevice: true,
|
|
29
|
+
note: "Query data stays on the device — fetched on demand via getQueryData."
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
/** Sentinel when JSON.stringify throws (circular refs, bigint, …). */
|
|
33
|
+
const UNSERIALIZABLE_DATA = exports.UNSERIALIZABLE_DATA = Object.freeze({
|
|
34
|
+
__buoyUnserializable: true,
|
|
35
|
+
note: "Query data is not JSON-serializable (circular or bigint) and stayed on the device."
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/** Keep small payloads inline; strip anything over this (same as network bodies). */
|
|
39
|
+
const SNAPSHOT_DATA_INLINE_LIMIT = exports.SNAPSHOT_DATA_INLINE_LIMIT = 16 * 1024;
|
|
40
|
+
const MAX_QUERY_DETAIL_BYTES = exports.MAX_QUERY_DETAIL_BYTES = 8 * 1024 * 1024;
|
|
41
|
+
function isDataOnDeviceMarker(value) {
|
|
42
|
+
return !!value && typeof value === "object" && value.__buoyDataOnDevice === true;
|
|
43
|
+
}
|
|
44
|
+
function isUnserializableMarker(value) {
|
|
45
|
+
return !!value && typeof value === "object" && value.__buoyUnserializable === true;
|
|
46
|
+
}
|
|
47
|
+
function isWireDataMarker(value) {
|
|
48
|
+
return isDataOnDeviceMarker(value) || isUnserializableMarker(value);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Replace unserializable / oversized values with a wire marker. */
|
|
52
|
+
function toWireData(value) {
|
|
53
|
+
if (value === undefined) return undefined;
|
|
54
|
+
if (!(0, _sharedUi.isOverWireBudget)(value, SNAPSHOT_DATA_INLINE_LIMIT)) return value;
|
|
55
|
+
// Distinguish "too big to send" from "cannot be sent at all" — the dashboard
|
|
56
|
+
// offers a fetch for the first and must not for the second.
|
|
57
|
+
return (0, _sharedUi.isJsonSerializable)(value) ? DATA_ON_DEVICE : UNSERIALIZABLE_DATA;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Query/mutation `error` (and `fetchFailureReason` / `failureReason`) often
|
|
62
|
+
* hold the live Axios/fetch error: `request` points at XHR (cyclic),
|
|
63
|
+
* `response.data` is the same fat body we already stripped from `state.data`.
|
|
64
|
+
* Spreading `query.state` left that copy on the wire after capping data.
|
|
65
|
+
* The dashboard only reads `error.message`.
|
|
66
|
+
*/
|
|
67
|
+
function toWireError(value) {
|
|
68
|
+
if (value == null) return value;
|
|
69
|
+
if (typeof value === "object") {
|
|
70
|
+
const err = value;
|
|
71
|
+
const name = typeof err.name === "string" ? err.name : undefined;
|
|
72
|
+
const message = typeof err.message === "string" ? err.message : undefined;
|
|
73
|
+
if (name !== undefined || message !== undefined) {
|
|
74
|
+
return toWireData({
|
|
75
|
+
...(name !== undefined ? {
|
|
76
|
+
name
|
|
77
|
+
} : {}),
|
|
78
|
+
...(message !== undefined ? {
|
|
79
|
+
message
|
|
80
|
+
} : {})
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return toWireData(value);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Cap an on-demand detail payload (action result, not the per-tick snapshot). */
|
|
88
|
+
function capQueryDetail(value) {
|
|
89
|
+
if (!(0, _sharedUi.isOverWireBudget)(value, MAX_QUERY_DETAIL_BYTES)) return value;
|
|
90
|
+
if (!(0, _sharedUi.isJsonSerializable)(value)) return UNSERIALIZABLE_DATA;
|
|
91
|
+
return {
|
|
92
|
+
__buoyTruncated: true,
|
|
93
|
+
note: `Exceeds the ${MAX_QUERY_DETAIL_BYTES / (1024 * 1024)}MB detail limit — inspect it on-device.`
|
|
94
|
+
};
|
|
95
|
+
}
|
|
13
96
|
function dehydrateQueryClient(client) {
|
|
14
97
|
const mutations = client.getMutationCache().getAll().map(mutation => dehydrateMutation(mutation));
|
|
15
98
|
const queries = client.getQueryCache().getAll().map(query => dehydrateQuery(query));
|
|
@@ -19,39 +102,64 @@ function dehydrateQueryClient(client) {
|
|
|
19
102
|
};
|
|
20
103
|
}
|
|
21
104
|
function dehydrateMutation(mutation) {
|
|
105
|
+
const state = mutation.state;
|
|
22
106
|
return {
|
|
23
107
|
mutationId: mutation.mutationId,
|
|
24
108
|
mutationKey: mutation.options.mutationKey,
|
|
25
|
-
state:
|
|
109
|
+
state: {
|
|
110
|
+
...state,
|
|
111
|
+
data: toWireData(state.data),
|
|
112
|
+
variables: toWireData(state.variables),
|
|
113
|
+
error: toWireError(state.error),
|
|
114
|
+
failureReason: toWireError(state.failureReason)
|
|
115
|
+
},
|
|
26
116
|
...(mutation.options.scope && {
|
|
27
117
|
scope: mutation.options.scope
|
|
28
118
|
}),
|
|
29
119
|
...(mutation.meta && {
|
|
30
|
-
meta: mutation.meta
|
|
120
|
+
meta: toWireData(mutation.meta)
|
|
31
121
|
})
|
|
32
122
|
};
|
|
33
123
|
}
|
|
124
|
+
function toWireObserverOptions(options) {
|
|
125
|
+
// queryFn / select / persister are functions. initialData and
|
|
126
|
+
// placeholderData are often the SAME fat tree as state.data (apps seed
|
|
127
|
+
// the cache with it). Capping state.data still left those copies on the
|
|
128
|
+
// wire and dropped the Query panel.
|
|
129
|
+
const {
|
|
130
|
+
queryFn: _queryFn,
|
|
131
|
+
select: _select,
|
|
132
|
+
persister: _persister,
|
|
133
|
+
initialData: _initialData,
|
|
134
|
+
placeholderData: _placeholderData,
|
|
135
|
+
...light
|
|
136
|
+
} = options;
|
|
137
|
+
return {
|
|
138
|
+
...light,
|
|
139
|
+
queryFn: undefined,
|
|
140
|
+
...(options.meta ? {
|
|
141
|
+
meta: toWireData(options.meta)
|
|
142
|
+
} : {})
|
|
143
|
+
};
|
|
144
|
+
}
|
|
34
145
|
function dehydrateQuery(query) {
|
|
35
146
|
const observerStates = query.observers.map(observer => ({
|
|
36
147
|
queryHash: query.queryHash,
|
|
37
|
-
|
|
38
|
-
// run device fetch functions (they aren't serializable anyway)
|
|
39
|
-
options: {
|
|
40
|
-
...observer.options,
|
|
41
|
-
queryFn: undefined
|
|
42
|
-
}
|
|
148
|
+
options: toWireObserverOptions(observer.options)
|
|
43
149
|
}));
|
|
44
150
|
return {
|
|
45
151
|
state: {
|
|
46
152
|
...query.state,
|
|
47
153
|
...(query.state.data !== undefined && {
|
|
48
|
-
data: query.state.data
|
|
49
|
-
})
|
|
154
|
+
data: toWireData(query.state.data)
|
|
155
|
+
}),
|
|
156
|
+
error: toWireError(query.state.error),
|
|
157
|
+
fetchFailureReason: toWireError(query.state.fetchFailureReason)
|
|
50
158
|
},
|
|
51
159
|
queryKey: query.queryKey,
|
|
52
160
|
queryHash: query.queryHash,
|
|
53
161
|
...(query.meta && {
|
|
54
|
-
meta: query.meta
|
|
162
|
+
meta: toWireData(query.meta)
|
|
55
163
|
}),
|
|
56
164
|
observers: observerStates
|
|
57
165
|
};
|
|
@@ -16,6 +16,9 @@ var _getQueryStatusLabel = require("../utils/getQueryStatusLabel");
|
|
|
16
16
|
* (useSyncQueries.ts) so the dashboard keeps identical behavior, including
|
|
17
17
|
* the trigger/restore loading and error simulations used by the TanStack
|
|
18
18
|
* devtools UI.
|
|
19
|
+
*
|
|
20
|
+
* v2: oversized / unserializable query (and mutation) data is replaced with
|
|
21
|
+
* on-device markers. Dashboards fetch real data via `getQueryData`.
|
|
19
22
|
*/
|
|
20
23
|
|
|
21
24
|
function createReactQuerySyncAdapter(queryClient) {
|
|
@@ -30,7 +33,7 @@ function createReactQuerySyncAdapter(queryClient) {
|
|
|
30
33
|
return query;
|
|
31
34
|
};
|
|
32
35
|
return {
|
|
33
|
-
version:
|
|
36
|
+
version: 2,
|
|
34
37
|
getSnapshot: () => ({
|
|
35
38
|
dehydratedState: (0, _dehydrate.dehydrateQueryClient)(queryClient),
|
|
36
39
|
isOnlineManagerOnline: _reactQuery.onlineManager.isOnline()
|
|
@@ -46,6 +49,30 @@ function createReactQuerySyncAdapter(queryClient) {
|
|
|
46
49
|
};
|
|
47
50
|
},
|
|
48
51
|
actions: {
|
|
52
|
+
/**
|
|
53
|
+
* On-demand detail: one query's real cached `data`. Wire-form snapshots
|
|
54
|
+
* replace oversized / unserializable data with markers; this is the
|
|
55
|
+
* explicit, size-guarded channel for the detail pane.
|
|
56
|
+
*/
|
|
57
|
+
getQueryData: params => {
|
|
58
|
+
const {
|
|
59
|
+
queryHash
|
|
60
|
+
} = params ?? {};
|
|
61
|
+
if (!queryHash) return {
|
|
62
|
+
found: false,
|
|
63
|
+
reason: "missing queryHash"
|
|
64
|
+
};
|
|
65
|
+
const query = queryClient.getQueryCache().get(queryHash);
|
|
66
|
+
if (!query) return {
|
|
67
|
+
found: false,
|
|
68
|
+
reason: "unknown queryHash"
|
|
69
|
+
};
|
|
70
|
+
return {
|
|
71
|
+
found: true,
|
|
72
|
+
queryHash,
|
|
73
|
+
data: (0, _dehydrate.capQueryDetail)(query.state.data)
|
|
74
|
+
};
|
|
75
|
+
},
|
|
49
76
|
/**
|
|
50
77
|
* Compact, token-bounded cache reader for a remote driver (MCP/LLM):
|
|
51
78
|
* projects each live query to light fields (hash, key, status label,
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.createQuerySnapshotProvider = createQuerySnapshotProvider;
|
|
7
7
|
exports.registerQuerySnapshotProvider = registerQuerySnapshotProvider;
|
|
8
8
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
9
|
+
var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
|
|
9
10
|
var _dehydrate = require("./dehydrate");
|
|
10
11
|
/**
|
|
11
12
|
* Time Machine snapshot provider for React Query.
|
|
@@ -32,6 +33,28 @@ function normalizeState(state) {
|
|
|
32
33
|
fetchMeta: null
|
|
33
34
|
};
|
|
34
35
|
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The comparable projection of a query for previews: status/error/data ONLY.
|
|
39
|
+
* Timestamps (dataUpdatedAt etc.) are excluded — including them makes every
|
|
40
|
+
* query read as "changed" the moment anything refetches.
|
|
41
|
+
*/
|
|
42
|
+
function comparableQuery(q) {
|
|
43
|
+
return {
|
|
44
|
+
status: q.state.status,
|
|
45
|
+
error: q.state.error ?? null,
|
|
46
|
+
data: q.state.data
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function queryLabel(queryKey, queryHash) {
|
|
50
|
+
try {
|
|
51
|
+
const s = JSON.stringify(queryKey);
|
|
52
|
+
return s.length > 60 ? `${s.slice(0, 57)}…` : s;
|
|
53
|
+
} catch {
|
|
54
|
+
return queryHash;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const ITEM_RENDER_BYTE_LIMIT = 256 * 1024;
|
|
35
58
|
function createQuerySnapshotProvider(queryClient) {
|
|
36
59
|
return {
|
|
37
60
|
id: "query",
|
|
@@ -62,8 +85,12 @@ function createQuerySnapshotProvider(queryClient) {
|
|
|
62
85
|
warnings
|
|
63
86
|
};
|
|
64
87
|
},
|
|
65
|
-
async restore(data) {
|
|
88
|
+
async restore(data, options) {
|
|
66
89
|
const snapshot = data;
|
|
90
|
+
const excludedSet = new Set(options?.excludeKeys ?? []);
|
|
91
|
+
const includedSet = options?.includeKeys ? new Set(options.includeKeys) : null;
|
|
92
|
+
const touch = key => !excludedSet.has(key) && (!includedSet || includedSet.has(key));
|
|
93
|
+
let excludedHits = 0;
|
|
67
94
|
const result = {
|
|
68
95
|
ok: true,
|
|
69
96
|
applied: 0,
|
|
@@ -81,6 +108,10 @@ function createQuerySnapshotProvider(queryClient) {
|
|
|
81
108
|
const cache = queryClient.getQueryCache();
|
|
82
109
|
const snapHashes = new Set(snapshot.queries.map(q => q.queryHash));
|
|
83
110
|
for (const snap of snapshot.queries) {
|
|
111
|
+
if (!touch(snap.queryHash)) {
|
|
112
|
+
excludedHits += 1;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
84
115
|
try {
|
|
85
116
|
const state = normalizeState(snap.state);
|
|
86
117
|
const existing = cache.get(snap.queryHash);
|
|
@@ -110,6 +141,10 @@ function createQuerySnapshotProvider(queryClient) {
|
|
|
110
141
|
// Cache entries the snapshot doesn't know about get removed; a mounted
|
|
111
142
|
// observer will rebuild + refetch its query on next interaction.
|
|
112
143
|
for (const query of cache.getAll().slice()) {
|
|
144
|
+
if (!touch(query.queryHash)) {
|
|
145
|
+
excludedHits += 1;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
113
148
|
if (!snapHashes.has(query.queryHash)) {
|
|
114
149
|
try {
|
|
115
150
|
cache.remove(query);
|
|
@@ -127,7 +162,80 @@ function createQuerySnapshotProvider(queryClient) {
|
|
|
127
162
|
queryClient.getMutationCache().clear();
|
|
128
163
|
result.warnings.push(`mutation cache cleared (${mutationCount} mutation(s))`);
|
|
129
164
|
}
|
|
165
|
+
if (excludedHits > 0) {
|
|
166
|
+
result.warnings.push(`${excludedHits} quer(y/ies) excluded by you`);
|
|
167
|
+
}
|
|
130
168
|
return result;
|
|
169
|
+
},
|
|
170
|
+
/** Per-query restore preview. `base` omitted = compare against live cache. */
|
|
171
|
+
async previewItems(target, base) {
|
|
172
|
+
const targetQueries = target?.queries ?? [];
|
|
173
|
+
const liveMode = base === undefined;
|
|
174
|
+
const baseQueries = liveMode ? (0, _dehydrate.dehydrateQueryClient)(queryClient).queries.map(({
|
|
175
|
+
observers: _o,
|
|
176
|
+
...q
|
|
177
|
+
}) => q) : base?.queries ?? [];
|
|
178
|
+
const baseByHash = new Map(baseQueries.map(q => [q.queryHash, q]));
|
|
179
|
+
const targetByHash = new Map(targetQueries.map(q => [q.queryHash, q]));
|
|
180
|
+
const items = [];
|
|
181
|
+
const notes = [];
|
|
182
|
+
for (const q of targetQueries) {
|
|
183
|
+
const label = queryLabel(q.queryKey, q.queryHash);
|
|
184
|
+
const baseQ = baseByHash.get(q.queryHash);
|
|
185
|
+
if (!baseQ) {
|
|
186
|
+
items.push({
|
|
187
|
+
key: q.queryHash,
|
|
188
|
+
label,
|
|
189
|
+
verdict: "added",
|
|
190
|
+
newValue: comparableQuery(q)
|
|
191
|
+
});
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const oldVal = comparableQuery(baseQ);
|
|
195
|
+
const newVal = comparableQuery(q);
|
|
196
|
+
if ((0, _dataViewer.boundedDeepEqual)(oldVal, newVal)) {
|
|
197
|
+
items.push({
|
|
198
|
+
key: q.queryHash,
|
|
199
|
+
label,
|
|
200
|
+
verdict: "unchanged"
|
|
201
|
+
});
|
|
202
|
+
} else if ((0, _dataViewer.jsonLikelyLargerThan)(oldVal, ITEM_RENDER_BYTE_LIMIT) || (0, _dataViewer.jsonLikelyLargerThan)(newVal, ITEM_RENDER_BYTE_LIMIT)) {
|
|
203
|
+
items.push({
|
|
204
|
+
key: q.queryHash,
|
|
205
|
+
label,
|
|
206
|
+
verdict: "too-large",
|
|
207
|
+
reason: "query data too large to render a diff — restore still applies it"
|
|
208
|
+
});
|
|
209
|
+
} else {
|
|
210
|
+
items.push({
|
|
211
|
+
key: q.queryHash,
|
|
212
|
+
label,
|
|
213
|
+
verdict: "changed",
|
|
214
|
+
oldValue: oldVal,
|
|
215
|
+
newValue: newVal
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
for (const q of baseQueries) {
|
|
220
|
+
if (!targetByHash.has(q.queryHash)) {
|
|
221
|
+
items.push({
|
|
222
|
+
key: q.queryHash,
|
|
223
|
+
label: queryLabel(q.queryKey, q.queryHash),
|
|
224
|
+
verdict: "removed",
|
|
225
|
+
oldValue: comparableQuery(q)
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (liveMode) {
|
|
230
|
+
const mutationCount = queryClient.getMutationCache().getAll().length;
|
|
231
|
+
if (mutationCount > 0) {
|
|
232
|
+
notes.push(`${mutationCount} in-memory mutation record(s) will be cleared`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
items,
|
|
237
|
+
notes
|
|
238
|
+
};
|
|
131
239
|
}
|
|
132
240
|
};
|
|
133
241
|
}
|
|
@@ -6,6 +6,83 @@
|
|
|
6
6
|
* hydrate an identical mirror of the device's QueryClient.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { isJsonSerializable, isOverWireBudget } from "@buoy-gg/shared-ui";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sentinel used in WIRE-FORM snapshots in place of oversized query/mutation
|
|
13
|
+
* data. Same hazard as redux/zustand: a single cached payload can exceed the
|
|
14
|
+
* 2MB emit budget (dashboard goes stale) or freeze JSON.stringify. Dashboards
|
|
15
|
+
* fetch the real value via `getQueryData`.
|
|
16
|
+
*/
|
|
17
|
+
export const DATA_ON_DEVICE = Object.freeze({
|
|
18
|
+
__buoyDataOnDevice: true,
|
|
19
|
+
note: "Query data stays on the device — fetched on demand via getQueryData."
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
/** Sentinel when JSON.stringify throws (circular refs, bigint, …). */
|
|
23
|
+
export const UNSERIALIZABLE_DATA = Object.freeze({
|
|
24
|
+
__buoyUnserializable: true,
|
|
25
|
+
note: "Query data is not JSON-serializable (circular or bigint) and stayed on the device."
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/** Keep small payloads inline; strip anything over this (same as network bodies). */
|
|
29
|
+
export const SNAPSHOT_DATA_INLINE_LIMIT = 16 * 1024;
|
|
30
|
+
export const MAX_QUERY_DETAIL_BYTES = 8 * 1024 * 1024;
|
|
31
|
+
export function isDataOnDeviceMarker(value) {
|
|
32
|
+
return !!value && typeof value === "object" && value.__buoyDataOnDevice === true;
|
|
33
|
+
}
|
|
34
|
+
export function isUnserializableMarker(value) {
|
|
35
|
+
return !!value && typeof value === "object" && value.__buoyUnserializable === true;
|
|
36
|
+
}
|
|
37
|
+
export function isWireDataMarker(value) {
|
|
38
|
+
return isDataOnDeviceMarker(value) || isUnserializableMarker(value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Replace unserializable / oversized values with a wire marker. */
|
|
42
|
+
export function toWireData(value) {
|
|
43
|
+
if (value === undefined) return undefined;
|
|
44
|
+
if (!isOverWireBudget(value, SNAPSHOT_DATA_INLINE_LIMIT)) return value;
|
|
45
|
+
// Distinguish "too big to send" from "cannot be sent at all" — the dashboard
|
|
46
|
+
// offers a fetch for the first and must not for the second.
|
|
47
|
+
return isJsonSerializable(value) ? DATA_ON_DEVICE : UNSERIALIZABLE_DATA;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Query/mutation `error` (and `fetchFailureReason` / `failureReason`) often
|
|
52
|
+
* hold the live Axios/fetch error: `request` points at XHR (cyclic),
|
|
53
|
+
* `response.data` is the same fat body we already stripped from `state.data`.
|
|
54
|
+
* Spreading `query.state` left that copy on the wire after capping data.
|
|
55
|
+
* The dashboard only reads `error.message`.
|
|
56
|
+
*/
|
|
57
|
+
export function toWireError(value) {
|
|
58
|
+
if (value == null) return value;
|
|
59
|
+
if (typeof value === "object") {
|
|
60
|
+
const err = value;
|
|
61
|
+
const name = typeof err.name === "string" ? err.name : undefined;
|
|
62
|
+
const message = typeof err.message === "string" ? err.message : undefined;
|
|
63
|
+
if (name !== undefined || message !== undefined) {
|
|
64
|
+
return toWireData({
|
|
65
|
+
...(name !== undefined ? {
|
|
66
|
+
name
|
|
67
|
+
} : {}),
|
|
68
|
+
...(message !== undefined ? {
|
|
69
|
+
message
|
|
70
|
+
} : {})
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return toWireData(value);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Cap an on-demand detail payload (action result, not the per-tick snapshot). */
|
|
78
|
+
export function capQueryDetail(value) {
|
|
79
|
+
if (!isOverWireBudget(value, MAX_QUERY_DETAIL_BYTES)) return value;
|
|
80
|
+
if (!isJsonSerializable(value)) return UNSERIALIZABLE_DATA;
|
|
81
|
+
return {
|
|
82
|
+
__buoyTruncated: true,
|
|
83
|
+
note: `Exceeds the ${MAX_QUERY_DETAIL_BYTES / (1024 * 1024)}MB detail limit — inspect it on-device.`
|
|
84
|
+
};
|
|
85
|
+
}
|
|
9
86
|
export function dehydrateQueryClient(client) {
|
|
10
87
|
const mutations = client.getMutationCache().getAll().map(mutation => dehydrateMutation(mutation));
|
|
11
88
|
const queries = client.getQueryCache().getAll().map(query => dehydrateQuery(query));
|
|
@@ -15,39 +92,64 @@ export function dehydrateQueryClient(client) {
|
|
|
15
92
|
};
|
|
16
93
|
}
|
|
17
94
|
function dehydrateMutation(mutation) {
|
|
95
|
+
const state = mutation.state;
|
|
18
96
|
return {
|
|
19
97
|
mutationId: mutation.mutationId,
|
|
20
98
|
mutationKey: mutation.options.mutationKey,
|
|
21
|
-
state:
|
|
99
|
+
state: {
|
|
100
|
+
...state,
|
|
101
|
+
data: toWireData(state.data),
|
|
102
|
+
variables: toWireData(state.variables),
|
|
103
|
+
error: toWireError(state.error),
|
|
104
|
+
failureReason: toWireError(state.failureReason)
|
|
105
|
+
},
|
|
22
106
|
...(mutation.options.scope && {
|
|
23
107
|
scope: mutation.options.scope
|
|
24
108
|
}),
|
|
25
109
|
...(mutation.meta && {
|
|
26
|
-
meta: mutation.meta
|
|
110
|
+
meta: toWireData(mutation.meta)
|
|
27
111
|
})
|
|
28
112
|
};
|
|
29
113
|
}
|
|
114
|
+
function toWireObserverOptions(options) {
|
|
115
|
+
// queryFn / select / persister are functions. initialData and
|
|
116
|
+
// placeholderData are often the SAME fat tree as state.data (apps seed
|
|
117
|
+
// the cache with it). Capping state.data still left those copies on the
|
|
118
|
+
// wire and dropped the Query panel.
|
|
119
|
+
const {
|
|
120
|
+
queryFn: _queryFn,
|
|
121
|
+
select: _select,
|
|
122
|
+
persister: _persister,
|
|
123
|
+
initialData: _initialData,
|
|
124
|
+
placeholderData: _placeholderData,
|
|
125
|
+
...light
|
|
126
|
+
} = options;
|
|
127
|
+
return {
|
|
128
|
+
...light,
|
|
129
|
+
queryFn: undefined,
|
|
130
|
+
...(options.meta ? {
|
|
131
|
+
meta: toWireData(options.meta)
|
|
132
|
+
} : {})
|
|
133
|
+
};
|
|
134
|
+
}
|
|
30
135
|
function dehydrateQuery(query) {
|
|
31
136
|
const observerStates = query.observers.map(observer => ({
|
|
32
137
|
queryHash: query.queryHash,
|
|
33
|
-
|
|
34
|
-
// run device fetch functions (they aren't serializable anyway)
|
|
35
|
-
options: {
|
|
36
|
-
...observer.options,
|
|
37
|
-
queryFn: undefined
|
|
38
|
-
}
|
|
138
|
+
options: toWireObserverOptions(observer.options)
|
|
39
139
|
}));
|
|
40
140
|
return {
|
|
41
141
|
state: {
|
|
42
142
|
...query.state,
|
|
43
143
|
...(query.state.data !== undefined && {
|
|
44
|
-
data: query.state.data
|
|
45
|
-
})
|
|
144
|
+
data: toWireData(query.state.data)
|
|
145
|
+
}),
|
|
146
|
+
error: toWireError(query.state.error),
|
|
147
|
+
fetchFailureReason: toWireError(query.state.fetchFailureReason)
|
|
46
148
|
},
|
|
47
149
|
queryKey: query.queryKey,
|
|
48
150
|
queryHash: query.queryHash,
|
|
49
151
|
...(query.meta && {
|
|
50
|
-
meta: query.meta
|
|
152
|
+
meta: toWireData(query.meta)
|
|
51
153
|
}),
|
|
52
154
|
observers: observerStates
|
|
53
155
|
};
|
|
@@ -9,9 +9,12 @@
|
|
|
9
9
|
* (useSyncQueries.ts) so the dashboard keeps identical behavior, including
|
|
10
10
|
* the trigger/restore loading and error simulations used by the TanStack
|
|
11
11
|
* devtools UI.
|
|
12
|
+
*
|
|
13
|
+
* v2: oversized / unserializable query (and mutation) data is replaced with
|
|
14
|
+
* on-device markers. Dashboards fetch real data via `getQueryData`.
|
|
12
15
|
*/
|
|
13
16
|
import { onlineManager } from "@tanstack/react-query";
|
|
14
|
-
import { dehydrateQueryClient } from "./dehydrate";
|
|
17
|
+
import { capQueryDetail, dehydrateQueryClient } from "./dehydrate";
|
|
15
18
|
import { getQueryStatusLabel } from "../utils/getQueryStatusLabel";
|
|
16
19
|
export function createReactQuerySyncAdapter(queryClient) {
|
|
17
20
|
const getQuery = params => {
|
|
@@ -25,7 +28,7 @@ export function createReactQuerySyncAdapter(queryClient) {
|
|
|
25
28
|
return query;
|
|
26
29
|
};
|
|
27
30
|
return {
|
|
28
|
-
version:
|
|
31
|
+
version: 2,
|
|
29
32
|
getSnapshot: () => ({
|
|
30
33
|
dehydratedState: dehydrateQueryClient(queryClient),
|
|
31
34
|
isOnlineManagerOnline: onlineManager.isOnline()
|
|
@@ -41,6 +44,30 @@ export function createReactQuerySyncAdapter(queryClient) {
|
|
|
41
44
|
};
|
|
42
45
|
},
|
|
43
46
|
actions: {
|
|
47
|
+
/**
|
|
48
|
+
* On-demand detail: one query's real cached `data`. Wire-form snapshots
|
|
49
|
+
* replace oversized / unserializable data with markers; this is the
|
|
50
|
+
* explicit, size-guarded channel for the detail pane.
|
|
51
|
+
*/
|
|
52
|
+
getQueryData: params => {
|
|
53
|
+
const {
|
|
54
|
+
queryHash
|
|
55
|
+
} = params ?? {};
|
|
56
|
+
if (!queryHash) return {
|
|
57
|
+
found: false,
|
|
58
|
+
reason: "missing queryHash"
|
|
59
|
+
};
|
|
60
|
+
const query = queryClient.getQueryCache().get(queryHash);
|
|
61
|
+
if (!query) return {
|
|
62
|
+
found: false,
|
|
63
|
+
reason: "unknown queryHash"
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
found: true,
|
|
67
|
+
queryHash,
|
|
68
|
+
data: capQueryDetail(query.state.data)
|
|
69
|
+
};
|
|
70
|
+
},
|
|
44
71
|
/**
|
|
45
72
|
* Compact, token-bounded cache reader for a remote driver (MCP/LLM):
|
|
46
73
|
* projects each live query to light fields (hash, key, status label,
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import { registerStateSnapshotProvider } from "@buoy-gg/shared-ui";
|
|
21
|
+
import { boundedDeepEqual, jsonLikelyLargerThan } from "@buoy-gg/shared-ui/dataViewer";
|
|
21
22
|
import { dehydrateQueryClient } from "./dehydrate";
|
|
22
23
|
/** A restored query must never claim an in-flight fetch it doesn't have. */
|
|
23
24
|
function normalizeState(state) {
|
|
@@ -27,6 +28,28 @@ function normalizeState(state) {
|
|
|
27
28
|
fetchMeta: null
|
|
28
29
|
};
|
|
29
30
|
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The comparable projection of a query for previews: status/error/data ONLY.
|
|
34
|
+
* Timestamps (dataUpdatedAt etc.) are excluded — including them makes every
|
|
35
|
+
* query read as "changed" the moment anything refetches.
|
|
36
|
+
*/
|
|
37
|
+
function comparableQuery(q) {
|
|
38
|
+
return {
|
|
39
|
+
status: q.state.status,
|
|
40
|
+
error: q.state.error ?? null,
|
|
41
|
+
data: q.state.data
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function queryLabel(queryKey, queryHash) {
|
|
45
|
+
try {
|
|
46
|
+
const s = JSON.stringify(queryKey);
|
|
47
|
+
return s.length > 60 ? `${s.slice(0, 57)}…` : s;
|
|
48
|
+
} catch {
|
|
49
|
+
return queryHash;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const ITEM_RENDER_BYTE_LIMIT = 256 * 1024;
|
|
30
53
|
export function createQuerySnapshotProvider(queryClient) {
|
|
31
54
|
return {
|
|
32
55
|
id: "query",
|
|
@@ -57,8 +80,12 @@ export function createQuerySnapshotProvider(queryClient) {
|
|
|
57
80
|
warnings
|
|
58
81
|
};
|
|
59
82
|
},
|
|
60
|
-
async restore(data) {
|
|
83
|
+
async restore(data, options) {
|
|
61
84
|
const snapshot = data;
|
|
85
|
+
const excludedSet = new Set(options?.excludeKeys ?? []);
|
|
86
|
+
const includedSet = options?.includeKeys ? new Set(options.includeKeys) : null;
|
|
87
|
+
const touch = key => !excludedSet.has(key) && (!includedSet || includedSet.has(key));
|
|
88
|
+
let excludedHits = 0;
|
|
62
89
|
const result = {
|
|
63
90
|
ok: true,
|
|
64
91
|
applied: 0,
|
|
@@ -76,6 +103,10 @@ export function createQuerySnapshotProvider(queryClient) {
|
|
|
76
103
|
const cache = queryClient.getQueryCache();
|
|
77
104
|
const snapHashes = new Set(snapshot.queries.map(q => q.queryHash));
|
|
78
105
|
for (const snap of snapshot.queries) {
|
|
106
|
+
if (!touch(snap.queryHash)) {
|
|
107
|
+
excludedHits += 1;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
79
110
|
try {
|
|
80
111
|
const state = normalizeState(snap.state);
|
|
81
112
|
const existing = cache.get(snap.queryHash);
|
|
@@ -105,6 +136,10 @@ export function createQuerySnapshotProvider(queryClient) {
|
|
|
105
136
|
// Cache entries the snapshot doesn't know about get removed; a mounted
|
|
106
137
|
// observer will rebuild + refetch its query on next interaction.
|
|
107
138
|
for (const query of cache.getAll().slice()) {
|
|
139
|
+
if (!touch(query.queryHash)) {
|
|
140
|
+
excludedHits += 1;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
108
143
|
if (!snapHashes.has(query.queryHash)) {
|
|
109
144
|
try {
|
|
110
145
|
cache.remove(query);
|
|
@@ -122,7 +157,80 @@ export function createQuerySnapshotProvider(queryClient) {
|
|
|
122
157
|
queryClient.getMutationCache().clear();
|
|
123
158
|
result.warnings.push(`mutation cache cleared (${mutationCount} mutation(s))`);
|
|
124
159
|
}
|
|
160
|
+
if (excludedHits > 0) {
|
|
161
|
+
result.warnings.push(`${excludedHits} quer(y/ies) excluded by you`);
|
|
162
|
+
}
|
|
125
163
|
return result;
|
|
164
|
+
},
|
|
165
|
+
/** Per-query restore preview. `base` omitted = compare against live cache. */
|
|
166
|
+
async previewItems(target, base) {
|
|
167
|
+
const targetQueries = target?.queries ?? [];
|
|
168
|
+
const liveMode = base === undefined;
|
|
169
|
+
const baseQueries = liveMode ? dehydrateQueryClient(queryClient).queries.map(({
|
|
170
|
+
observers: _o,
|
|
171
|
+
...q
|
|
172
|
+
}) => q) : base?.queries ?? [];
|
|
173
|
+
const baseByHash = new Map(baseQueries.map(q => [q.queryHash, q]));
|
|
174
|
+
const targetByHash = new Map(targetQueries.map(q => [q.queryHash, q]));
|
|
175
|
+
const items = [];
|
|
176
|
+
const notes = [];
|
|
177
|
+
for (const q of targetQueries) {
|
|
178
|
+
const label = queryLabel(q.queryKey, q.queryHash);
|
|
179
|
+
const baseQ = baseByHash.get(q.queryHash);
|
|
180
|
+
if (!baseQ) {
|
|
181
|
+
items.push({
|
|
182
|
+
key: q.queryHash,
|
|
183
|
+
label,
|
|
184
|
+
verdict: "added",
|
|
185
|
+
newValue: comparableQuery(q)
|
|
186
|
+
});
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const oldVal = comparableQuery(baseQ);
|
|
190
|
+
const newVal = comparableQuery(q);
|
|
191
|
+
if (boundedDeepEqual(oldVal, newVal)) {
|
|
192
|
+
items.push({
|
|
193
|
+
key: q.queryHash,
|
|
194
|
+
label,
|
|
195
|
+
verdict: "unchanged"
|
|
196
|
+
});
|
|
197
|
+
} else if (jsonLikelyLargerThan(oldVal, ITEM_RENDER_BYTE_LIMIT) || jsonLikelyLargerThan(newVal, ITEM_RENDER_BYTE_LIMIT)) {
|
|
198
|
+
items.push({
|
|
199
|
+
key: q.queryHash,
|
|
200
|
+
label,
|
|
201
|
+
verdict: "too-large",
|
|
202
|
+
reason: "query data too large to render a diff — restore still applies it"
|
|
203
|
+
});
|
|
204
|
+
} else {
|
|
205
|
+
items.push({
|
|
206
|
+
key: q.queryHash,
|
|
207
|
+
label,
|
|
208
|
+
verdict: "changed",
|
|
209
|
+
oldValue: oldVal,
|
|
210
|
+
newValue: newVal
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
for (const q of baseQueries) {
|
|
215
|
+
if (!targetByHash.has(q.queryHash)) {
|
|
216
|
+
items.push({
|
|
217
|
+
key: q.queryHash,
|
|
218
|
+
label: queryLabel(q.queryKey, q.queryHash),
|
|
219
|
+
verdict: "removed",
|
|
220
|
+
oldValue: comparableQuery(q)
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (liveMode) {
|
|
225
|
+
const mutationCount = queryClient.getMutationCache().getAll().length;
|
|
226
|
+
if (mutationCount > 0) {
|
|
227
|
+
notes.push(`${mutationCount} in-memory mutation record(s) will be cleared`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
items,
|
|
232
|
+
notes
|
|
233
|
+
};
|
|
126
234
|
}
|
|
127
235
|
};
|
|
128
236
|
}
|
|
@@ -4,6 +4,39 @@
|
|
|
4
4
|
* hydrate an identical mirror of the device's QueryClient.
|
|
5
5
|
*/
|
|
6
6
|
import type { DefaultError, MutationKey, MutationMeta, MutationScope, MutationState, QueryClient, QueryKey, QueryMeta, QueryObserverOptions, QueryState } from "@tanstack/react-query";
|
|
7
|
+
/**
|
|
8
|
+
* Sentinel used in WIRE-FORM snapshots in place of oversized query/mutation
|
|
9
|
+
* data. Same hazard as redux/zustand: a single cached payload can exceed the
|
|
10
|
+
* 2MB emit budget (dashboard goes stale) or freeze JSON.stringify. Dashboards
|
|
11
|
+
* fetch the real value via `getQueryData`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const DATA_ON_DEVICE: Readonly<{
|
|
14
|
+
__buoyDataOnDevice: true;
|
|
15
|
+
note: "Query data stays on the device — fetched on demand via getQueryData.";
|
|
16
|
+
}>;
|
|
17
|
+
/** Sentinel when JSON.stringify throws (circular refs, bigint, …). */
|
|
18
|
+
export declare const UNSERIALIZABLE_DATA: Readonly<{
|
|
19
|
+
__buoyUnserializable: true;
|
|
20
|
+
note: "Query data is not JSON-serializable (circular or bigint) and stayed on the device.";
|
|
21
|
+
}>;
|
|
22
|
+
/** Keep small payloads inline; strip anything over this (same as network bodies). */
|
|
23
|
+
export declare const SNAPSHOT_DATA_INLINE_LIMIT: number;
|
|
24
|
+
export declare const MAX_QUERY_DETAIL_BYTES: number;
|
|
25
|
+
export declare function isDataOnDeviceMarker(value: unknown): boolean;
|
|
26
|
+
export declare function isUnserializableMarker(value: unknown): boolean;
|
|
27
|
+
export declare function isWireDataMarker(value: unknown): boolean;
|
|
28
|
+
/** Replace unserializable / oversized values with a wire marker. */
|
|
29
|
+
export declare function toWireData(value: unknown): unknown;
|
|
30
|
+
/**
|
|
31
|
+
* Query/mutation `error` (and `fetchFailureReason` / `failureReason`) often
|
|
32
|
+
* hold the live Axios/fetch error: `request` points at XHR (cyclic),
|
|
33
|
+
* `response.data` is the same fat body we already stripped from `state.data`.
|
|
34
|
+
* Spreading `query.state` left that copy on the wire after capping data.
|
|
35
|
+
* The dashboard only reads `error.message`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function toWireError(value: unknown): unknown;
|
|
38
|
+
/** Cap an on-demand detail payload (action result, not the per-tick snapshot). */
|
|
39
|
+
export declare function capQueryDetail(value: unknown): unknown;
|
|
7
40
|
export interface DehydratedState {
|
|
8
41
|
mutations: DehydratedMutation[];
|
|
9
42
|
queries: DehydratedQuery[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dehydrate.d.ts","sourceRoot":"","sources":["../../../../src/react-query/sync/dehydrate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EACV,YAAY,EAEZ,WAAW,EACX,YAAY,EACZ,aAAa,EACb,aAAa,EAEb,WAAW,EAEX,QAAQ,EACR,SAAS,EACT,oBAAoB,EACpB,UAAU,EACX,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"dehydrate.d.ts","sourceRoot":"","sources":["../../../../src/react-query/sync/dehydrate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EACV,YAAY,EAEZ,WAAW,EACX,YAAY,EACZ,aAAa,EACb,aAAa,EAEb,WAAW,EAEX,QAAQ,EACR,SAAS,EACT,oBAAoB,EACpB,UAAU,EACX,MAAM,uBAAuB,CAAC;AAG/B;;;;;GAKG;AACH,eAAO,MAAM,cAAc;;;EAGzB,CAAC;AAEH,sEAAsE;AACtE,eAAO,MAAM,mBAAmB;;;EAG9B,CAAC;AAEH,qFAAqF;AACrF,eAAO,MAAM,0BAA0B,QAAY,CAAC;AAEpD,eAAO,MAAM,sBAAsB,QAAkB,CAAC;AAEtD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAM5D;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAM9D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAExD;AAED,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMlD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAcnD;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOtD;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,aAAa,CAAC;IACrB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,SAAS,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa,CAC5B,YAAY,GAAG,OAAO,EACtB,MAAM,GAAG,YAAY,EACrB,KAAK,GAAG,YAAY,EACpB,UAAU,GAAG,YAAY,EACzB,SAAS,SAAS,QAAQ,GAAG,QAAQ;IAErC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,oBAAoB,CAC3B,YAAY,EACZ,MAAM,EACN,KAAK,EACL,UAAU,EACV,SAAS,CACV,CAAC;CACH;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,eAAe,CAYzE"}
|
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
* (useSyncQueries.ts) so the dashboard keeps identical behavior, including
|
|
8
8
|
* the trigger/restore loading and error simulations used by the TanStack
|
|
9
9
|
* devtools UI.
|
|
10
|
+
*
|
|
11
|
+
* v2: oversized / unserializable query (and mutation) data is replaced with
|
|
12
|
+
* on-device markers. Dashboards fetch real data via `getQueryData`.
|
|
10
13
|
*/
|
|
11
14
|
import { type QueryClient } from "@tanstack/react-query";
|
|
12
15
|
export declare function createReactQuerySyncAdapter(queryClient: QueryClient): {
|
|
@@ -17,6 +20,22 @@ export declare function createReactQuerySyncAdapter(queryClient: QueryClient): {
|
|
|
17
20
|
};
|
|
18
21
|
subscribe: (onChange: () => void) => () => void;
|
|
19
22
|
actions: {
|
|
23
|
+
/**
|
|
24
|
+
* On-demand detail: one query's real cached `data`. Wire-form snapshots
|
|
25
|
+
* replace oversized / unserializable data with markers; this is the
|
|
26
|
+
* explicit, size-guarded channel for the detail pane.
|
|
27
|
+
*/
|
|
28
|
+
getQueryData: (params: unknown) => {
|
|
29
|
+
found: false;
|
|
30
|
+
reason: string;
|
|
31
|
+
queryHash?: undefined;
|
|
32
|
+
data?: undefined;
|
|
33
|
+
} | {
|
|
34
|
+
found: true;
|
|
35
|
+
queryHash: string;
|
|
36
|
+
data: unknown;
|
|
37
|
+
reason?: undefined;
|
|
38
|
+
};
|
|
20
39
|
/**
|
|
21
40
|
* Compact, token-bounded cache reader for a remote driver (MCP/LLM):
|
|
22
41
|
* projects each live query to light fields (hash, key, status label,
|
|
@@ -24,7 +43,7 @@ export declare function createReactQuerySyncAdapter(queryClient: QueryClient): {
|
|
|
24
43
|
* the device unless `includeData` is set. Unlike getSnapshot (full
|
|
25
44
|
* dehydrated cache), this is safe to read repeatedly.
|
|
26
45
|
*/
|
|
27
|
-
listQueries: (params
|
|
46
|
+
listQueries: (params?: unknown) => {
|
|
28
47
|
queries: {
|
|
29
48
|
data?: unknown;
|
|
30
49
|
queryHash: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactQuerySyncAdapter.d.ts","sourceRoot":"","sources":["../../../../src/react-query/sync/reactQuerySyncAdapter.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"reactQuerySyncAdapter.d.ts","sourceRoot":"","sources":["../../../../src/react-query/sync/reactQuerySyncAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAiB,KAAK,WAAW,EAAiB,MAAM,uBAAuB,CAAC;AA0BvF,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,WAAW;;;;;;0BAgB1C,MAAM,IAAI;;QAa9B;;;;WAIG;+BACoB,OAAO;;;;;;;;;;;QAY9B;;;;;;WAMG;+BACoB,OAAO;;;;;;;;;;;;;;;;0BAkCZ,OAAO;6BAKJ,OAAO;wBAEZ,OAAO;yBACN,OAAO;+BAGD,OAAO;+BAIP,OAAO;+BAaP,OAAO;iCAEL,OAAO;iCAwBP,OAAO;;;4BA4BZ,OAAO;;EAMhC"}
|
|
@@ -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,EAEL,KAAK,qBAAqB,
|
|
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,EAEL,KAAK,qBAAqB,EAK3B,MAAM,oBAAoB,CAAC;AAuC5B,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,WAAW,GACvB,qBAAqB,CAuLvB;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.19",
|
|
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/
|
|
33
|
-
"@buoy-gg/
|
|
32
|
+
"@buoy-gg/floating-tools-core": "^7.0.19",
|
|
33
|
+
"@buoy-gg/shared-ui": "^7.0.19"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@tanstack/react-query": ">=5.0.0",
|
|
@@ -59,7 +59,12 @@
|
|
|
59
59
|
"sourceMaps": false
|
|
60
60
|
}
|
|
61
61
|
],
|
|
62
|
-
|
|
62
|
+
[
|
|
63
|
+
"typescript",
|
|
64
|
+
{
|
|
65
|
+
"project": "tsconfig.build.json"
|
|
66
|
+
}
|
|
67
|
+
]
|
|
63
68
|
]
|
|
64
69
|
},
|
|
65
70
|
"repository": {
|