@buoy-gg/react-query 7.0.41 → 7.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/README.md +11 -73
  2. package/lib/commonjs/checkPeer.js +1 -8
  3. package/lib/commonjs/checkPeer.web.js +1 -3
  4. package/lib/commonjs/index.js +1 -657
  5. package/lib/commonjs/preset.js +1 -243
  6. package/lib/commonjs/react-query/components/DataEditorMode.js +1 -317
  7. package/lib/commonjs/react-query/components/FilterStatusBadge.js +1 -55
  8. package/lib/commonjs/react-query/components/MutationBrowserMode.js +1 -52
  9. package/lib/commonjs/react-query/components/MutationEditorMode.js +1 -276
  10. package/lib/commonjs/react-query/components/QueryBrowserMode.js +1 -99
  11. package/lib/commonjs/react-query/components/QueryDebugInfo.js +1 -107
  12. package/lib/commonjs/react-query/components/QueryFilterViewV3.js +1 -224
  13. package/lib/commonjs/react-query/components/QuerySelector.js +1 -209
  14. package/lib/commonjs/react-query/components/ReactQueryDevToolsModal.js +1 -91
  15. package/lib/commonjs/react-query/components/ReactQuerySection.js +1 -47
  16. package/lib/commonjs/react-query/components/ReactQueryTracker.js +1 -38
  17. package/lib/commonjs/react-query/components/WifiToggle.js +1 -51
  18. package/lib/commonjs/react-query/components/modals/DataEditorModal.js +1 -103
  19. package/lib/commonjs/react-query/components/modals/MutationBrowserFooter.js +1 -61
  20. package/lib/commonjs/react-query/components/modals/MutationBrowserModal.js +1 -164
  21. package/lib/commonjs/react-query/components/modals/MutationEditorModal.js +1 -106
  22. package/lib/commonjs/react-query/components/modals/QueryBrowserFooter.js +1 -56
  23. package/lib/commonjs/react-query/components/modals/QueryBrowserModal.js +1 -254
  24. package/lib/commonjs/react-query/components/modals/ReactQueryModal.js +1 -83
  25. package/lib/commonjs/react-query/components/modals/ReactQueryModalHeader.js +1 -194
  26. package/lib/commonjs/react-query/components/modals/SwipeIndicator.js +1 -204
  27. package/lib/commonjs/react-query/components/query-browser/ActionButton.js +1 -100
  28. package/lib/commonjs/react-query/components/query-browser/ClearCacheButton.js +1 -53
  29. package/lib/commonjs/react-query/components/query-browser/Explorer.js +1 -75
  30. package/lib/commonjs/react-query/components/query-browser/MutationButton.js +1 -190
  31. package/lib/commonjs/react-query/components/query-browser/MutationDetails.js +1 -124
  32. package/lib/commonjs/react-query/components/query-browser/MutationDetailsChips.js +1 -68
  33. package/lib/commonjs/react-query/components/query-browser/MutationInformation.js +1 -118
  34. package/lib/commonjs/react-query/components/query-browser/MutationStatusCount.js +1 -84
  35. package/lib/commonjs/react-query/components/query-browser/MutationsList.js +1 -220
  36. package/lib/commonjs/react-query/components/query-browser/NetworkToggleButton.js +1 -54
  37. package/lib/commonjs/react-query/components/query-browser/QueryActions.js +1 -124
  38. package/lib/commonjs/react-query/components/query-browser/QueryBrowser.js +1 -181
  39. package/lib/commonjs/react-query/components/query-browser/QueryDetails.js +1 -141
  40. package/lib/commonjs/react-query/components/query-browser/QueryDetailsChip.js +1 -78
  41. package/lib/commonjs/react-query/components/query-browser/QueryInformation.js +1 -95
  42. package/lib/commonjs/react-query/components/query-browser/QueryRow.js +1 -96
  43. package/lib/commonjs/react-query/components/query-browser/QueryStatus.js +1 -167
  44. package/lib/commonjs/react-query/components/query-browser/QueryStatusCount.js +1 -100
  45. package/lib/commonjs/react-query/components/query-browser/StorageStatusCount.js +1 -61
  46. package/lib/commonjs/react-query/components/query-browser/index.js +1 -170
  47. package/lib/commonjs/react-query/components/query-browser/svgs.js +1 -72
  48. package/lib/commonjs/react-query/hooks/useActionButtons.js +1 -51
  49. package/lib/commonjs/react-query/hooks/useAllMutations.js +1 -85
  50. package/lib/commonjs/react-query/hooks/useAllQueries.js +1 -117
  51. package/lib/commonjs/react-query/hooks/useModalManager.js +1 -178
  52. package/lib/commonjs/react-query/hooks/useModalPersistence.js +1 -71
  53. package/lib/commonjs/react-query/hooks/useMutationActionButtons.js +1 -21
  54. package/lib/commonjs/react-query/hooks/useQueryStatusCounts.js +1 -114
  55. package/lib/commonjs/react-query/hooks/useReactQueryState.js +1 -24
  56. package/lib/commonjs/react-query/hooks/useSelectedMutation.js +1 -30
  57. package/lib/commonjs/react-query/hooks/useSelectedQuery.js +1 -96
  58. package/lib/commonjs/react-query/hooks/useStorageQueryCounts.js +1 -28
  59. package/lib/commonjs/react-query/hooks/useWifiState.js +1 -67
  60. package/lib/commonjs/react-query/stores/reactQueryEventStore.js +1 -302
  61. package/lib/commonjs/react-query/sync/dehydrate.js +1 -166
  62. package/lib/commonjs/react-query/sync/reactQuerySyncAdapter.js +1 -593
  63. package/lib/commonjs/react-query/sync/snapshotProvider.js +1 -289
  64. package/lib/commonjs/react-query/sync/useReactQuerySyncAdapter.js +1 -34
  65. package/lib/commonjs/react-query/types/types.js +1 -14
  66. package/lib/commonjs/react-query/utils/actions/deleteItem.js +1 -23
  67. package/lib/commonjs/react-query/utils/actions/emitDevToolsEvent.js +1 -40
  68. package/lib/commonjs/react-query/utils/actions/invalidate.js +1 -15
  69. package/lib/commonjs/react-query/utils/actions/refetch.js +1 -17
  70. package/lib/commonjs/react-query/utils/actions/remove.js +1 -15
  71. package/lib/commonjs/react-query/utils/actions/reset.js +1 -17
  72. package/lib/commonjs/react-query/utils/actions/triggerError.js +1 -33
  73. package/lib/commonjs/react-query/utils/actions/triggerLoading.js +1 -54
  74. package/lib/commonjs/react-query/utils/deleteNestedDataByPath.js +1 -56
  75. package/lib/commonjs/react-query/utils/getQueryStatusColor.js +1 -16
  76. package/lib/commonjs/react-query/utils/getQueryStatusLabel.js +1 -23
  77. package/lib/commonjs/react-query/utils/getStorageQueryCounts.js +1 -35
  78. package/lib/commonjs/react-query/utils/modalStorageOperations.js +1 -127
  79. package/lib/commonjs/react-query/utils/storageQueryUtils.js +1 -149
  80. package/lib/commonjs/react-query/utils/testIDs.js +1 -61
  81. package/lib/commonjs/react-query/utils/updateNestedDataByPath.js +1 -61
  82. package/lib/module/checkPeer.js +1 -8
  83. package/lib/module/checkPeer.web.js +1 -3
  84. package/lib/module/index.js +1 -130
  85. package/lib/module/preset.js +1 -239
  86. package/lib/module/react-query/components/DataEditorMode.js +1 -311
  87. package/lib/module/react-query/components/FilterStatusBadge.js +1 -51
  88. package/lib/module/react-query/components/MutationBrowserMode.js +1 -47
  89. package/lib/module/react-query/components/MutationEditorMode.js +1 -270
  90. package/lib/module/react-query/components/QueryBrowserMode.js +1 -94
  91. package/lib/module/react-query/components/QueryDebugInfo.js +1 -104
  92. package/lib/module/react-query/components/QueryFilterViewV3.js +1 -221
  93. package/lib/module/react-query/components/QuerySelector.js +1 -205
  94. package/lib/module/react-query/components/ReactQueryDevToolsModal.js +1 -87
  95. package/lib/module/react-query/components/ReactQuerySection.js +1 -43
  96. package/lib/module/react-query/components/ReactQueryTracker.js +1 -35
  97. package/lib/module/react-query/components/WifiToggle.js +1 -48
  98. package/lib/module/react-query/components/modals/DataEditorModal.js +1 -99
  99. package/lib/module/react-query/components/modals/MutationBrowserFooter.js +1 -56
  100. package/lib/module/react-query/components/modals/MutationBrowserModal.js +1 -161
  101. package/lib/module/react-query/components/modals/MutationEditorModal.js +1 -102
  102. package/lib/module/react-query/components/modals/QueryBrowserFooter.js +1 -51
  103. package/lib/module/react-query/components/modals/QueryBrowserModal.js +1 -250
  104. package/lib/module/react-query/components/modals/ReactQueryModal.js +1 -79
  105. package/lib/module/react-query/components/modals/ReactQueryModalHeader.js +1 -190
  106. package/lib/module/react-query/components/modals/SwipeIndicator.js +1 -201
  107. package/lib/module/react-query/components/query-browser/ActionButton.js +1 -96
  108. package/lib/module/react-query/components/query-browser/ClearCacheButton.js +1 -49
  109. package/lib/module/react-query/components/query-browser/Explorer.js +1 -70
  110. package/lib/module/react-query/components/query-browser/MutationButton.js +1 -186
  111. package/lib/module/react-query/components/query-browser/MutationDetails.js +1 -119
  112. package/lib/module/react-query/components/query-browser/MutationDetailsChips.js +1 -64
  113. package/lib/module/react-query/components/query-browser/MutationInformation.js +1 -113
  114. package/lib/module/react-query/components/query-browser/MutationStatusCount.js +1 -79
  115. package/lib/module/react-query/components/query-browser/MutationsList.js +1 -215
  116. package/lib/module/react-query/components/query-browser/NetworkToggleButton.js +1 -50
  117. package/lib/module/react-query/components/query-browser/QueryActions.js +1 -119
  118. package/lib/module/react-query/components/query-browser/QueryBrowser.js +1 -176
  119. package/lib/module/react-query/components/query-browser/QueryDetails.js +1 -136
  120. package/lib/module/react-query/components/query-browser/QueryDetailsChip.js +1 -74
  121. package/lib/module/react-query/components/query-browser/QueryInformation.js +1 -90
  122. package/lib/module/react-query/components/query-browser/QueryRow.js +1 -92
  123. package/lib/module/react-query/components/query-browser/QueryStatus.js +1 -163
  124. package/lib/module/react-query/components/query-browser/QueryStatusCount.js +1 -95
  125. package/lib/module/react-query/components/query-browser/StorageStatusCount.js +1 -56
  126. package/lib/module/react-query/components/query-browser/index.js +1 -22
  127. package/lib/module/react-query/components/query-browser/svgs.js +1 -64
  128. package/lib/module/react-query/hooks/useActionButtons.js +1 -46
  129. package/lib/module/react-query/hooks/useAllMutations.js +1 -82
  130. package/lib/module/react-query/hooks/useAllQueries.js +1 -114
  131. package/lib/module/react-query/hooks/useModalManager.js +1 -175
  132. package/lib/module/react-query/hooks/useModalPersistence.js +1 -67
  133. package/lib/module/react-query/hooks/useMutationActionButtons.js +1 -17
  134. package/lib/module/react-query/hooks/useQueryStatusCounts.js +1 -112
  135. package/lib/module/react-query/hooks/useReactQueryState.js +1 -20
  136. package/lib/module/react-query/hooks/useSelectedMutation.js +1 -27
  137. package/lib/module/react-query/hooks/useSelectedQuery.js +1 -92
  138. package/lib/module/react-query/hooks/useStorageQueryCounts.js +1 -25
  139. package/lib/module/react-query/hooks/useWifiState.js +1 -64
  140. package/lib/module/react-query/stores/reactQueryEventStore.js +1 -293
  141. package/lib/module/react-query/sync/dehydrate.js +1 -156
  142. package/lib/module/react-query/sync/reactQuerySyncAdapter.js +1 -589
  143. package/lib/module/react-query/sync/snapshotProvider.js +1 -284
  144. package/lib/module/react-query/sync/useReactQuerySyncAdapter.js +1 -31
  145. package/lib/module/react-query/types/types.js +1 -10
  146. package/lib/module/react-query/utils/actions/deleteItem.js +1 -19
  147. package/lib/module/react-query/utils/actions/emitDevToolsEvent.js +1 -36
  148. package/lib/module/react-query/utils/actions/invalidate.js +1 -11
  149. package/lib/module/react-query/utils/actions/refetch.js +1 -13
  150. package/lib/module/react-query/utils/actions/remove.js +1 -11
  151. package/lib/module/react-query/utils/actions/reset.js +1 -13
  152. package/lib/module/react-query/utils/actions/triggerError.js +1 -29
  153. package/lib/module/react-query/utils/actions/triggerLoading.js +1 -50
  154. package/lib/module/react-query/utils/deleteNestedDataByPath.js +1 -51
  155. package/lib/module/react-query/utils/getQueryStatusColor.js +1 -12
  156. package/lib/module/react-query/utils/getQueryStatusLabel.js +1 -19
  157. package/lib/module/react-query/utils/getStorageQueryCounts.js +1 -31
  158. package/lib/module/react-query/utils/modalStorageOperations.js +1 -117
  159. package/lib/module/react-query/utils/storageQueryUtils.js +1 -140
  160. package/lib/module/react-query/utils/testIDs.js +1 -54
  161. package/lib/module/react-query/utils/updateNestedDataByPath.js +1 -56
  162. package/lib/web/index.mjs +3 -4
  163. package/package.json +4 -7
  164. package/lib/typescript/checkPeer.d.ts.map +0 -1
  165. package/lib/typescript/checkPeer.web.d.ts.map +0 -1
  166. package/lib/typescript/index.d.ts.map +0 -1
  167. package/lib/typescript/preset.d.ts.map +0 -1
  168. package/lib/typescript/react-query/components/DataEditorMode.d.ts.map +0 -1
  169. package/lib/typescript/react-query/components/FilterStatusBadge.d.ts.map +0 -1
  170. package/lib/typescript/react-query/components/MutationBrowserMode.d.ts.map +0 -1
  171. package/lib/typescript/react-query/components/MutationEditorMode.d.ts.map +0 -1
  172. package/lib/typescript/react-query/components/QueryBrowserMode.d.ts.map +0 -1
  173. package/lib/typescript/react-query/components/QueryDebugInfo.d.ts.map +0 -1
  174. package/lib/typescript/react-query/components/QueryFilterViewV3.d.ts.map +0 -1
  175. package/lib/typescript/react-query/components/QuerySelector.d.ts.map +0 -1
  176. package/lib/typescript/react-query/components/ReactQueryDevToolsModal.d.ts.map +0 -1
  177. package/lib/typescript/react-query/components/ReactQuerySection.d.ts.map +0 -1
  178. package/lib/typescript/react-query/components/ReactQueryTracker.d.ts.map +0 -1
  179. package/lib/typescript/react-query/components/WifiToggle.d.ts.map +0 -1
  180. package/lib/typescript/react-query/components/modals/DataEditorModal.d.ts.map +0 -1
  181. package/lib/typescript/react-query/components/modals/MutationBrowserFooter.d.ts.map +0 -1
  182. package/lib/typescript/react-query/components/modals/MutationBrowserModal.d.ts.map +0 -1
  183. package/lib/typescript/react-query/components/modals/MutationEditorModal.d.ts.map +0 -1
  184. package/lib/typescript/react-query/components/modals/QueryBrowserFooter.d.ts.map +0 -1
  185. package/lib/typescript/react-query/components/modals/QueryBrowserModal.d.ts.map +0 -1
  186. package/lib/typescript/react-query/components/modals/ReactQueryModal.d.ts.map +0 -1
  187. package/lib/typescript/react-query/components/modals/ReactQueryModalHeader.d.ts.map +0 -1
  188. package/lib/typescript/react-query/components/modals/SwipeIndicator.d.ts.map +0 -1
  189. package/lib/typescript/react-query/components/query-browser/ActionButton.d.ts.map +0 -1
  190. package/lib/typescript/react-query/components/query-browser/ClearCacheButton.d.ts.map +0 -1
  191. package/lib/typescript/react-query/components/query-browser/Explorer.d.ts.map +0 -1
  192. package/lib/typescript/react-query/components/query-browser/MutationButton.d.ts.map +0 -1
  193. package/lib/typescript/react-query/components/query-browser/MutationDetails.d.ts.map +0 -1
  194. package/lib/typescript/react-query/components/query-browser/MutationDetailsChips.d.ts.map +0 -1
  195. package/lib/typescript/react-query/components/query-browser/MutationInformation.d.ts.map +0 -1
  196. package/lib/typescript/react-query/components/query-browser/MutationStatusCount.d.ts.map +0 -1
  197. package/lib/typescript/react-query/components/query-browser/MutationsList.d.ts.map +0 -1
  198. package/lib/typescript/react-query/components/query-browser/NetworkToggleButton.d.ts.map +0 -1
  199. package/lib/typescript/react-query/components/query-browser/QueryActions.d.ts.map +0 -1
  200. package/lib/typescript/react-query/components/query-browser/QueryBrowser.d.ts.map +0 -1
  201. package/lib/typescript/react-query/components/query-browser/QueryDetails.d.ts.map +0 -1
  202. package/lib/typescript/react-query/components/query-browser/QueryDetailsChip.d.ts.map +0 -1
  203. package/lib/typescript/react-query/components/query-browser/QueryInformation.d.ts.map +0 -1
  204. package/lib/typescript/react-query/components/query-browser/QueryRow.d.ts.map +0 -1
  205. package/lib/typescript/react-query/components/query-browser/QueryStatus.d.ts.map +0 -1
  206. package/lib/typescript/react-query/components/query-browser/QueryStatusCount.d.ts.map +0 -1
  207. package/lib/typescript/react-query/components/query-browser/StorageStatusCount.d.ts.map +0 -1
  208. package/lib/typescript/react-query/components/query-browser/index.d.ts.map +0 -1
  209. package/lib/typescript/react-query/components/query-browser/svgs.d.ts.map +0 -1
  210. package/lib/typescript/react-query/hooks/useActionButtons.d.ts.map +0 -1
  211. package/lib/typescript/react-query/hooks/useAllMutations.d.ts.map +0 -1
  212. package/lib/typescript/react-query/hooks/useAllQueries.d.ts.map +0 -1
  213. package/lib/typescript/react-query/hooks/useModalManager.d.ts.map +0 -1
  214. package/lib/typescript/react-query/hooks/useModalPersistence.d.ts.map +0 -1
  215. package/lib/typescript/react-query/hooks/useMutationActionButtons.d.ts.map +0 -1
  216. package/lib/typescript/react-query/hooks/useQueryStatusCounts.d.ts.map +0 -1
  217. package/lib/typescript/react-query/hooks/useReactQueryState.d.ts.map +0 -1
  218. package/lib/typescript/react-query/hooks/useSelectedMutation.d.ts.map +0 -1
  219. package/lib/typescript/react-query/hooks/useSelectedQuery.d.ts.map +0 -1
  220. package/lib/typescript/react-query/hooks/useStorageQueryCounts.d.ts.map +0 -1
  221. package/lib/typescript/react-query/hooks/useWifiState.d.ts.map +0 -1
  222. package/lib/typescript/react-query/stores/reactQueryEventStore.d.ts.map +0 -1
  223. package/lib/typescript/react-query/sync/dehydrate.d.ts.map +0 -1
  224. package/lib/typescript/react-query/sync/reactQuerySyncAdapter.d.ts.map +0 -1
  225. package/lib/typescript/react-query/sync/snapshotProvider.d.ts.map +0 -1
  226. package/lib/typescript/react-query/sync/useReactQuerySyncAdapter.d.ts.map +0 -1
  227. package/lib/typescript/react-query/types/types.d.ts.map +0 -1
  228. package/lib/typescript/react-query/utils/actions/deleteItem.d.ts.map +0 -1
  229. package/lib/typescript/react-query/utils/actions/emitDevToolsEvent.d.ts.map +0 -1
  230. package/lib/typescript/react-query/utils/actions/invalidate.d.ts.map +0 -1
  231. package/lib/typescript/react-query/utils/actions/refetch.d.ts.map +0 -1
  232. package/lib/typescript/react-query/utils/actions/remove.d.ts.map +0 -1
  233. package/lib/typescript/react-query/utils/actions/reset.d.ts.map +0 -1
  234. package/lib/typescript/react-query/utils/actions/triggerError.d.ts.map +0 -1
  235. package/lib/typescript/react-query/utils/actions/triggerLoading.d.ts.map +0 -1
  236. package/lib/typescript/react-query/utils/deleteNestedDataByPath.d.ts.map +0 -1
  237. package/lib/typescript/react-query/utils/getQueryStatusColor.d.ts.map +0 -1
  238. package/lib/typescript/react-query/utils/getQueryStatusLabel.d.ts.map +0 -1
  239. package/lib/typescript/react-query/utils/getStorageQueryCounts.d.ts.map +0 -1
  240. package/lib/typescript/react-query/utils/modalStorageOperations.d.ts.map +0 -1
  241. package/lib/typescript/react-query/utils/storageQueryUtils.d.ts.map +0 -1
  242. package/lib/typescript/react-query/utils/testIDs.d.ts.map +0 -1
  243. package/lib/typescript/react-query/utils/updateNestedDataByPath.d.ts.map +0 -1
@@ -1,589 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * Sync adapter for the React Query tool, consumed by @buoy-gg/external-sync's
5
- * `useExternalSync` (structurally matches its ToolSyncAdapter interface so
6
- * this package doesn't need a dependency on it).
7
- *
8
- * Action handlers are ported from buoy-desktop's react-query-external-sync
9
- * (useSyncQueries.ts) so the dashboard keeps identical behavior, including
10
- * the trigger/restore loading and error simulations used by the TanStack
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`.
15
- */
16
- import { expandKeyedArrays, patchFromPath, readPath, refusalText, shapeSummary, suggestedPatch, typedEditViolations, unshapedLists } from "@buoy-gg/shared-ui";
17
- import { onlineManager } from "@tanstack/react-query";
18
- import { capQueryDetail, dehydrateQueryClient } from "./dehydrate";
19
- import { getQueryStatusLabel } from "../utils/getQueryStatusLabel";
20
-
21
- /**
22
- * Does this patch write into the list at `path`? Only then is an
23
- * unchecked-shape warning about that list worth saying — a patch that changes
24
- * `promoCode` should not be told about an empty `results`. Mirrors the same
25
- * helper in the zustand adapter, which has warned about this since it shipped.
26
- */
27
- function touchesList(patch, path) {
28
- let cur = patch;
29
- for (const seg of path.split(".")) {
30
- if (!cur || typeof cur !== "object" || Array.isArray(cur)) return false;
31
- if (!(seg in cur)) return false;
32
- cur = cur[seg];
33
- }
34
- // An empty list stays empty; there is no new item to be unsure about.
35
- return Array.isArray(cur) ? cur.length > 0 : !!cur && typeof cur === "object";
36
- }
37
- const isPlainObject = v => !!v && typeof v === "object" && !Array.isArray(v);
38
- /** The shape category the screen depends on: array vs object vs the rest. */
39
- function shapeKind(v) {
40
- if (Array.isArray(v)) return "array";
41
- if (v === null) return "null";
42
- if (typeof v === "object") return "object";
43
- return typeof v;
44
- }
45
-
46
- /**
47
- * Objects merge key by key; arrays and primitives are replaced. Two dangers a
48
- * remote caller (an LLM most of all) hits are collected instead of silently
49
- * written:
50
- *
51
- * - `shrunk`: a non-empty array shorter than the one it replaces — "change
52
- * item 0" sent as only item 0, dropping the rest.
53
- * - `breaks`: a field whose SHAPE changes — an array or object overwritten by
54
- * null or a primitive. This is the crash we actually shipped: a model set
55
- * the siblings it wasn't changing (`sizes:null, store:null`) thinking it had
56
- * to name them, and the screen's `sizes.map(s => s.multiplier)` threw. Merge
57
- * KEEPS untouched fields, so nulling them is never necessary and never safe.
58
- *
59
- * The handler refuses either unless forced. An empty array (explicit clear)
60
- * and null→value / value→value-of-same-kind are fine.
61
- */
62
- function deepMerge(base, patch, path = "", issues = {
63
- shrunk: [],
64
- breaks: []
65
- }) {
66
- if (Array.isArray(base) && Array.isArray(patch)) {
67
- if (patch.length > 0 && patch.length < base.length) {
68
- issues.shrunk.push({
69
- path: path || "(root)",
70
- have: base.length,
71
- sent: patch.length
72
- });
73
- }
74
- return patch;
75
- }
76
- if (!isPlainObject(base) || !isPlainObject(patch)) return patch;
77
- const out = {
78
- ...base
79
- };
80
- for (const [k, v] of Object.entries(patch)) {
81
- const p = path ? `${path}.${k}` : k;
82
- if (k in base) {
83
- const from = shapeKind(base[k]);
84
- const to = shapeKind(v);
85
- // A populated array/object being replaced by null or a primitive breaks
86
- // the shape the screen renders. (object→object and array→array recurse
87
- // or replace normally; null/primitive→anything is a real value change.)
88
- if ((from === "array" || from === "object") && from !== to) {
89
- issues.breaks.push({
90
- path: p,
91
- from,
92
- to
93
- });
94
- }
95
- out[k] = deepMerge(base[k], v, p, issues);
96
- } else {
97
- out[k] = v;
98
- }
99
- }
100
- return out;
101
- }
102
- /** Parse a loose, non-hash key spelling into comparable string parts, or null. */
103
- function looseKeyParts(raw) {
104
- const trimmed = raw.trim();
105
- try {
106
- const parsed = JSON.parse(trimmed);
107
- if (Array.isArray(parsed)) {
108
- return parsed.map(k => typeof k === "object" && k !== null ? JSON.stringify(k) : String(k));
109
- }
110
- } catch {
111
- /* not JSON — fall through to comma splitting */
112
- }
113
- if (trimmed.includes(",") && !trimmed.startsWith("[")) {
114
- return trimmed.split(",").map(s => s.trim().replace(/^["']|["']$/g, ""));
115
- }
116
- return null;
117
- }
118
- export function createReactQuerySyncAdapter(queryClient) {
119
- const getQuery = params => {
120
- const {
121
- queryHash
122
- } = params;
123
- const cache = queryClient.getQueryCache();
124
- let query = queryHash ? cache.get(queryHash) : undefined;
125
- // Tolerate a key that is not an exact hash. Models routinely send a
126
- // comma-joined key ("pokemon-detail,mewtwo,fetch") or a JSON array where a
127
- // hash is wanted; resolve it against the live cache by comparing each
128
- // query's key parts, so one malformed hash does not cost a turn.
129
- if (!query && typeof queryHash === "string") {
130
- const wanted = looseKeyParts(queryHash);
131
- if (wanted) {
132
- query = cache.getAll().find(q => {
133
- const parts = q.queryKey.map(k => typeof k === "object" ? JSON.stringify(k) : String(k));
134
- return parts.length === wanted.length && parts.every((p, i) => p === wanted[i]);
135
- });
136
- }
137
- }
138
- if (!query) {
139
- throw new Error(`Query with hash "${queryHash}" not found`);
140
- }
141
- return query;
142
- };
143
- return {
144
- version: 2,
145
- getSnapshot: () => ({
146
- dehydratedState: dehydrateQueryClient(queryClient),
147
- isOnlineManagerOnline: onlineManager.isOnline()
148
- }),
149
- subscribe: onChange => {
150
- const unsubQueries = queryClient.getQueryCache().subscribe(onChange);
151
- const unsubMutations = queryClient.getMutationCache().subscribe(onChange);
152
- const unsubOnline = onlineManager.subscribe(onChange);
153
- return () => {
154
- unsubQueries();
155
- unsubMutations();
156
- unsubOnline();
157
- };
158
- },
159
- actions: {
160
- /**
161
- * On-demand detail: one query's real cached `data`. Wire-form snapshots
162
- * replace oversized / unserializable data with markers; this is the
163
- * explicit, size-guarded channel for the detail pane.
164
- */
165
- getQueryData: params => {
166
- const {
167
- queryHash,
168
- path
169
- } = params ?? {};
170
- if (!queryHash) return {
171
- found: false,
172
- reason: "missing queryHash"
173
- };
174
- const query = queryClient.getQueryCache().get(queryHash);
175
- if (!query) return {
176
- found: false,
177
- reason: "unknown queryHash"
178
- };
179
- if (path) {
180
- const at = readPath(query.state.data, path);
181
- if (!at.ok) return {
182
- found: false,
183
- reason: at.error
184
- };
185
- return {
186
- found: true,
187
- queryHash,
188
- path,
189
- shape: shapeSummary(at.value),
190
- data: at.value
191
- };
192
- }
193
- // Before the data, not after: a long payload is sliced at the engine's
194
- // 24,000-character cap, and the shape is what a caller needs in order to
195
- // send a correctly NESTED edit back. Ten of eleven measured `query`
196
- // write failures were one level too shallow — `{name}` for a payload
197
- // that is `{item: {name}}` — and the sketch is where that is visible in
198
- // one line even when the data is not.
199
- // A query with no data is not the same as a query holding nothing, and
200
- // the two used to be indistinguishable: an errored query, a disabled
201
- // one and an empty one all came back as a bare `{found:true}`. A reader
202
- // — an LLM most of all — then reports "the query is empty" when the
203
- // truth is "it failed with X". `listQueries` has always known; this is
204
- // the call where anyone actually asks.
205
- if (query.state.data === undefined) {
206
- const status = query.state.status;
207
- const err = query.state.error;
208
- return {
209
- found: true,
210
- queryHash,
211
- hasData: false,
212
- status,
213
- fetchStatus: query.state.fetchStatus,
214
- ...(err ? {
215
- error: err instanceof Error ? err.message : String(err)
216
- } : {}),
217
- reason: status === "error" ? "This query has no data because it FAILED. Report the error, not an empty result." : query.state.fetchStatus === "fetching" ? "No data yet — this query is still fetching." : "This query has never resolved (it may be disabled, or never enabled). It is not empty — it has nothing."
218
- };
219
- }
220
- const shape = shapeSummary(query.state.data);
221
- return {
222
- found: true,
223
- queryHash,
224
- hasData: true,
225
- ...(shape ? {
226
- shape
227
- } : {}),
228
- data: capQueryDetail(query.state.data)
229
- };
230
- },
231
- /**
232
- * Compact, token-bounded cache reader for a remote driver (MCP/LLM):
233
- * projects each live query to light fields (hash, key, status label,
234
- * staleness, observers, error message) — the heavy cached `data` stays on
235
- * the device unless `includeData` is set. Unlike getSnapshot (full
236
- * dehydrated cache), this is safe to read repeatedly.
237
- */
238
- listQueries: params => {
239
- const {
240
- includeData = false,
241
- staleOnly = false,
242
- limit
243
- } = params ?? {};
244
- const all = queryClient.getQueryCache().getAll();
245
- const filtered = staleOnly ? all.filter(q => q.isStale()) : all;
246
- // MOUNTED FIRST, then most-recently-updated. `limit` exists to keep
247
- // this cheap for a remote reader, and sorting by recency alone made it
248
- // lossy in the one way that matters: a detail screen's query settles
249
- // once and is then older than every background refetch, so on a cache
250
- // with more live queries than the limit the query the user is actually
251
- // LOOKING AT was the first thing dropped. Nothing downstream can undo
252
- // that — a caller re-sorting the response can only reorder survivors.
253
- const sorted = [...filtered].sort((a, b) => {
254
- const mounted = Number(b.getObserversCount() > 0) - Number(a.getObserversCount() > 0);
255
- return mounted !== 0 ? mounted : (b.state.dataUpdatedAt ?? 0) - (a.state.dataUpdatedAt ?? 0);
256
- });
257
- const capped = typeof limit === "number" && limit > 0 ? sorted.slice(0, limit) : sorted;
258
- const queries = capped.map(q => {
259
- const err = q.state.error;
260
- return {
261
- queryHash: q.queryHash,
262
- queryKey: q.queryKey,
263
- status: getQueryStatusLabel(q),
264
- fetchStatus: q.state.fetchStatus,
265
- isStale: q.isStale(),
266
- observers: q.getObserversCount(),
267
- updatedAt: q.state.dataUpdatedAt,
268
- error: err ? err.message ?? String(err) : undefined,
269
- ...(includeData ? {
270
- data: q.state.data
271
- } : {}),
272
- // The compact view exists so a caller can survey the cache without
273
- // pulling payloads; the shape is the part of a payload it actually
274
- // needs to write a correct edit, and it costs one line.
275
- ...(shapeSummary(q.state.data) ? {
276
- shape: shapeSummary(q.state.data)
277
- } : {})
278
- };
279
- });
280
- return {
281
- queries,
282
- total: all.length,
283
- returned: queries.length,
284
- includedData: includeData
285
- };
286
- },
287
- refetch: params => {
288
- const query = getQuery(params);
289
- // Swallow fetch rejections — the resulting error state syncs anyway
290
- return query.fetch().catch(() => undefined);
291
- },
292
- invalidate: params => queryClient.invalidateQueries(getQuery(params)),
293
- reset: params => queryClient.resetQueries(getQuery(params)),
294
- /**
295
- * Dropping a query does NOT re-drive the screen watching it.
296
- *
297
- * React Query removes the cache entry; a mounted observer keeps its last
298
- * result in local state until something makes it fetch again. So the app
299
- * carries on rendering a value that now exists nowhere — including one
300
- * the agent itself wrote a moment earlier. Measured on device: `remove`
301
- * on the live menu query left the storefront showing a single fabricated
302
- * item, with no skeleton, no refetch and no error, while the cache held
303
- * no menu at all. Returning a bare null let that be reported as "done".
304
- *
305
- * `reset` is the action that actually re-drives an observed query, so
306
- * the note names it rather than leaving the caller to find out from a
307
- * screen that looks fine.
308
- */
309
- remove: params => {
310
- const target = getQuery(params);
311
- const watched = queryClient.getQueryCache().findAll(target).some(q => q.getObserversCount() > 0);
312
- queryClient.removeQueries(target);
313
- return {
314
- ok: true,
315
- ...(watched ? {
316
- note: "Removed — but a screen is still watching this query, and React Query leaves that screen rendering its LAST value (including anything written into the cache before this) until something refetches. Nothing on screen will change on its own. Use `reset` instead when you want the screen to go back to loading and fetch again."
317
- } : {})
318
- };
319
- },
320
- setQueryData: params => {
321
- const {
322
- data,
323
- merge,
324
- force,
325
- path,
326
- value
327
- } = params;
328
- /**
329
- * Address the query the way EVERY OTHER action here does.
330
- *
331
- * This action took `queryKey` and silently ignored `queryHash` — while
332
- * `listQueries` hands out `queryHash` and getQueryData / invalidate /
333
- * refetch / reset / remove / triggerError / triggerLoading all take it.
334
- * A caller that used the hash got `getQueryData(undefined)` →
335
- * `undefined`, and so a refusal about "(root): undefined → object"
336
- * that named the wrong problem. With `force:true` — which that refusal
337
- * literally suggests — it wrote under an undefined key and still
338
- * returned `{ok:true, changedKeys:[…]}`: a success report for a write
339
- * that touched nothing, which is the one outcome this codebase refuses
340
- * to ship. Ask Buoy itself was covered because the ENGINE aliases hash
341
- * → key before dispatch; the MCP server, the desktop dashboard and
342
- * Scenarios all call straight in here and were not.
343
- */
344
- const {
345
- queryKey: rawKey,
346
- queryHash
347
- } = params;
348
- let queryKey = rawKey;
349
- if (queryKey === undefined && typeof queryHash === "string") {
350
- const found = queryClient.getQueryCache().get(queryHash);
351
- if (!found) {
352
- return {
353
- ok: false,
354
- error: `Refused: no query with hash ${queryHash} is in the cache. Read listQueries for the current hashes — a query that has been removed or whose key includes changing params (a search term, a cart payload) will not match an older hash.`
355
- };
356
- }
357
- queryKey = found.queryKey;
358
- }
359
- if (queryKey === undefined) {
360
- return {
361
- ok: false,
362
- error: `Refused: no query was named. Send \`queryKey\` (the array from listQueries) or \`queryHash\` (its string form).`
363
- };
364
- }
365
- const current = queryClient.getQueryData(queryKey);
366
- /**
367
- * There is nothing to merge INTO.
368
- *
369
- * The typed-edit guard answers this with "`(root)`: undefined →
370
- * object", which describes the symptom and not the cause — and it is
371
- * the same sentence a caller used to get when the query simply could
372
- * not be found, so it taught nothing. A query with no data is usually
373
- * one that FAILED or was never enabled, and that is what the caller
374
- * needs to hear.
375
- */
376
- const existing = queryClient.getQueryCache().find({
377
- queryKey,
378
- exact: true
379
- });
380
- // Only when the query is THERE and holds nothing. A key that is not in
381
- // the cache at all is a deliberate seed — `setQueryData(["new"], …)`
382
- // creates the entry, and that has always worked.
383
- if (current === undefined && existing && (data !== undefined || path !== undefined)) {
384
- const q = existing;
385
- const status = q?.state.status;
386
- const why = status === "error" ? `it FAILED${q?.state.error ? ` (${q.state.error instanceof Error ? q.state.error.message : String(q.state.error)})` : ""}` : status === "pending" ? "it has never resolved (it may be disabled, or still loading)" : "it holds no data";
387
- return {
388
- ok: false,
389
- error: `Refused: this query has no data to edit — ${why}. There is nothing to merge into. Fix the cause first (restoreError, or let it fetch), or send force:true with the COMPLETE value if you mean to seed the cache from nothing.`,
390
- status
391
- };
392
- }
393
- // `path` is sugar over a merge, resolved against the data as it is now.
394
- // It only ever produces a patch; everything below — the keyed expansion,
395
- // the typed-edit guard, the receipt — then runs unchanged, so the guard
396
- // stays the single place that decides what a write may do.
397
- // `data` stopped being schema-required when `path` became an
398
- // alternative, so the handler has to reject NEITHER — the same hole that
399
- // let a bare `setState` fall through to a whole-store replace. Here it
400
- // would write `undefined` over a cached value.
401
- if (data === undefined && path === undefined) {
402
- return {
403
- ok: false,
404
- error: `Refused: no change was described. Send \`data\` (with merge:true for a partial edit), or \`path\` and \`value\` to set one value.`
405
- };
406
- }
407
- let patch = data;
408
- if (path !== undefined) {
409
- if (value === undefined) {
410
- return {
411
- ok: false,
412
- error: `Refused: sent \`path\` without \`value\`. Say what to set "${path}" to; if you mean to clear it, send value:null and the field must already be nullable.`
413
- };
414
- }
415
- const built = patchFromPath(current, path, value);
416
- if (!built.ok) return {
417
- ok: false,
418
- error: `Refused: ${built.error}`
419
- };
420
- patch = built.patch;
421
- }
422
- if (merge || path !== undefined) {
423
- // Address list items by their own id instead of resending the list:
424
- // {"results": {"pikachu": {"name": "test123"}}}
425
- // Expanded BEFORE the guard below, so the typed-edit rule still holds
426
- // over the result. This is the only form that works when the read was
427
- // truncated — and a capped read is the normal case here, not the edge
428
- // one. See packages/shared/src/sync/keyedArrays.ts for the measurement.
429
- const expandedKeyed = force ? {
430
- patch,
431
- notes: [],
432
- error: undefined
433
- } : expandKeyedArrays(current, patch);
434
- // An id that contradicts its own address is refused HERE, where we
435
- // still know both halves; the typed-edit guard downstream would only
436
- // see the item we picked and could not name the ambiguity.
437
- if (expandedKeyed.error) {
438
- return {
439
- ok: false,
440
- error: `Refused: ${expandedKeyed.error}`
441
- };
442
- }
443
- const effective = expandedKeyed.patch;
444
- // Edit like the devtools value editor: only same-type changes to
445
- // fields that already exist. One rule replaces every ad-hoc guard —
446
- // no new keys, no type changes, no null-ing a rendered array/object,
447
- // no resizing a list. This is what makes a crash structurally
448
- // impossible. `force` drops to a raw write for the rare real case.
449
- if (!force) {
450
- const violations = typedEditViolations(current, effective, {
451
- noun: "data"
452
- });
453
- if (violations.length > 0) {
454
- const suggestion = suggestedPatch(effective, violations);
455
- return {
456
- ok: false,
457
- error: refusalText(violations, "data", suggestion),
458
- violations,
459
- ...(suggestion ? {
460
- suggestedData: suggestion
461
- } : {})
462
- };
463
- }
464
- }
465
- const next = deepMerge(current, effective);
466
- // A list that was EMPTY had no item shape for anything to check the
467
- // new item against — not the guard above, not the reader, not the
468
- // app. The zustand tool has always said so; this one stayed silent
469
- // while the system prompt told the model the note always arrives, so
470
- // a write of an invented shape into an empty list came back a clean
471
- // success and got reported as one.
472
- const unchecked = unshapedLists(current).filter(p => touchesList(effective, p));
473
- queryClient.setQueryData(queryKey, next, {
474
- updatedAt: Date.now()
475
- });
476
- return {
477
- ok: true,
478
- mode: "merge",
479
- ...(path !== undefined ? {
480
- path
481
- } : {}),
482
- changedKeys: isPlainObject(effective) ? Object.keys(effective) : undefined,
483
- ...(expandedKeyed.notes.length ? {
484
- keyed: expandedKeyed.notes
485
- } : {}),
486
- ...(unchecked.length ? {
487
- unchecked: unchecked.map(p => `\`${p}\` was empty, so nothing in the app knows what its items look like and the shape of what you added was NOT checked. If the screen renders a field you left out, it will render undefined — read the query back and compare against how the screen uses it.`)
488
- } : {})
489
- };
490
- }
491
- // THE GUARD. A remote caller — an LLM most of all — reads the cached
492
- // value through a wire that truncates big payloads, edits one field,
493
- // and writes the torn object back. The screen then renders
494
- // `data.stats.map` over a field that no longer exists and the app
495
- // dies. If the replacement silently drops top-level keys the cache
496
- // has, that is almost never intended, so refuse and name the fix.
497
- if (!force && isPlainObject(current) && isPlainObject(data)) {
498
- const missing = Object.keys(current).filter(k => !(k in data));
499
- if (missing.length > 0) {
500
- return {
501
- ok: false,
502
- error: `Refused: the new value drops ${missing.length} top-level field(s) the cached value has (${missing.slice(0, 8).join(", ")}${missing.length > 8 ? ", …" : ""}). A screen rendering those fields would crash. To change some fields, send merge:true with ONLY the fields that change. To really replace the whole value, send force:true.`,
503
- missingKeys: missing
504
- };
505
- }
506
- }
507
- queryClient.setQueryData(queryKey, data, {
508
- updatedAt: Date.now()
509
- });
510
- return {
511
- ok: true,
512
- mode: "replace"
513
- };
514
- },
515
- triggerError: params => {
516
- const query = getQuery(params);
517
- const __previousQueryOptions = query.options;
518
- query.setState({
519
- status: "error",
520
- error: new Error("Unknown error from devtools"),
521
- fetchMeta: {
522
- ...query.state.fetchMeta,
523
- // @ts-expect-error This does exist
524
- __previousQueryOptions
525
- }
526
- });
527
- },
528
- restoreError: params => queryClient.resetQueries(getQuery(params)),
529
- triggerLoading: params => {
530
- const query = getQuery(params);
531
- const __previousQueryOptions = query.options;
532
- // Trigger a fetch in order to trigger suspense as well
533
- query.fetch({
534
- ...__previousQueryOptions,
535
- queryFn: () => new Promise(() => {
536
- // Never resolve — simulates perpetual loading
537
- }),
538
- gcTime: -1
539
- }).catch(() => undefined);
540
- query.setState({
541
- data: undefined,
542
- status: "pending",
543
- fetchMeta: {
544
- ...query.state.fetchMeta,
545
- // @ts-expect-error This does exist
546
- __previousQueryOptions
547
- }
548
- });
549
- },
550
- restoreLoading: params => {
551
- const query = getQuery(params);
552
- const previousState = query.state;
553
- const previousOptions = query.state.fetchMeta ? query.state.fetchMeta.__previousQueryOptions : null;
554
- query.cancel({
555
- silent: true
556
- });
557
- query.setState({
558
- ...previousState,
559
- fetchStatus: "idle",
560
- fetchMeta: null
561
- });
562
- if (previousOptions) {
563
- query.fetch(previousOptions).catch(() => undefined);
564
- }
565
- },
566
- clearQueryCache: () => {
567
- // Same trap as `remove`, across every screen at once. See its note.
568
- const watched = queryClient.getQueryCache().getAll().filter(q => q.getObserversCount() > 0).length;
569
- queryClient.getQueryCache().clear();
570
- return {
571
- ok: true,
572
- cleared: true,
573
- ...(watched ? {
574
- note: `Cleared — but ${watched} quer${watched === 1 ? "y is" : "ies are"} still being watched by a screen, and React Query leaves those screens rendering their LAST value until something refetches. The cache is empty; the app on screen is not. Use \`reset\` on a query when you want its screen to reload.`
575
- } : {})
576
- };
577
- },
578
- clearMutationCache: () => {
579
- queryClient.getMutationCache().clear();
580
- },
581
- setOnline: params => {
582
- const {
583
- online
584
- } = params;
585
- onlineManager.setOnline(online);
586
- }
587
- }
588
- };
589
- }
1
+ "use strict";import{expandKeyedArrays as O,patchFromPath as $,readPath as D,refusalText as M,shapeSummary as b,suggestedPatch as K,typedEditViolations as R,unshapedLists as j}from"@buoy-gg/shared-ui";import{onlineManager as Q}from"@tanstack/react-query";import{capQueryDetail as E,dehydrateQueryClient as T}from"./dehydrate";import{getQueryStatusLabel as L}from"../utils/getQueryStatusLabel";function N(r,o){let t=r;for(const e of o.split(".")){if(!t||typeof t!=="object"||Array.isArray(t))return false;if(!(e in t))return false;t=t[e]}return Array.isArray(t)?t.length>0:!!t&&typeof t==="object"}const m=r=>!!r&&typeof r==="object"&&!Array.isArray(r);function S(r){if(Array.isArray(r))return"array";if(r===null)return"null";if(typeof r==="object")return"object";return typeof r}function k(r,o,t="",e={shrunk:[],breaks:[]}){if(Array.isArray(r)&&Array.isArray(o)){if(o.length>0&&o.length<r.length){e.shrunk.push({path:t||"(root)",have:r.length,sent:o.length})}return o}if(!m(r)||!m(o))return o;const s={...r};for(const[n,u]of Object.entries(o)){const c=t?`${t}.${n}`:n;if(n in r){const d=S(r[n]);const h=S(u);if((d==="array"||d==="object")&&d!==h){e.breaks.push({path:c,from:d,to:h})}s[n]=k(r[n],u,c,e)}else{s[n]=u}}return s}function x(r){const o=r.trim();try{const t=JSON.parse(o);if(Array.isArray(t)){return t.map(e=>typeof e==="object"&&e!==null?JSON.stringify(e):String(e))}}catch{}if(o.includes(",")&&!o.startsWith("[")){return o.split(",").map(t=>t.trim().replace(/^["']|["']$/g,""))}return null}export function createReactQuerySyncAdapter(r){const o=t=>{const{queryHash:e}=t;const s=r.getQueryCache();let n=e?s.get(e):void 0;if(!n&&typeof e==="string"){const u=x(e);if(u){n=s.getAll().find(c=>{const d=c.queryKey.map(h=>typeof h==="object"?JSON.stringify(h):String(h));return d.length===u.length&&d.every((h,f)=>h===u[f])})}}if(!n){throw new Error(`Query with hash "${e}" not found`)}return n};return{version:2,getSnapshot:()=>({dehydratedState:T(r),isOnlineManagerOnline:Q.isOnline()}),subscribe:t=>{const e=r.getQueryCache().subscribe(t);const s=r.getMutationCache().subscribe(t);const n=Q.subscribe(t);return()=>{e();s();n()}},actions:{getQueryData:t=>{const{queryHash:e,path:s}=t??{};if(!e)return{found:false,reason:"missing queryHash"};const n=r.getQueryCache().get(e);if(!n)return{found:false,reason:"unknown queryHash"};if(s){const c=D(n.state.data,s);if(!c.ok)return{found:false,reason:c.error};return{found:true,queryHash:e,path:s,shape:b(c.value),data:c.value}}if(n.state.data===void 0){const c=n.state.status;const d=n.state.error;return{found:true,queryHash:e,hasData:false,status:c,fetchStatus:n.state.fetchStatus,...d?{error:d instanceof Error?d.message:String(d)}:{},reason:c==="error"?"This query has no data because it FAILED. Report the error, not an empty result.":n.state.fetchStatus==="fetching"?"No data yet \u2014 this query is still fetching.":"This query has never resolved (it may be disabled, or never enabled). It is not empty \u2014 it has nothing."}}const u=b(n.state.data);return{found:true,queryHash:e,hasData:true,...u?{shape:u}:{},data:E(n.state.data)}},listQueries:t=>{const{includeData:e=false,staleOnly:s=false,limit:n}=t??{};const u=r.getQueryCache().getAll();const c=s?u.filter(a=>a.isStale()):u;const d=[...c].sort((a,y)=>{const p=Number(y.getObserversCount()>0)-Number(a.getObserversCount()>0);return p!==0?p:(y.state.dataUpdatedAt??0)-(a.state.dataUpdatedAt??0)});const h=typeof n==="number"&&n>0?d.slice(0,n):d;const f=h.map(a=>{const y=a.state.error;return{queryHash:a.queryHash,queryKey:a.queryKey,status:L(a),fetchStatus:a.state.fetchStatus,isStale:a.isStale(),observers:a.getObserversCount(),updatedAt:a.state.dataUpdatedAt,error:y?y.message??String(y):void 0,...e?{data:a.state.data}:{},...b(a.state.data)?{shape:b(a.state.data)}:{}}});return{queries:f,total:u.length,returned:f.length,includedData:e}},refetch:t=>{const e=o(t);return e.fetch().catch(()=>void 0)},invalidate:t=>r.invalidateQueries(o(t)),reset:t=>r.resetQueries(o(t)),remove:t=>{const e=o(t);const s=r.getQueryCache().findAll(e).some(n=>n.getObserversCount()>0);r.removeQueries(e);return{ok:true,...s?{note:"Removed \u2014 but a screen is still watching this query, and React Query leaves that screen rendering its LAST value (including anything written into the cache before this) until something refetches. Nothing on screen will change on its own. Use `reset` instead when you want the screen to go back to loading and fetch again."}:{}}},setQueryData:t=>{const{data:e,merge:s,force:n,path:u,value:c}=t;const{queryKey:d,queryHash:h}=t;let f=d;if(f===void 0&&typeof h==="string"){const i=r.getQueryCache().get(h);if(!i){return{ok:false,error:`Refused: no query with hash ${h} is in the cache. Read listQueries for the current hashes \u2014 a query that has been removed or whose key includes changing params (a search term, a cart payload) will not match an older hash.`}}f=i.queryKey}if(f===void 0){return{ok:false,error:`Refused: no query was named. Send \`queryKey\` (the array from listQueries) or \`queryHash\` (its string form).`}}const a=r.getQueryData(f);const y=r.getQueryCache().find({queryKey:f,exact:true});if(a===void 0&&y&&(e!==void 0||u!==void 0)){const i=y;const l=i?.state.status;const w=l==="error"?`it FAILED${i?.state.error?` (${i.state.error instanceof Error?i.state.error.message:String(i.state.error)})`:""}`:l==="pending"?"it has never resolved (it may be disabled, or still loading)":"it holds no data";return{ok:false,error:`Refused: this query has no data to edit \u2014 ${w}. There is nothing to merge into. Fix the cause first (restoreError, or let it fetch), or send force:true with the COMPLETE value if you mean to seed the cache from nothing.`,status:l}}if(e===void 0&&u===void 0){return{ok:false,error:`Refused: no change was described. Send \`data\` (with merge:true for a partial edit), or \`path\` and \`value\` to set one value.`}}let p=e;if(u!==void 0){if(c===void 0){return{ok:false,error:`Refused: sent \`path\` without \`value\`. Say what to set "${u}" to; if you mean to clear it, send value:null and the field must already be nullable.`}}const i=$(a,u,c);if(!i.ok)return{ok:false,error:`Refused: ${i.error}`};p=i.patch}if(s||u!==void 0){const i=n?{patch:p,notes:[],error:void 0}:O(a,p);if(i.error){return{ok:false,error:`Refused: ${i.error}`}}const l=i.patch;if(!n){const g=R(a,l,{noun:"data"});if(g.length>0){const v=K(l,g);return{ok:false,error:M(g,"data",v),violations:g,...v?{suggestedData:v}:{}}}}const w=k(a,l);const A=j(a).filter(g=>N(l,g));r.setQueryData(f,w,{updatedAt:Date.now()});return{ok:true,mode:"merge",...u!==void 0?{path:u}:{},changedKeys:m(l)?Object.keys(l):void 0,...i.notes.length?{keyed:i.notes}:{},...A.length?{unchecked:A.map(g=>`\`${g}\` was empty, so nothing in the app knows what its items look like and the shape of what you added was NOT checked. If the screen renders a field you left out, it will render undefined \u2014 read the query back and compare against how the screen uses it.`)}:{}}}if(!n&&m(a)&&m(e)){const i=Object.keys(a).filter(l=>!(l in e));if(i.length>0){return{ok:false,error:`Refused: the new value drops ${i.length} top-level field(s) the cached value has (${i.slice(0,8).join(", ")}${i.length>8?", \u2026":""}). A screen rendering those fields would crash. To change some fields, send merge:true with ONLY the fields that change. To really replace the whole value, send force:true.`,missingKeys:i}}}r.setQueryData(f,e,{updatedAt:Date.now()});return{ok:true,mode:"replace"}},triggerError:t=>{const e=o(t);const s=e.options;e.setState({status:"error",error:new Error("Unknown error from devtools"),fetchMeta:{...e.state.fetchMeta,__previousQueryOptions:s}})},restoreError:t=>r.resetQueries(o(t)),triggerLoading:t=>{const e=o(t);const s=e.options;e.fetch({...s,queryFn:()=>new Promise(()=>{}),gcTime:-1}).catch(()=>void 0);e.setState({data:void 0,status:"pending",fetchMeta:{...e.state.fetchMeta,__previousQueryOptions:s}})},restoreLoading:t=>{const e=o(t);const s=e.state;const n=e.state.fetchMeta?e.state.fetchMeta.__previousQueryOptions:null;e.cancel({silent:true});e.setState({...s,fetchStatus:"idle",fetchMeta:null});if(n){e.fetch(n).catch(()=>void 0)}},clearQueryCache:()=>{const t=r.getQueryCache().getAll().filter(e=>e.getObserversCount()>0).length;r.getQueryCache().clear();return{ok:true,cleared:true,...t?{note:`Cleared \u2014 but ${t} quer${t===1?"y is":"ies are"} still being watched by a screen, and React Query leaves those screens rendering their LAST value until something refetches. The cache is empty; the app on screen is not. Use \`reset\` on a query when you want its screen to reload.`}:{}}},clearMutationCache:()=>{r.getMutationCache().clear()},setOnline:t=>{const{online:e}=t;Q.setOnline(e)}}}}