@buoy-gg/network 7.0.40 → 7.0.42

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 (275) hide show
  1. package/README.md +11 -79
  2. package/lib/commonjs/index.js +1 -325
  3. package/lib/commonjs/index.web.js +1 -420
  4. package/lib/commonjs/network/components/DataViewer.web.js +1 -879
  5. package/lib/commonjs/network/components/NetworkCopyScreen.web.js +1 -48
  6. package/lib/commonjs/network/components/NetworkCopySettingsView.js +27 -755
  7. package/lib/commonjs/network/components/NetworkCopySettingsView.web.js +14 -1242
  8. package/lib/commonjs/network/components/NetworkDetailScreen.web.js +1 -101
  9. package/lib/commonjs/network/components/NetworkDetailStepper.js +1 -108
  10. package/lib/commonjs/network/components/NetworkDetailStepper.web.js +1 -298
  11. package/lib/commonjs/network/components/NetworkEventDetailView.js +15 -1130
  12. package/lib/commonjs/network/components/NetworkEventDetailView.web.js +15 -1484
  13. package/lib/commonjs/network/components/NetworkEventItemCompact.js +2 -401
  14. package/lib/commonjs/network/components/NetworkEventItemCompact.web.js +2 -820
  15. package/lib/commonjs/network/components/NetworkFilterScreen.web.js +1 -55
  16. package/lib/commonjs/network/components/NetworkFilterViewV3.js +1 -442
  17. package/lib/commonjs/network/components/NetworkFilterViewV3.web.js +1 -1310
  18. package/lib/commonjs/network/components/NetworkHeaderLive.js +1 -375
  19. package/lib/commonjs/network/components/NetworkHeaderLive.web.js +1 -623
  20. package/lib/commonjs/network/components/NetworkHeaderMenu.js +1 -190
  21. package/lib/commonjs/network/components/NetworkListScreen.js +1 -404
  22. package/lib/commonjs/network/components/NetworkListScreen.web.js +1 -625
  23. package/lib/commonjs/network/components/NetworkModal.js +1 -786
  24. package/lib/commonjs/network/components/NetworkNumberPrompt.js +1 -178
  25. package/lib/commonjs/network/components/NetworkNumberPrompt.web.js +1 -232
  26. package/lib/commonjs/network/components/NetworkOverrideEditor.js +1 -814
  27. package/lib/commonjs/network/components/NetworkOverrideEditor.web.js +1 -942
  28. package/lib/commonjs/network/components/NetworkOverrideHeaderButton.js +1 -107
  29. package/lib/commonjs/network/components/NetworkOverrideHeaderButton.web.js +1 -133
  30. package/lib/commonjs/network/components/NetworkOverridesButton.js +1 -90
  31. package/lib/commonjs/network/components/NetworkOverridesButton.web.js +1 -143
  32. package/lib/commonjs/network/components/NetworkOverridesScreen.js +1 -543
  33. package/lib/commonjs/network/components/NetworkOverridesScreen.web.js +1 -830
  34. package/lib/commonjs/network/components/NetworkSavedScreen.js +1 -226
  35. package/lib/commonjs/network/components/NetworkSavedScreen.web.js +1 -463
  36. package/lib/commonjs/network/components/NetworkUpgradeBanner.js +1 -76
  37. package/lib/commonjs/network/components/response-editor/Explorer.js +1 -973
  38. package/lib/commonjs/network/components/response-editor/Explorer.web.js +1 -1136
  39. package/lib/commonjs/network/components/response-editor/deleteNestedDataByPath.js +1 -56
  40. package/lib/commonjs/network/components/response-editor/editorContext.js +1 -33
  41. package/lib/commonjs/network/components/response-editor/updateNestedDataByPath.js +1 -61
  42. package/lib/commonjs/network/conditions/NetworkConditionsControl.js +1 -235
  43. package/lib/commonjs/network/conditions/NetworkConditionsControl.test.js +1 -136
  44. package/lib/commonjs/network/conditions/NetworkConditionsIcon.js +1 -33
  45. package/lib/commonjs/network/conditions/NetworkFloatingTool.js +1 -310
  46. package/lib/commonjs/network/conditions/NetworkFloatingTool.test.js +1 -219
  47. package/lib/commonjs/network/conditions/store.js +1 -75
  48. package/lib/commonjs/network/conditions/wait.js +1 -43
  49. package/lib/commonjs/network/conditions/xhr.js +1 -110
  50. package/lib/commonjs/network/hooks/useLiveNetworkEvent.js +1 -62
  51. package/lib/commonjs/network/hooks/useNetworkBadgeCounts.js +1 -83
  52. package/lib/commonjs/network/hooks/useNetworkEventList.js +1 -108
  53. package/lib/commonjs/network/hooks/useNetworkEvents.js +1 -318
  54. package/lib/commonjs/network/hooks/useNetworkHasMatches.js +1 -56
  55. package/lib/commonjs/network/hooks/useNetworkSaved.js +1 -38
  56. package/lib/commonjs/network/hooks/useNetworkSelection.js +1 -53
  57. package/lib/commonjs/network/hooks/useOverrideRules.js +1 -36
  58. package/lib/commonjs/network/hooks/useTickEveryMinute.js +1 -21
  59. package/lib/commonjs/network/overrides/applyToFetch.js +1 -80
  60. package/lib/commonjs/network/overrides/applyToXhr.js +2 -453
  61. package/lib/commonjs/network/overrides/engine.js +1 -93
  62. package/lib/commonjs/network/overrides/matchRule.js +1 -81
  63. package/lib/commonjs/network/overrides/overriddenRows.js +1 -0
  64. package/lib/commonjs/network/overrides/overrideRulesStore.js +1 -550
  65. package/lib/commonjs/network/overrides/presets.js +1 -70
  66. package/lib/commonjs/network/overrides/resolveOverride.js +1 -158
  67. package/lib/commonjs/network/overrides/types.js +1 -90
  68. package/lib/commonjs/network/sync/networkBodyResolver.js +1 -39
  69. package/lib/commonjs/network/sync/networkSyncAdapter.js +1 -882
  70. package/lib/commonjs/network/sync/overrideHonesty.release.test.js +1 -36
  71. package/lib/commonjs/network/types/index.js +1 -5
  72. package/lib/commonjs/network/utils/extractOperationName.js +1 -80
  73. package/lib/commonjs/network/utils/filterNetworkEvents.js +1 -96
  74. package/lib/commonjs/network/utils/formatGraphQLVariables.js +1 -219
  75. package/lib/commonjs/network/utils/formatting.js +1 -30
  76. package/lib/commonjs/network/utils/generateCurl.js +2 -71
  77. package/lib/commonjs/network/utils/generateNetworkCopyText.js +37 -166
  78. package/lib/commonjs/network/utils/httpCompletion.js +1 -37
  79. package/lib/commonjs/network/utils/networkEventStore.js +1 -393
  80. package/lib/commonjs/network/utils/networkListener.js +4 -1259
  81. package/lib/commonjs/network/utils/networkSavedStore.js +3 -577
  82. package/lib/commonjs/network/utils/networkSelectionStore.js +1 -193
  83. package/lib/commonjs/network/utils/realNow.js +1 -0
  84. package/lib/commonjs/network/utils/requestId.js +1 -0
  85. package/lib/commonjs/network/utils/resolveRequestUrl.js +1 -0
  86. package/lib/commonjs/network/utils/selectSavedEvents.js +1 -39
  87. package/lib/commonjs/network/utils/startNetworkCapture.js +1 -0
  88. package/lib/commonjs/network/utils/withPinnedFirst.js +1 -32
  89. package/lib/commonjs/preset.js +1 -102
  90. package/lib/module/index.js +1 -103
  91. package/lib/module/index.web.js +1 -82
  92. package/lib/module/network/components/DataViewer.web.js +1 -875
  93. package/lib/module/network/components/NetworkCopyScreen.web.js +1 -44
  94. package/lib/module/network/components/NetworkCopySettingsView.js +27 -750
  95. package/lib/module/network/components/NetworkCopySettingsView.web.js +14 -1237
  96. package/lib/module/network/components/NetworkDetailScreen.web.js +1 -97
  97. package/lib/module/network/components/NetworkDetailStepper.js +1 -104
  98. package/lib/module/network/components/NetworkDetailStepper.web.js +1 -296
  99. package/lib/module/network/components/NetworkEventDetailView.js +15 -1129
  100. package/lib/module/network/components/NetworkEventDetailView.web.js +15 -1482
  101. package/lib/module/network/components/NetworkEventItemCompact.js +2 -398
  102. package/lib/module/network/components/NetworkEventItemCompact.web.js +2 -818
  103. package/lib/module/network/components/NetworkFilterScreen.web.js +1 -51
  104. package/lib/module/network/components/NetworkFilterViewV3.js +1 -438
  105. package/lib/module/network/components/NetworkFilterViewV3.web.js +1 -1306
  106. package/lib/module/network/components/NetworkHeaderLive.js +1 -366
  107. package/lib/module/network/components/NetworkHeaderLive.web.js +1 -617
  108. package/lib/module/network/components/NetworkHeaderMenu.js +1 -184
  109. package/lib/module/network/components/NetworkListScreen.js +1 -400
  110. package/lib/module/network/components/NetworkListScreen.web.js +1 -623
  111. package/lib/module/network/components/NetworkModal.js +1 -781
  112. package/lib/module/network/components/NetworkNumberPrompt.js +1 -174
  113. package/lib/module/network/components/NetworkNumberPrompt.web.js +1 -230
  114. package/lib/module/network/components/NetworkOverrideEditor.js +1 -811
  115. package/lib/module/network/components/NetworkOverrideEditor.web.js +1 -939
  116. package/lib/module/network/components/NetworkOverrideHeaderButton.js +1 -104
  117. package/lib/module/network/components/NetworkOverrideHeaderButton.web.js +1 -131
  118. package/lib/module/network/components/NetworkOverridesButton.js +1 -87
  119. package/lib/module/network/components/NetworkOverridesButton.web.js +1 -141
  120. package/lib/module/network/components/NetworkOverridesScreen.js +1 -539
  121. package/lib/module/network/components/NetworkOverridesScreen.web.js +1 -826
  122. package/lib/module/network/components/NetworkSavedScreen.js +1 -222
  123. package/lib/module/network/components/NetworkSavedScreen.web.js +1 -461
  124. package/lib/module/network/components/NetworkUpgradeBanner.js +1 -72
  125. package/lib/module/network/components/response-editor/Explorer.js +1 -972
  126. package/lib/module/network/components/response-editor/Explorer.web.js +1 -1133
  127. package/lib/module/network/components/response-editor/deleteNestedDataByPath.js +1 -51
  128. package/lib/module/network/components/response-editor/editorContext.js +1 -29
  129. package/lib/module/network/components/response-editor/updateNestedDataByPath.js +1 -56
  130. package/lib/module/network/conditions/NetworkConditionsControl.js +1 -231
  131. package/lib/module/network/conditions/NetworkConditionsControl.test.js +1 -135
  132. package/lib/module/network/conditions/NetworkConditionsIcon.js +1 -29
  133. package/lib/module/network/conditions/NetworkFloatingTool.js +1 -304
  134. package/lib/module/network/conditions/NetworkFloatingTool.test.js +1 -218
  135. package/lib/module/network/conditions/store.js +1 -65
  136. package/lib/module/network/conditions/wait.js +1 -38
  137. package/lib/module/network/conditions/xhr.js +1 -106
  138. package/lib/module/network/hooks/useLiveNetworkEvent.js +1 -58
  139. package/lib/module/network/hooks/useNetworkBadgeCounts.js +1 -79
  140. package/lib/module/network/hooks/useNetworkEventList.js +1 -104
  141. package/lib/module/network/hooks/useNetworkEvents.js +1 -314
  142. package/lib/module/network/hooks/useNetworkHasMatches.js +1 -52
  143. package/lib/module/network/hooks/useNetworkSaved.js +1 -34
  144. package/lib/module/network/hooks/useNetworkSelection.js +1 -46
  145. package/lib/module/network/hooks/useOverrideRules.js +1 -32
  146. package/lib/module/network/hooks/useTickEveryMinute.js +1 -11
  147. package/lib/module/network/overrides/applyToFetch.js +1 -72
  148. package/lib/module/network/overrides/applyToXhr.js +2 -446
  149. package/lib/module/network/overrides/engine.js +1 -85
  150. package/lib/module/network/overrides/matchRule.js +1 -75
  151. package/lib/module/network/overrides/overriddenRows.js +1 -0
  152. package/lib/module/network/overrides/overrideRulesStore.js +1 -547
  153. package/lib/module/network/overrides/presets.js +1 -65
  154. package/lib/module/network/overrides/resolveOverride.js +1 -152
  155. package/lib/module/network/overrides/types.js +1 -86
  156. package/lib/module/network/sync/networkBodyResolver.js +1 -34
  157. package/lib/module/network/sync/networkSyncAdapter.js +1 -880
  158. package/lib/module/network/sync/overrideHonesty.release.test.js +1 -35
  159. package/lib/module/network/types/index.js +1 -3
  160. package/lib/module/network/utils/extractOperationName.js +1 -76
  161. package/lib/module/network/utils/filterNetworkEvents.js +1 -92
  162. package/lib/module/network/utils/formatGraphQLVariables.js +1 -213
  163. package/lib/module/network/utils/formatting.js +1 -9
  164. package/lib/module/network/utils/generateCurl.js +2 -67
  165. package/lib/module/network/utils/generateNetworkCopyText.js +37 -162
  166. package/lib/module/network/utils/httpCompletion.js +1 -32
  167. package/lib/module/network/utils/networkEventStore.js +1 -391
  168. package/lib/module/network/utils/networkListener.js +4 -1249
  169. package/lib/module/network/utils/networkSavedStore.js +3 -572
  170. package/lib/module/network/utils/networkSelectionStore.js +1 -188
  171. package/lib/module/network/utils/realNow.js +1 -0
  172. package/lib/module/network/utils/requestId.js +1 -0
  173. package/lib/module/network/utils/resolveRequestUrl.js +1 -0
  174. package/lib/module/network/utils/selectSavedEvents.js +1 -35
  175. package/lib/module/network/utils/startNetworkCapture.js +1 -0
  176. package/lib/module/network/utils/withPinnedFirst.js +1 -28
  177. package/lib/module/preset.js +1 -100
  178. package/lib/typescript/index.d.ts +1 -0
  179. package/lib/typescript/network/overrides/applyToXhr.d.ts +1 -0
  180. package/lib/typescript/network/overrides/engine.d.ts +1 -1
  181. package/lib/typescript/network/overrides/matchRule.d.ts +1 -1
  182. package/lib/typescript/network/overrides/overriddenRows.d.ts +16 -0
  183. package/lib/typescript/network/overrides/resolveOverride.d.ts +2 -2
  184. package/lib/typescript/network/overrides/types.d.ts +9 -0
  185. package/lib/typescript/network/utils/networkListener.d.ts +14 -4
  186. package/lib/typescript/network/utils/networkSavedStore.d.ts +4 -4
  187. package/lib/typescript/network/utils/realNow.d.ts +18 -0
  188. package/lib/typescript/network/utils/requestId.d.ts +2 -0
  189. package/lib/typescript/network/utils/resolveRequestUrl.d.ts +3 -0
  190. package/lib/typescript/network/utils/startNetworkCapture.d.ts +6 -0
  191. package/lib/web/index.mjs +145 -0
  192. package/package.json +32 -10
  193. package/lib/typescript/index.d.ts.map +0 -1
  194. package/lib/typescript/index.web.d.ts.map +0 -1
  195. package/lib/typescript/network/components/DataViewer.web.d.ts.map +0 -1
  196. package/lib/typescript/network/components/NetworkCopyScreen.web.d.ts.map +0 -1
  197. package/lib/typescript/network/components/NetworkCopySettingsView.d.ts.map +0 -1
  198. package/lib/typescript/network/components/NetworkCopySettingsView.web.d.ts.map +0 -1
  199. package/lib/typescript/network/components/NetworkDetailScreen.web.d.ts.map +0 -1
  200. package/lib/typescript/network/components/NetworkDetailStepper.d.ts.map +0 -1
  201. package/lib/typescript/network/components/NetworkDetailStepper.web.d.ts.map +0 -1
  202. package/lib/typescript/network/components/NetworkEventDetailView.d.ts.map +0 -1
  203. package/lib/typescript/network/components/NetworkEventDetailView.web.d.ts.map +0 -1
  204. package/lib/typescript/network/components/NetworkEventItemCompact.d.ts.map +0 -1
  205. package/lib/typescript/network/components/NetworkEventItemCompact.web.d.ts.map +0 -1
  206. package/lib/typescript/network/components/NetworkFilterScreen.web.d.ts.map +0 -1
  207. package/lib/typescript/network/components/NetworkFilterViewV3.d.ts.map +0 -1
  208. package/lib/typescript/network/components/NetworkFilterViewV3.web.d.ts.map +0 -1
  209. package/lib/typescript/network/components/NetworkHeaderLive.d.ts.map +0 -1
  210. package/lib/typescript/network/components/NetworkHeaderLive.web.d.ts.map +0 -1
  211. package/lib/typescript/network/components/NetworkHeaderMenu.d.ts.map +0 -1
  212. package/lib/typescript/network/components/NetworkListScreen.d.ts.map +0 -1
  213. package/lib/typescript/network/components/NetworkListScreen.web.d.ts.map +0 -1
  214. package/lib/typescript/network/components/NetworkModal.d.ts.map +0 -1
  215. package/lib/typescript/network/components/NetworkNumberPrompt.d.ts.map +0 -1
  216. package/lib/typescript/network/components/NetworkNumberPrompt.web.d.ts.map +0 -1
  217. package/lib/typescript/network/components/NetworkOverrideEditor.d.ts.map +0 -1
  218. package/lib/typescript/network/components/NetworkOverrideEditor.web.d.ts.map +0 -1
  219. package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts.map +0 -1
  220. package/lib/typescript/network/components/NetworkOverrideHeaderButton.web.d.ts.map +0 -1
  221. package/lib/typescript/network/components/NetworkOverridesButton.d.ts.map +0 -1
  222. package/lib/typescript/network/components/NetworkOverridesButton.web.d.ts.map +0 -1
  223. package/lib/typescript/network/components/NetworkOverridesScreen.d.ts.map +0 -1
  224. package/lib/typescript/network/components/NetworkOverridesScreen.web.d.ts.map +0 -1
  225. package/lib/typescript/network/components/NetworkSavedScreen.d.ts.map +0 -1
  226. package/lib/typescript/network/components/NetworkSavedScreen.web.d.ts.map +0 -1
  227. package/lib/typescript/network/components/NetworkUpgradeBanner.d.ts.map +0 -1
  228. package/lib/typescript/network/components/response-editor/Explorer.d.ts.map +0 -1
  229. package/lib/typescript/network/components/response-editor/Explorer.web.d.ts.map +0 -1
  230. package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts.map +0 -1
  231. package/lib/typescript/network/components/response-editor/editorContext.d.ts.map +0 -1
  232. package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts.map +0 -1
  233. package/lib/typescript/network/conditions/NetworkConditionsControl.d.ts.map +0 -1
  234. package/lib/typescript/network/conditions/NetworkConditionsControl.test.d.ts.map +0 -1
  235. package/lib/typescript/network/conditions/NetworkConditionsIcon.d.ts.map +0 -1
  236. package/lib/typescript/network/conditions/NetworkFloatingTool.d.ts.map +0 -1
  237. package/lib/typescript/network/conditions/NetworkFloatingTool.test.d.ts.map +0 -1
  238. package/lib/typescript/network/conditions/store.d.ts.map +0 -1
  239. package/lib/typescript/network/conditions/wait.d.ts.map +0 -1
  240. package/lib/typescript/network/conditions/xhr.d.ts.map +0 -1
  241. package/lib/typescript/network/hooks/useLiveNetworkEvent.d.ts.map +0 -1
  242. package/lib/typescript/network/hooks/useNetworkBadgeCounts.d.ts.map +0 -1
  243. package/lib/typescript/network/hooks/useNetworkEventList.d.ts.map +0 -1
  244. package/lib/typescript/network/hooks/useNetworkEvents.d.ts.map +0 -1
  245. package/lib/typescript/network/hooks/useNetworkHasMatches.d.ts.map +0 -1
  246. package/lib/typescript/network/hooks/useNetworkSaved.d.ts.map +0 -1
  247. package/lib/typescript/network/hooks/useNetworkSelection.d.ts.map +0 -1
  248. package/lib/typescript/network/hooks/useOverrideRules.d.ts.map +0 -1
  249. package/lib/typescript/network/hooks/useTickEveryMinute.d.ts.map +0 -1
  250. package/lib/typescript/network/overrides/applyToFetch.d.ts.map +0 -1
  251. package/lib/typescript/network/overrides/applyToXhr.d.ts.map +0 -1
  252. package/lib/typescript/network/overrides/engine.d.ts.map +0 -1
  253. package/lib/typescript/network/overrides/matchRule.d.ts.map +0 -1
  254. package/lib/typescript/network/overrides/overrideRulesStore.d.ts.map +0 -1
  255. package/lib/typescript/network/overrides/presets.d.ts.map +0 -1
  256. package/lib/typescript/network/overrides/resolveOverride.d.ts.map +0 -1
  257. package/lib/typescript/network/overrides/types.d.ts.map +0 -1
  258. package/lib/typescript/network/sync/networkBodyResolver.d.ts.map +0 -1
  259. package/lib/typescript/network/sync/networkSyncAdapter.d.ts.map +0 -1
  260. package/lib/typescript/network/sync/overrideHonesty.release.test.d.ts.map +0 -1
  261. package/lib/typescript/network/types/index.d.ts.map +0 -1
  262. package/lib/typescript/network/utils/extractOperationName.d.ts.map +0 -1
  263. package/lib/typescript/network/utils/filterNetworkEvents.d.ts.map +0 -1
  264. package/lib/typescript/network/utils/formatGraphQLVariables.d.ts.map +0 -1
  265. package/lib/typescript/network/utils/formatting.d.ts.map +0 -1
  266. package/lib/typescript/network/utils/generateCurl.d.ts.map +0 -1
  267. package/lib/typescript/network/utils/generateNetworkCopyText.d.ts.map +0 -1
  268. package/lib/typescript/network/utils/httpCompletion.d.ts.map +0 -1
  269. package/lib/typescript/network/utils/networkEventStore.d.ts.map +0 -1
  270. package/lib/typescript/network/utils/networkListener.d.ts.map +0 -1
  271. package/lib/typescript/network/utils/networkSavedStore.d.ts.map +0 -1
  272. package/lib/typescript/network/utils/networkSelectionStore.d.ts.map +0 -1
  273. package/lib/typescript/network/utils/selectSavedEvents.d.ts.map +0 -1
  274. package/lib/typescript/network/utils/withPinnedFirst.d.ts.map +0 -1
  275. package/lib/typescript/preset.d.ts.map +0 -1
@@ -1,882 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.networkSyncAdapter = exports.SNAPSHOT_HEADER_VALUE_LIMIT = exports.SNAPSHOT_EVENTS_BUDGET = exports.SNAPSHOT_BODY_INLINE_LIMIT = void 0;
7
- var _store = require("../conditions/store");
8
- var _networkEventStore = require("../utils/networkEventStore");
9
- var _networkSavedStore = require("../utils/networkSavedStore");
10
- var _overrideRulesStore = require("../overrides/overrideRulesStore");
11
- var _presets = require("../overrides/presets");
12
- var _engine = require("../overrides/engine");
13
- var _networkListener = require("../utils/networkListener");
14
- var _sharedUi = require("@buoy-gg/shared-ui");
15
- /**
16
- * Request/response bodies larger than this are NOT streamed in the list
17
- * snapshot. Prefer the cached size proxy already on the event (free); if that
18
- * field is missing or wrong (0 for a fat/cyclic body), fall back to an
19
- * O(limit) walk. Stripped bodies come back via `getEventBody` on detail open.
20
- */
21
- const SNAPSHOT_BODY_INLINE_LIMIT = exports.SNAPSHOT_BODY_INLINE_LIMIT = 16 * 1024;
22
-
23
- /**
24
- * Total inline budget for one snapshot's event list, held under the emit
25
- * layer's 2MB so a snapshot is never DROPPED (a drop leaves the whole panel
26
- * stale). Per-field caps alone don't get there: 500 requests with 9KB
27
- * responses are all individually legal and still add up to ~4.7MB. Newest
28
- * events keep their bodies inline (that's what a developer is looking at);
29
- * once the budget is spent, older events degrade to metadata + fetch-on-demand.
30
- */
31
- const SNAPSHOT_EVENTS_BUDGET = exports.SNAPSHOT_EVENTS_BUDGET = 1.25 * 1024 * 1024;
32
- function shouldStripBody(data, reportedSize) {
33
- if (data === undefined) return false;
34
- // The cached size proxy already on the event is free when it's right; the
35
- // walk is the fallback for when it's missing or wrong (0 for a fat body).
36
- if ((reportedSize ?? 0) > SNAPSHOT_BODY_INLINE_LIMIT) return true;
37
- return (0, _sharedUi.isOverWireBudget)(data, SNAPSHOT_BODY_INLINE_LIMIT);
38
- }
39
-
40
- /** One event's wire form plus its measured cost, so the budget pass is free. */
41
-
42
- /**
43
- * Per-event wire cache. `networkEventStore` never mutates an event in place —
44
- * a response/override update replaces the object — so keying on identity is
45
- * correct and self-invalidating, and a completed request is converted once
46
- * instead of on all ~5 snapshots per second for as long as it stays in the
47
- * list. This is what keeps the guards off the hot path.
48
- */
49
- const wireCache = new WeakMap();
50
- const strippedCache = new WeakMap();
51
-
52
- /** Per-field guards: oversized bodies out, heavy headers/variables slimmed. */
53
- function toWireEvent(event) {
54
- const cached = wireCache.get(event);
55
- if (cached) return cached;
56
- let entry;
57
- try {
58
- entry = buildWireEvent(event);
59
- } catch {
60
- // A body with a throwing getter or `toJSON` can blow up the size walk
61
- // itself. Degrading this ONE event to metadata beats letting getSnapshot
62
- // throw, which would take the whole panel down with it.
63
- entry = buildMetadataOnly(event);
64
- }
65
- wireCache.set(event, entry);
66
- return entry;
67
- }
68
- function buildMetadataOnly(event) {
69
- const stripped = {
70
- ...event,
71
- requestData: undefined,
72
- responseData: undefined,
73
- graphqlVariables: undefined,
74
- requestBodyOmitted: event.requestData !== undefined ? true : undefined,
75
- responseBodyOmitted: event.responseData !== undefined ? true : undefined
76
- };
77
- // The payload fields are gone, so measuring this is safe even when measuring
78
- // the original blew up. Fall back to a nominal cost only if even THIS throws
79
- // (a hostile getter on the event itself rather than on its body).
80
- let bytes = 1024;
81
- try {
82
- bytes = (0, _sharedUi.approxJsonSize)(stripped, SNAPSHOT_EVENTS_BUDGET).bytes;
83
- } catch {
84
- /* keep the nominal estimate */
85
- }
86
- return {
87
- event: stripped,
88
- bytes
89
- };
90
- }
91
- function buildWireEvent(event) {
92
- const stripRequest = shouldStripBody(event.requestData, event.requestSize);
93
- const stripResponse = shouldStripBody(event.responseData, event.responseSize);
94
- const graphqlVariables = toWireGraphqlVariables(event.graphqlVariables);
95
- const requestHeaders = toWireHeaders(event.requestHeaders);
96
- const responseHeaders = toWireHeaders(event.responseHeaders);
97
- const changed = stripRequest || stripResponse || graphqlVariables !== event.graphqlVariables || requestHeaders !== event.requestHeaders || responseHeaders !== event.responseHeaders;
98
- let wire = event;
99
- if (changed) {
100
- // `undefined` keys are omitted by JSON serialization, so dropping the data
101
- // shrinks the wire payload. Sizes stay HONEST — the explicit
102
- // request/responseBodyOmitted flags are what tell the dashboard to fetch,
103
- // matching `OverrideRule.bodyOmitted`. Full values come from `getEventBody`.
104
- wire = {
105
- ...event
106
- };
107
- if (stripRequest) {
108
- wire.requestData = undefined;
109
- wire.requestBodyOmitted = true;
110
- }
111
- if (stripResponse) {
112
- wire.responseData = undefined;
113
- wire.responseBodyOmitted = true;
114
- }
115
- if (graphqlVariables !== event.graphqlVariables) {
116
- wire.graphqlVariables = graphqlVariables;
117
- }
118
- if (requestHeaders !== event.requestHeaders) {
119
- wire.requestHeaders = requestHeaders;
120
- wire.headersOmitted = true;
121
- }
122
- if (responseHeaders !== event.responseHeaders) {
123
- wire.responseHeaders = responseHeaders;
124
- wire.headersOmitted = true;
125
- }
126
- }
127
- return {
128
- event: wire,
129
- bytes: (0, _sharedUi.approxJsonSize)(wire, SNAPSHOT_EVENTS_BUDGET).bytes
130
- };
131
- }
132
-
133
- /**
134
- * Metadata-only form, used for the tail of the list once the snapshot budget
135
- * is spent. Method/url/status/timing all stay — only the payloads go.
136
- */
137
- function toStrippedEvent(event) {
138
- const cached = strippedCache.get(event);
139
- if (cached) return cached;
140
- const {
141
- event: wire
142
- } = toWireEvent(event);
143
- const stripped = {
144
- ...wire
145
- };
146
- if (stripped.requestData !== undefined) {
147
- stripped.requestData = undefined;
148
- stripped.requestBodyOmitted = true;
149
- }
150
- if (stripped.responseData !== undefined) {
151
- stripped.responseData = undefined;
152
- stripped.responseBodyOmitted = true;
153
- }
154
- if (stripped.graphqlVariables !== undefined) {
155
- stripped.graphqlVariables = toWireGraphqlVariables(stripped.graphqlVariables, /* force */true);
156
- }
157
- const entry = {
158
- event: stripped,
159
- bytes: (0, _sharedUi.approxJsonSize)(stripped, SNAPSHOT_EVENTS_BUDGET).bytes
160
- };
161
- strippedCache.set(event, entry);
162
- return entry;
163
- }
164
-
165
- /**
166
- * Spend the snapshot budget newest-first. The store keeps events newest-first
167
- * already, so this hands the developer full detail on what they are actually
168
- * looking at and degrades the tail rather than dropping the whole panel.
169
- */
170
- function fitEventsToBudget(events) {
171
- const out = new Array(events.length);
172
- let spent = 0;
173
- for (let i = 0; i < events.length; i++) {
174
- const full = toWireEvent(events[i]);
175
- if (spent + full.bytes <= SNAPSHOT_EVENTS_BUDGET) {
176
- out[i] = full.event;
177
- spent += full.bytes;
178
- } else {
179
- const lean = toStrippedEvent(events[i]);
180
- out[i] = lean.event;
181
- spent += lean.bytes;
182
- }
183
- }
184
- return out;
185
- }
186
-
187
- /**
188
- * GraphQL variables are copied off `request.data.variables` onto their own
189
- * field for the list subtitle (`GetPokemon › Sandshrew`). Capping requestData
190
- * still left that copy on the wire. Keep short primitives for the subtitle;
191
- * drop nested/fat values (file uploads, base64). Full variables stay in
192
- * `requestData` on-device and come back via `getEventBody`.
193
- */
194
- function toWireGraphqlVariables(vars, force = false) {
195
- if (!vars) return vars;
196
- if (!force && !shouldStripBody(vars, undefined)) return vars;
197
- const slim = {};
198
- for (const [key, value] of Object.entries(vars)) {
199
- if (typeof value === "string" && value.length <= 64) slim[key] = value;else if (typeof value === "number" || typeof value === "boolean") {
200
- slim[key] = value;
201
- }
202
- }
203
- return Object.keys(slim).length > 0 ? slim : undefined;
204
- }
205
-
206
- /**
207
- * Header values (Cookie, Authorization, custom JSON) still rode every
208
- * snapshot after bodies were stripped. 500 events × a 4KB session cookie
209
- * is a 2MB drop of the whole Network panel. Keep short values inline
210
- * (content-type, accept); truncate the rest. Full maps stay on-device
211
- * and come back via `getEventBody`.
212
- *
213
- * Returns the SAME object when nothing was truncated: callers use identity to
214
- * decide whether anything was omitted, so a fresh `{}` here would flag every
215
- * header-less event as truncated (and defeat the no-copy fast path).
216
- */
217
- const SNAPSHOT_HEADER_VALUE_LIMIT = exports.SNAPSHOT_HEADER_VALUE_LIMIT = 64;
218
- function toWireHeaders(headers) {
219
- if (!headers) return headers;
220
- let changed = false;
221
- const slim = {};
222
- for (const [key, value] of Object.entries(headers)) {
223
- if (typeof value !== "string") continue;
224
- if (value.length <= SNAPSHOT_HEADER_VALUE_LIMIT) {
225
- slim[key] = value;
226
- } else {
227
- slim[key] = `${value.slice(0, SNAPSHOT_HEADER_VALUE_LIMIT)}… [${value.length - SNAPSHOT_HEADER_VALUE_LIMIT} more]`;
228
- changed = true;
229
- }
230
- }
231
- return changed ? slim : headers;
232
- }
233
-
234
- /**
235
- * Drop oversized rule bodies from the snapshot, flagging what was dropped.
236
- *
237
- * Same limit and same reasoning as `stripLargeBodies` above — and the same
238
- * hazard, only worse: an override body is authored once and then rides EVERY
239
- * snapshot for as long as the rule exists, whereas an event ages out of the
240
- * list. `draftFromEvent` seeds a rule with the real response, so 500KB is an
241
- * ordinary size here, not a pathological one.
242
- */
243
- const stripLargeRuleBodies = state => {
244
- let changed = false;
245
- const rules = state.rules.map(rule => {
246
- if (!rule.body || rule.body.length <= SNAPSHOT_BODY_INLINE_LIMIT) {
247
- return rule;
248
- }
249
- changed = true;
250
- return {
251
- ...rule,
252
- body: undefined,
253
- bodyOmitted: true
254
- };
255
- });
256
- // Identity is preserved when nothing was stripped: the desktop mirror feeds
257
- // this straight into a `useEffect` dependency, and a fresh object every
258
- // snapshot would re-run it several times a second.
259
- return changed ? {
260
- ...state,
261
- rules
262
- } : state;
263
- };
264
- const resolveEvent = id => _networkEventStore.networkEventStore.getEventById(id) ?? _networkSavedStore.networkSavedStore.getEventById(id);
265
- const readId = params => params && typeof params === "object" ? params.id : undefined;
266
- const readBool = (params, key) => !!(params && typeof params === "object" && params[key]);
267
-
268
- /**
269
- * Stamp an override write receipt with whether the rule can actually fire.
270
- *
271
- * Omitted entirely when overrides work, so a dev build's receipts are
272
- * unchanged and no existing consumer sees a new field it has to reason about.
273
- * Present only when the answer is "saved, but inert" — which is exactly when a
274
- * caller relaying success to a person would otherwise be wrong.
275
- */
276
- const inactiveStamp = () => (0, _engine.overridesCanApply)() ? {} : {
277
- active: false,
278
- inactiveReason: _engine.OVERRIDES_INACTIVE_REASON
279
- };
280
- const VALID_KINDS = ["respond", "fail", "delay"];
281
-
282
- /**
283
- * Turn an override rule sent over the wire into a draft the store will accept.
284
- *
285
- * Validated rather than trusted: these params arrive from the dashboard and
286
- * from MCP clients, and a malformed rule doesn't just fail — it gets PERSISTED
287
- * and then re-applied to real traffic on every launch. `urlPattern` is the one
288
- * field with no sane default, so its absence rejects the whole call.
289
- */
290
- function readRuleDraft(params,
291
- /**
292
- * Prefill from a captured request, as the UI's Override button does. Any
293
- * field the caller sent explicitly still wins over it.
294
- */
295
- base) {
296
- if (!params || typeof params !== "object") return null;
297
- const raw = params.rule ?? params;
298
- if (!raw || typeof raw !== "object") return null;
299
- const rule = raw;
300
- const urlPattern = typeof rule.urlPattern === "string" && rule.urlPattern.trim() ? rule.urlPattern.trim() : base?.urlPattern ?? "";
301
- if (!urlPattern) return null;
302
- const kind = VALID_KINDS.includes(rule.kind) ? rule.kind : base?.kind ?? "respond";
303
- return {
304
- id: typeof rule.id === "string" ? rule.id : undefined,
305
- enabled: rule.enabled !== false,
306
- name: typeof rule.name === "string" ? rule.name : base?.name,
307
- urlPattern,
308
- methods: Array.isArray(rule.methods) ? rule.methods.filter(m => typeof m === "string").map(m => m.toUpperCase()) : base?.methods,
309
- kind,
310
- status: typeof rule.status === "number" ? rule.status : base?.status,
311
- statusText: typeof rule.statusText === "string" ? rule.statusText : base?.statusText,
312
- headers: rule.headers && typeof rule.headers === "object" ? rule.headers : base?.headers,
313
- // Objects are accepted and serialized so a caller can send JSON directly
314
- // instead of pre-stringifying it, which is the mistake everyone makes once.
315
- body: patchedBody(rule, base),
316
- failKind: rule.failKind === "timeout" ? "timeout" : undefined,
317
- delayMs: typeof rule.delayMs === "number" ? rule.delayMs : undefined,
318
- times: typeof rule.times === "number" ? rule.times : null,
319
- alternate: rule.alternate === true
320
- };
321
- }
322
- const isPlainObject = v => !!v && typeof v === "object" && !Array.isArray(v);
323
- /**
324
- * Objects merge key by key; arrays and primitives are replaced. Collects two
325
- * dangers instead of writing them: `shrunk` (a non-empty array shorter than
326
- * the one it replaces) and `breaks` (an array/object field overwritten by null
327
- * or a primitive — the shape the app renders, changed out from under it). The
328
- * handler refuses either unless forced.
329
- *
330
- * This stays local while the typed-edit RULE is shared: it is the merge itself,
331
- * not the check, and it reports network-specific dangers the store surfaces do
332
- * not have. `shapeKind` comes from the shared module so both agree on what
333
- * counts as an array.
334
- */
335
- function deepMerge(base, patch, path = "", issues = {
336
- shrunk: [],
337
- breaks: []
338
- }) {
339
- if (Array.isArray(base) && Array.isArray(patch)) {
340
- if (patch.length > 0 && patch.length < base.length) {
341
- issues.shrunk.push({
342
- path: path || "(root)",
343
- have: base.length,
344
- sent: patch.length
345
- });
346
- }
347
- return patch;
348
- }
349
- if (!isPlainObject(base) || !isPlainObject(patch)) return patch;
350
- const out = {
351
- ...base
352
- };
353
- for (const [k, v] of Object.entries(patch)) {
354
- const p = path ? `${path}.${k}` : k;
355
- if (k in base) {
356
- const from = (0, _sharedUi.shapeKind)(base[k]);
357
- const to = (0, _sharedUi.shapeKind)(v);
358
- if ((from === "array" || from === "object") && from !== to) {
359
- issues.breaks.push({
360
- path: p,
361
- from,
362
- to
363
- });
364
- }
365
- out[k] = deepMerge(base[k], v, p, issues);
366
- } else {
367
- out[k] = v;
368
- }
369
- }
370
- return out;
371
- }
372
-
373
- /** Typed-edit violations a bodyPatch would cause against the seed body, or []. */
374
- function patchViolations(rule, seed) {
375
- if (rule.body != null || !isPlainObject(rule.bodyPatch) || typeof seed !== "string") return [];
376
- try {
377
- return (0, _sharedUi.typedEditViolations)(JSON.parse(seed), rule.bodyPatch, {
378
- noun: "response body"
379
- });
380
- } catch {
381
- return [];
382
- }
383
- }
384
-
385
- /**
386
- * The rule's body: explicit `body` wins, else `bodyPatch` deep-merged into the
387
- * seeded body (from `fromRequestId`, or the rule being replaced), else the seed.
388
- *
389
- * `bodyPatch` exists for the same reason `setQueryData` has `merge`: a remote
390
- * caller reads the real response through a wire that truncates big payloads,
391
- * edits one field, and pastes the torn object back as `body`. The app then
392
- * renders a response missing half its fields. With a patch the caller sends
393
- * `{ stats: [...] }` and the other 30KB stay exactly as the server sent them.
394
- */
395
- function patchedBody(rule, base) {
396
- if (typeof rule.body === "string") return rule.body;
397
- if (rule.body != null) return JSON.stringify(rule.body, null, 2);
398
- const seed = base?.body ?? (typeof rule.id === "string" ? _overrideRulesStore.overrideRulesStore.getState().rules.find(r => r.id === rule.id)?.body : undefined);
399
- if (isPlainObject(rule.bodyPatch) && typeof seed === "string") {
400
- try {
401
- return JSON.stringify(deepMerge(JSON.parse(seed), rule.bodyPatch), null, 2);
402
- } catch {
403
- return seed;
404
- }
405
- }
406
- return seed;
407
- }
408
-
409
- /**
410
- * Replacing a rule by id inherits every field the caller did not send, so a
411
- * remote driver can flip one thing — `{ id, bodyPatch }`, `{ id, status: 500 }`
412
- * — without re-sending the urlPattern it never had to know.
413
- */
414
- function existingRule(params) {
415
- if (!params || typeof params !== "object") return null;
416
- const raw = params.rule ?? params;
417
- if (!raw || typeof raw !== "object") return null;
418
- const id = raw.id;
419
- if (typeof id !== "string") return null;
420
- const existing = _overrideRulesStore.overrideRulesStore.getState().rules.find(r => r.id === id);
421
- return existing ? {
422
- ...existing
423
- } : null;
424
- }
425
-
426
- /**
427
- * The body a remote surface never received, when it says so.
428
- *
429
- * A dashboard editing a rule whose body was stripped from the snapshot has
430
- * nothing to send back for it. Without this the save would write `body:
431
- * undefined` and silently destroy the payload — the one field a rule exists for.
432
- */
433
- function preservedBody(params) {
434
- if (!params || typeof params !== "object") return null;
435
- const raw = params.rule ?? params;
436
- if (!raw || typeof raw !== "object") return null;
437
- const rule = raw;
438
- if (rule.bodyOmitted !== true || typeof rule.id !== "string") return null;
439
- const existing = _overrideRulesStore.overrideRulesStore.getState().rules.find(candidate => candidate.id === rule.id);
440
- return existing ? {
441
- body: existing.body
442
- } : null;
443
- }
444
-
445
- /**
446
- * Resolve `fromRequestId` into the same draft the UI's Override button builds.
447
- *
448
- * Worth routing through `draftFromEvent` rather than letting a caller paste the
449
- * URL: it drops the query string to `*`, which is the difference between a rule
450
- * that fires and one that sits at 0 hits against a cache-busting client.
451
- */
452
- function baseFromRequest(params) {
453
- if (!params || typeof params !== "object") return null;
454
- const id = params.fromRequestId;
455
- if (typeof id !== "string" || !id) return null;
456
- const event = resolveEvent(id);
457
- return event ? (0, _presets.draftFromEvent)(event) : null;
458
- }
459
-
460
- /**
461
- * Sync adapter for the network tool, consumed by @buoy-gg/external-sync's
462
- * `useExternalSync` (structurally matches its ToolSyncAdapter interface so
463
- * this package doesn't need a dependency on it).
464
- *
465
- * Subscribing starts the network interceptor, so requests are only captured
466
- * while a dashboard is watching the network panel — or while an MCP
467
- * client holds a capture-mode watch (`devtool-watch` with `stream:false`),
468
- * which records without asking the device to push snapshots.
469
- *
470
- * v2: large bodies are stripped from the snapshot and fetched lazily via
471
- * `getEventBody` (see SNAPSHOT_BODY_INLINE_LIMIT).
472
- *
473
- * v3: the payload became an OBJECT — `{ events, saved }` — so pinned/saved
474
- * requests reach the dashboard. They can't ride as flags on the events: a pin
475
- * outlives the event that produced it (that is its whole purpose), so it has
476
- * to be its own list. Dashboards that predate v3 read `payload` as an array;
477
- * `NetworkPanel`/`NetworkInline` accept either shape.
478
- */
479
- const networkSyncAdapter = exports.networkSyncAdapter = {
480
- dispose: () => {
481
- _overrideRulesStore.overrideRulesStore.setEnabled(false);
482
- },
483
- // v5: honest request/responseSize + explicit request/responseBodyOmitted
484
- // flags, and a total snapshot budget so the list degrades instead of the
485
- // whole panel being dropped at the emit layer.
486
- version: 6,
487
- getSnapshot: () => {
488
- // Piggyback the interception health check on the watch loop: while a
489
- // dashboard/MCP watch is open this runs continuously, so a clobbered
490
- // fetch/XHR patch (see networkListener.startListening) heals within one
491
- // snapshot tick instead of staying dead for the session. Two property
492
- // reads when healthy.
493
- _networkEventStore.networkEventStore.ensureInterception();
494
- return {
495
- conditions: {
496
- version: 1,
497
- runtimeId: _store.networkConditionsRuntimeId,
498
- profile: (0, _store.getNetworkCondition)(),
499
- available: (0, _store.conditionsCanApply)()
500
- },
501
- events: fitEventsToBudget(_networkEventStore.networkEventStore.getEvents()),
502
- /**
503
- * Response-override rules live on the DEVICE — that's the only place they
504
- * can run, since a rule is applied inside the app's own XMLHttpRequest.
505
- * Remote surfaces mirror this and forward their edits back as actions.
506
- */
507
- overrides: stripLargeRuleBodies(_overrideRulesStore.overrideRulesStore.getState()),
508
- // Saved snapshots go through the same body strip. They are few (capped in
509
- // the store) but they ride on EVERY snapshot, so a fat one would land in
510
- // the same 200ms loop that the body-stripping exists to protect.
511
- saved: _networkSavedStore.networkSavedStore.getRecords().map(record => ({
512
- ...record,
513
- event: toWireEvent(record.event).event
514
- }))
515
- };
516
- },
517
- subscribe: onChange => {
518
- // Pinning with no traffic in flight still has to reach the dashboard, so
519
- // both stores drive the snapshot.
520
- const unsubscribeEvents = _networkEventStore.networkEventStore.subscribeToEvents(onChange);
521
- const unsubscribeConditions = (0, _store.subscribeNetworkConditions)(onChange);
522
- const unsubscribeSaved = _networkSavedStore.networkSavedStore.subscribe(onChange);
523
- // Same reasoning for rules: editing one with no traffic in flight must
524
- // still reach the dashboard. Subscribing also hydrates the rule list.
525
- const unsubscribeOverrides = _overrideRulesStore.overrideRulesStore.subscribe(onChange);
526
- return () => {
527
- unsubscribeConditions();
528
- unsubscribeEvents();
529
- unsubscribeSaved();
530
- unsubscribeOverrides();
531
- };
532
- },
533
- actions: {
534
- getNetworkConditions: () => ({
535
- runtimeId: _store.networkConditionsRuntimeId,
536
- profile: (0, _store.getNetworkCondition)(),
537
- available: (0, _store.conditionsCanApply)()
538
- }),
539
- setNetworkConditions: params => {
540
- const profile = params && typeof params === "object" ? params.profile : undefined;
541
- return {
542
- runtimeId: _store.networkConditionsRuntimeId,
543
- profile: (0, _store.setNetworkCondition)(profile),
544
- available: (0, _store.conditionsCanApply)()
545
- };
546
- },
547
- clearEvents: () => {
548
- _networkEventStore.networkEventStore.clearEvents();
549
- },
550
- /**
551
- * Return the full (un-stripped) request/response bodies for one event,
552
- * fetched on demand by the dashboard when its detail view opens. Falls
553
- * back to the saved store, which may hold the only remaining copy of a
554
- * request that has since been cleared. Returns null if neither has it.
555
- */
556
- getEventBody: params => {
557
- const id = readId(params);
558
- if (!id) return null;
559
- const event = resolveEvent(id);
560
- if (!event) return null;
561
- return {
562
- // Identity + the override mark ride along so a caller (Ask Buoy's
563
- // receipt, an MCP session) can say WHOSE body this is and whether an
564
- // override rule produced it — a mocked response rendered as "live"
565
- // is the fabrication problem wearing a chrome suit.
566
- url: event.url ?? null,
567
- method: event.method ?? null,
568
- status: event.status ?? null,
569
- override: event.override ?? null,
570
- requestData: event.requestData ?? null,
571
- responseData: event.responseData ?? null,
572
- requestHeaders: event.requestHeaders ?? null,
573
- responseHeaders: event.responseHeaders ?? null
574
- };
575
- },
576
- /** Pin/unpin a request from the dashboard. */
577
- setPinned: params => {
578
- const id = readId(params);
579
- if (!id) return null;
580
- const event = resolveEvent(id);
581
- if (!event) return null;
582
- const wanted = readBool(params, "pinned");
583
- // `flagsForEventId`, not `isPinned` — the id may be a `saved:<key>`
584
- // snapshot, which the live-id Sets deliberately don't carry.
585
- const current = (0, _networkSavedStore.flagsForEventId)(_networkSavedStore.networkSavedStore.getState(), id).pinned;
586
- if (current === wanted) return {
587
- ok: true
588
- };
589
- return _networkSavedStore.networkSavedStore.togglePin(event);
590
- },
591
- /** Save/unsave a request from the dashboard. */
592
- setSaved: params => {
593
- const id = readId(params);
594
- if (!id) return null;
595
- const event = resolveEvent(id);
596
- if (!event) return null;
597
- const wanted = readBool(params, "saved");
598
- const current = (0, _networkSavedStore.flagsForEventId)(_networkSavedStore.networkSavedStore.getState(), id).saved;
599
- if (current === wanted) return {
600
- ok: true
601
- };
602
- return _networkSavedStore.networkSavedStore.toggleSave(event);
603
- },
604
- /** Drop one pinned/saved record by its stable key. */
605
- removeSavedRecord: params => {
606
- const key = params && typeof params === "object" ? params.key : undefined;
607
- if (!key) return null;
608
- _networkSavedStore.networkSavedStore.remove(key);
609
- return {
610
- ok: true
611
- };
612
- },
613
- clearSavedRequests: () => {
614
- _networkSavedStore.networkSavedStore.clearSaved();
615
- return {
616
- ok: true
617
- };
618
- },
619
- clearPinnedRequests: () => {
620
- _networkSavedStore.networkSavedStore.clearPinned();
621
- return {
622
- ok: true
623
- };
624
- },
625
- // =========================================================================
626
- // RESPONSE OVERRIDES
627
- // =========================================================================
628
-
629
- /** Master switch — turns every rule off without losing any of them. */
630
- setOverridesEnabled: params => {
631
- _overrideRulesStore.overrideRulesStore.setEnabled(readBool(params, "enabled"));
632
- return {
633
- ok: true,
634
- enabled: _overrideRulesStore.overrideRulesStore.getState().enabled,
635
- // `active` is the difference between "we saved it" and "it is doing
636
- // something". A remote driver reads this and tells the user the truth.
637
- ...inactiveStamp()
638
- };
639
- },
640
- /** Create a rule, or replace one by id. */
641
- upsertOverrideRule: params => {
642
- const base = baseFromRequest(params) ?? preservedBody(params) ?? existingRule(params);
643
- const rawRule = params?.rule ?? params;
644
- // `bodyPath` + `bodyValue` are sugar over `bodyPatch`, resolved against the
645
- // real response before anything else looks at the rule — so the keyed
646
- // expansion, the typed-edit guard and the merge below all run on an
647
- // ordinary patch and gain no special cases. This is the same form the
648
- // state tools take; it exists here because a response body is the surface
649
- // where the caller is LEAST likely to have seen the shape (it read the
650
- // body over a wire that truncates at 24,000 characters), and therefore
651
- // most likely to get the nesting wrong.
652
- if (rawRule && typeof rawRule.bodyPath === "string" && rawRule.body == null) {
653
- const seed = base?.body ?? (typeof rawRule.id === "string" ? _overrideRulesStore.overrideRulesStore.getState().rules.find(r => r.id === rawRule.id)?.body : undefined);
654
- if (typeof seed !== "string") {
655
- return {
656
- ok: false,
657
- error: "bodyPath needs something to patch: send fromRequestId (the captured request whose real response it addresses) or the id of an existing rule."
658
- };
659
- }
660
- if (rawRule.bodyValue === undefined) {
661
- return {
662
- ok: false,
663
- error: `Refused: sent \`bodyPath\` without \`bodyValue\`. Say what to set "${rawRule.bodyPath}" to.`
664
- };
665
- }
666
- let parsed;
667
- try {
668
- parsed = JSON.parse(seed);
669
- } catch {
670
- return {
671
- ok: false,
672
- error: "The captured response body is not JSON, so it cannot be addressed by path. Send a whole `body` instead."
673
- };
674
- }
675
- const built = (0, _sharedUi.patchFromPath)(parsed, rawRule.bodyPath, rawRule.bodyValue);
676
- if (!built.ok) return {
677
- ok: false,
678
- error: `Refused: ${built.error}`
679
- };
680
- rawRule.bodyPatch = built.patch;
681
- delete rawRule.bodyPath;
682
- delete rawRule.bodyValue;
683
- }
684
- if (rawRule && isPlainObject(rawRule.bodyPatch) && rawRule.body == null) {
685
- const seed = base?.body ?? (typeof rawRule.id === "string" ? _overrideRulesStore.overrideRulesStore.getState().rules.find(r => r.id === rawRule.id)?.body : undefined);
686
- if (typeof seed !== "string") {
687
- return {
688
- ok: false,
689
- error: "bodyPatch needs something to patch: send fromRequestId (the captured request whose real response the patch is merged into) or the id of an existing rule."
690
- };
691
- }
692
- if (rawRule.force !== true) {
693
- // Address list items in the real response by their own id rather than
694
- // resending the array: {results:{pikachu:{name:"test123"}}}. Expanded
695
- // against the seed BEFORE the guard and before the merge, so the
696
- // typed-edit rule still holds over the result. This is the only form
697
- // that is correct when the caller read the response through a wire
698
- // that truncated it — see packages/shared/src/sync/keyedArrays.ts.
699
- let keyedError;
700
- try {
701
- const expanded = (0, _sharedUi.expandKeyedArrays)(JSON.parse(seed), rawRule.bodyPatch);
702
- keyedError = expanded.error;
703
- if (expanded.notes.length) rawRule.bodyPatch = expanded.patch;
704
- } catch {
705
- /* a non-JSON seed has no lists to address; leave the patch alone */
706
- }
707
- // See keyedArrays.ts: an added item whose id disagrees with the key
708
- // it was sent under is ambiguous, and only this layer can say so.
709
- if (keyedError) {
710
- return {
711
- ok: false,
712
- error: `Refused: ${keyedError}`
713
- };
714
- }
715
- const violations = patchViolations(rawRule, seed);
716
- if (violations.length > 0) {
717
- return {
718
- ok: false,
719
- error: (0, _sharedUi.refusalText)(violations, "response body", (0, _sharedUi.suggestedPatch)(rawRule.bodyPatch, violations)),
720
- violations
721
- };
722
- }
723
- }
724
- }
725
- const draft = readRuleDraft(params, base);
726
- if (!draft) {
727
- const wanted = params?.fromRequestId;
728
- return {
729
- ok: false,
730
- error: wanted ? `No captured request \`${wanted}\` — it may have been cleared. Send a urlPattern instead.` : "A rule needs a non-empty urlPattern."
731
- };
732
- }
733
- const rule = _overrideRulesStore.overrideRulesStore.upsertRule(draft);
734
- if (!rule) return {
735
- ok: false,
736
- error: "Override rule limit reached."
737
- };
738
- // A rule pushed from a remote surface is meant to take effect now;
739
- // leaving it dark under an OFF master switch reads as a silent failure.
740
- if (rule.enabled) _overrideRulesStore.overrideRulesStore.setEnabled(true);
741
- // A RECEIPT, not the rule. `fromRequestId` seeds the real response as the
742
- // body, so echoing the whole rule sent 380KB back down the socket for a
743
- // Pokémon payload — and no caller reads it: the desktop mirror gets the
744
- // rule from the next snapshot, and MCP only needs the id to report and
745
- // remove it.
746
- return {
747
- ok: true,
748
- rule: {
749
- id: rule.id,
750
- urlPattern: rule.urlPattern,
751
- enabled: rule.enabled,
752
- kind: rule.kind,
753
- status: rule.status,
754
- times: rule.times,
755
- bodySize: rule.body ? rule.body.length : 0
756
- },
757
- // A rule with no budget overrides EVERY matching request until someone
758
- // deletes it, and that is rarely what a one-off ask meant. Measured on
759
- // `api-sim/next-call-fails-once` ("just the next one, then let it work
760
- // again"): ten of fourteen attempts left the budget off and got a rule
761
- // that never expires. Saying so is not a nag — it is the difference
762
- // between a caller that adds `times` on its next turn and one that walks
763
- // away leaving the app permanently broken.
764
- ...(rule.times === undefined || rule.times === null ? {
765
- lingers: `This rule has no \`times\` budget, so it overrides EVERY matching request until it is disabled or deleted (id \`${rule.id}\`). If you meant only the next one, set times:1.`
766
- } : {}),
767
- ...inactiveStamp()
768
- };
769
- },
770
- setOverrideRuleEnabled: params => {
771
- const id = readId(params);
772
- if (!id) return {
773
- ok: false,
774
- error: "Missing rule id."
775
- };
776
- _overrideRulesStore.overrideRulesStore.setRuleEnabled(id, readBool(params, "enabled"));
777
- return {
778
- ok: true,
779
- ...inactiveStamp()
780
- };
781
- },
782
- deleteOverrideRule: params => {
783
- const id = readId(params);
784
- if (!id) return {
785
- ok: false,
786
- error: "Missing rule id."
787
- };
788
- _overrideRulesStore.overrideRulesStore.removeRule(id);
789
- return {
790
- ok: true
791
- };
792
- },
793
- clearOverrideRules: () => {
794
- _overrideRulesStore.overrideRulesStore.clearRules();
795
- return {
796
- ok: true
797
- };
798
- },
799
- /** Read the rules back — hit counts included, which the snapshot coalesces. */
800
- listOverrideRules: () => _overrideRulesStore.overrideRulesStore.getState(),
801
- /**
802
- * The full body of one rule, for the surfaces the snapshot withheld it from
803
- * (see `stripLargeRuleBodies`). Fetched when the user opens the rule, which
804
- * is the only moment it's needed.
805
- */
806
- getOverrideRuleBody: params => {
807
- const id = readId(params);
808
- if (!id) return null;
809
- // `getState().rules`, not `getRules()` — the latter reports nothing while
810
- // the master switch is off, and a rule is perfectly editable then.
811
- const rule = _overrideRulesStore.overrideRulesStore.getState().rules.find(candidate => candidate.id === id);
812
- if (!rule) return null;
813
- return {
814
- body: rule.body ?? null
815
- };
816
- },
817
- /** Why isn't my rule firing? Reports the engine's own view of the world. */
818
- /**
819
- * Is the device actually recording right now, and why not?
820
- *
821
- * The honest answer to an empty request list. Without this a caller can
822
- * only guess, and the plausible guesses ("interception is broken on this
823
- * runtime") are all wrong — the usual answer is simply that nothing is
824
- * holding capture open.
825
- */
826
- getCaptureStatus: () => {
827
- // RECORDING is what the caller actually wants to know, and it is driven
828
- // by the store's subscriber count — not by whether the interceptor is
829
- // installed. Those genuinely differ: an enabled override rule pins the
830
- // interceptor (`overrideRulesStore.syncKeepAlive`) without anything
831
- // writing to the event store, so reporting `isNetworkListening()` as
832
- // "capturing" would answer "yes" to a device recording nothing. That is
833
- // the same species of misleading answer this action exists to replace.
834
- const subscribers = _networkEventStore.networkEventStore.getSubscriberCounts().total;
835
-
836
- // `isNetworkListening()` lazily CONSTRUCTS the listener, which reaches
837
- // for XMLHttpRequest — absent in Node and in any headless host. A
838
- // diagnostic that throws is worse than no diagnostic, so probe
839
- // defensively and report what we do know either way.
840
- let interceptorInstalled = null;
841
- let listenerCount = null;
842
- try {
843
- interceptorInstalled = (0, _networkListener.isNetworkListening)();
844
- listenerCount = (0, _networkListener.getNetworkListenerCount)();
845
- } catch {
846
- /* no interceptable runtime here */
847
- }
848
- // `interceptorInstalled` is the listener's own flag; `interceptorLive`
849
- // is whether the interceptors are actually reachable through the global
850
- // chain. installed:true + live:false = something re-assigned fetch/XHR
851
- // over the interceptor (it self-heals on the next subscribe/snapshot —
852
- // see ensureInterception).
853
- let interceptorLive = null;
854
- try {
855
- interceptorLive = (0, _networkListener.isNetworkInterceptionLive)();
856
- } catch {
857
- /* no interceptable runtime here */
858
- }
859
- return {
860
- capturing: subscribers > 0,
861
- subscribers,
862
- interceptorInstalled,
863
- interceptorLive,
864
- listenerCount,
865
- eventCount: _networkEventStore.networkEventStore.getEvents().length
866
- };
867
- },
868
- debugOverrides: params => {
869
- const url = (params && typeof params === "object" ? params.url : undefined) ?? "https://example.com/";
870
- return {
871
- interceptorInstalled: (0, _networkListener.isNetworkListening)(),
872
- listenerCount: (0, _networkListener.getNetworkListenerCount)(),
873
- engine: (0, _engine.inspectEngine)(url, "GET"),
874
- store: {
875
- enabled: _overrideRulesStore.overrideRulesStore.getState().enabled,
876
- ruleCount: _overrideRulesStore.overrideRulesStore.getState().rules.length,
877
- rulesVisibleToEngine: _overrideRulesStore.overrideRulesStore.getRules().length
878
- }
879
- };
880
- }
881
- }
882
- };
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.networkSyncAdapter=exports.SNAPSHOT_HEADER_VALUE_LIMIT=exports.SNAPSHOT_EVENTS_BUDGET=exports.SNAPSHOT_BODY_INLINE_LIMIT=void 0;var _store=require("../conditions/store");var _networkEventStore=require("../utils/networkEventStore");var _networkSavedStore=require("../utils/networkSavedStore");var _overrideRulesStore=require("../overrides/overrideRulesStore");var _presets=require("../overrides/presets");var _engine=require("../overrides/engine");var _networkListener=require("../utils/networkListener");var _sharedUi=require("@buoy-gg/shared-ui");const SNAPSHOT_BODY_INLINE_LIMIT=exports.SNAPSHOT_BODY_INLINE_LIMIT=16*1024;const SNAPSHOT_EVENTS_BUDGET=exports.SNAPSHOT_EVENTS_BUDGET=1.25*1024*1024;function shouldStripBody(e,t){if(e===void 0)return false;if((t??0)>SNAPSHOT_BODY_INLINE_LIMIT)return true;return(0,_sharedUi.isOverWireBudget)(e,SNAPSHOT_BODY_INLINE_LIMIT)}const wireCache=new WeakMap;const strippedCache=new WeakMap;function toWireEvent(e){const t=wireCache.get(e);if(t)return t;let r;try{r=buildWireEvent(e)}catch{r=buildMetadataOnly(e)}wireCache.set(e,r);return r}function buildMetadataOnly(e){const t={...e,requestData:void 0,responseData:void 0,graphqlVariables:void 0,requestBodyOmitted:e.requestData!==void 0?true:void 0,responseBodyOmitted:e.responseData!==void 0?true:void 0};let r=1024;try{r=(0,_sharedUi.approxJsonSize)(t,SNAPSHOT_EVENTS_BUDGET).bytes}catch{}return{event:t,bytes:r}}function buildWireEvent(e){const t=shouldStripBody(e.requestData,e.requestSize);const r=shouldStripBody(e.responseData,e.responseSize);const n=toWireGraphqlVariables(e.graphqlVariables);const o=toWireHeaders(e.requestHeaders);const s=toWireHeaders(e.responseHeaders);const d=t||r||n!==e.graphqlVariables||o!==e.requestHeaders||s!==e.responseHeaders;let i=e;if(d){i={...e};if(t){i.requestData=void 0;i.requestBodyOmitted=true}if(r){i.responseData=void 0;i.responseBodyOmitted=true}if(n!==e.graphqlVariables){i.graphqlVariables=n}if(o!==e.requestHeaders){i.requestHeaders=o;i.headersOmitted=true}if(s!==e.responseHeaders){i.responseHeaders=s;i.headersOmitted=true}}return{event:i,bytes:(0,_sharedUi.approxJsonSize)(i,SNAPSHOT_EVENTS_BUDGET).bytes}}function toStrippedEvent(e){const t=strippedCache.get(e);if(t)return t;const{event:r}=toWireEvent(e);const n={...r};if(n.requestData!==void 0){n.requestData=void 0;n.requestBodyOmitted=true}if(n.responseData!==void 0){n.responseData=void 0;n.responseBodyOmitted=true}if(n.graphqlVariables!==void 0){n.graphqlVariables=toWireGraphqlVariables(n.graphqlVariables,true)}const o={event:n,bytes:(0,_sharedUi.approxJsonSize)(n,SNAPSHOT_EVENTS_BUDGET).bytes};strippedCache.set(e,o);return o}function fitEventsToBudget(e){const t=new Array(e.length);let r=0;for(let n=0;n<e.length;n++){const o=toWireEvent(e[n]);if(r+o.bytes<=SNAPSHOT_EVENTS_BUDGET){t[n]=o.event;r+=o.bytes}else{const s=toStrippedEvent(e[n]);t[n]=s.event;r+=s.bytes}}return t}function toWireGraphqlVariables(e,t=false){if(!e)return e;if(!t&&!shouldStripBody(e,void 0))return e;const r={};for(const[n,o]of Object.entries(e)){if(typeof o==="string"&&o.length<=64)r[n]=o;else if(typeof o==="number"||typeof o==="boolean"){r[n]=o}}return Object.keys(r).length>0?r:void 0}const SNAPSHOT_HEADER_VALUE_LIMIT=exports.SNAPSHOT_HEADER_VALUE_LIMIT=64;function toWireHeaders(e){if(!e)return e;let t=false;const r={};for(const[n,o]of Object.entries(e)){if(typeof o!=="string")continue;if(o.length<=SNAPSHOT_HEADER_VALUE_LIMIT){r[n]=o}else{r[n]=`${o.slice(0,SNAPSHOT_HEADER_VALUE_LIMIT)}\u2026 [${o.length-SNAPSHOT_HEADER_VALUE_LIMIT} more]`;t=true}}return t?r:e}const stripLargeRuleBodies=e=>{let t=false;const r=e.rules.map(n=>{if(!n.body||n.body.length<=SNAPSHOT_BODY_INLINE_LIMIT){return n}t=true;return{...n,body:void 0,bodyOmitted:true}});return t?{...e,rules:r}:e};const resolveEvent=e=>_networkEventStore.networkEventStore.getEventById(e)??_networkSavedStore.networkSavedStore.getEventById(e);const readId=e=>e&&typeof e==="object"?e.id:void 0;const readBool=(e,t)=>!!(e&&typeof e==="object"&&e[t]);const inactiveStamp=()=>(0,_engine.overridesCanApply)()?{}:{active:false,inactiveReason:_engine.OVERRIDES_INACTIVE_REASON};const VALID_KINDS=["respond","fail","delay"];function readRuleDraft(e,t){if(!e||typeof e!=="object")return null;const r=e.rule??e;if(!r||typeof r!=="object")return null;const n=r;const o=typeof n.urlPattern==="string"&&n.urlPattern.trim()?n.urlPattern.trim():t?.urlPattern??"";if(!o)return null;const s=VALID_KINDS.includes(n.kind)?n.kind:t?.kind??"respond";return{id:typeof n.id==="string"?n.id:void 0,enabled:n.enabled!==false,name:typeof n.name==="string"?n.name:t?.name,urlPattern:o,methods:Array.isArray(n.methods)?n.methods.filter(d=>typeof d==="string").map(d=>d.toUpperCase()):t?.methods,requireHeader:typeof n.requireHeader==="string"&&n.requireHeader.trim()?n.requireHeader.trim():void 0,kind:s,status:typeof n.status==="number"?n.status:t?.status,statusText:typeof n.statusText==="string"?n.statusText:t?.statusText,headers:n.headers&&typeof n.headers==="object"?n.headers:t?.headers,body:patchedBody(n,t),failKind:n.failKind==="timeout"?"timeout":void 0,delayMs:typeof n.delayMs==="number"?n.delayMs:void 0,times:typeof n.times==="number"?n.times:null,alternate:n.alternate===true}}const isPlainObject=e=>!!e&&typeof e==="object"&&!Array.isArray(e);function deepMerge(e,t,r="",n={shrunk:[],breaks:[]}){if(Array.isArray(e)&&Array.isArray(t)){if(t.length>0&&t.length<e.length){n.shrunk.push({path:r||"(root)",have:e.length,sent:t.length})}return t}if(!isPlainObject(e)||!isPlainObject(t))return t;const o={...e};for(const[s,d]of Object.entries(t)){const i=r?`${r}.${s}`:s;if(s in e){const u=(0,_sharedUi.shapeKind)(e[s]);const l=(0,_sharedUi.shapeKind)(d);if((u==="array"||u==="object")&&u!==l){n.breaks.push({path:i,from:u,to:l})}o[s]=deepMerge(e[s],d,i,n)}else{o[s]=d}}return o}function patchViolations(e,t){if(e.body!=null||!isPlainObject(e.bodyPatch)||typeof t!=="string")return[];try{return(0,_sharedUi.typedEditViolations)(JSON.parse(t),e.bodyPatch,{noun:"response body"})}catch{return[]}}function patchedBody(e,t){if(typeof e.body==="string")return e.body;if(e.body!=null)return JSON.stringify(e.body,null,2);const r=t?.body??(typeof e.id==="string"?_overrideRulesStore.overrideRulesStore.getState().rules.find(n=>n.id===e.id)?.body:void 0);if(isPlainObject(e.bodyPatch)&&typeof r==="string"){try{return JSON.stringify(deepMerge(JSON.parse(r),e.bodyPatch),null,2)}catch{return r}}return r}function existingRule(e){if(!e||typeof e!=="object")return null;const t=e.rule??e;if(!t||typeof t!=="object")return null;const r=t.id;if(typeof r!=="string")return null;const n=_overrideRulesStore.overrideRulesStore.getState().rules.find(o=>o.id===r);return n?{...n}:null}function preservedBody(e){if(!e||typeof e!=="object")return null;const t=e.rule??e;if(!t||typeof t!=="object")return null;const r=t;if(r.bodyOmitted!==true||typeof r.id!=="string")return null;const n=_overrideRulesStore.overrideRulesStore.getState().rules.find(o=>o.id===r.id);return n?{body:n.body}:null}function baseFromRequest(e){if(!e||typeof e!=="object")return null;const t=e.fromRequestId;if(typeof t!=="string"||!t)return null;const r=resolveEvent(t);return r?(0,_presets.draftFromEvent)(r):null}const networkSyncAdapter=exports.networkSyncAdapter={dispose:()=>{_overrideRulesStore.overrideRulesStore.setEnabled(false)},version:6,getSnapshot:()=>{_networkEventStore.networkEventStore.ensureInterception();return{conditions:{version:1,runtimeId:_store.networkConditionsRuntimeId,profile:(0,_store.getNetworkCondition)(),available:(0,_store.conditionsCanApply)()},events:fitEventsToBudget(_networkEventStore.networkEventStore.getEvents()),overrides:stripLargeRuleBodies(_overrideRulesStore.overrideRulesStore.getState()),saved:_networkSavedStore.networkSavedStore.getRecords().map(e=>({...e,event:toWireEvent(e.event).event}))}},subscribe:e=>{const t=_networkEventStore.networkEventStore.subscribeToEvents(e);const r=(0,_store.subscribeNetworkConditions)(e);const n=_networkSavedStore.networkSavedStore.subscribe(e);const o=_overrideRulesStore.overrideRulesStore.subscribe(e);return()=>{r();t();n();o()}},actions:{getNetworkConditions:()=>({runtimeId:_store.networkConditionsRuntimeId,profile:(0,_store.getNetworkCondition)(),available:(0,_store.conditionsCanApply)()}),setNetworkConditions:e=>{const t=e&&typeof e==="object"?e.profile:void 0;return{runtimeId:_store.networkConditionsRuntimeId,profile:(0,_store.setNetworkCondition)(t),available:(0,_store.conditionsCanApply)()}},clearEvents:()=>{_networkEventStore.networkEventStore.clearEvents()},getEventBody:e=>{const t=readId(e);if(!t)return null;const r=resolveEvent(t);if(!r)return null;return{url:r.url??null,method:r.method??null,status:r.status??null,override:r.override??null,requestData:r.requestData??null,responseData:r.responseData??null,requestHeaders:r.requestHeaders??null,responseHeaders:r.responseHeaders??null}},setPinned:e=>{const t=readId(e);if(!t)return null;const r=resolveEvent(t);if(!r)return null;const n=readBool(e,"pinned");const o=(0,_networkSavedStore.flagsForEventId)(_networkSavedStore.networkSavedStore.getState(),t).pinned;if(o===n)return{ok:true};return _networkSavedStore.networkSavedStore.togglePin(r)},setSaved:e=>{const t=readId(e);if(!t)return null;const r=resolveEvent(t);if(!r)return null;const n=readBool(e,"saved");const o=(0,_networkSavedStore.flagsForEventId)(_networkSavedStore.networkSavedStore.getState(),t).saved;if(o===n)return{ok:true};return _networkSavedStore.networkSavedStore.toggleSave(r)},removeSavedRecord:e=>{const t=e&&typeof e==="object"?e.key:void 0;if(!t)return null;_networkSavedStore.networkSavedStore.remove(t);return{ok:true}},clearSavedRequests:()=>{_networkSavedStore.networkSavedStore.clearSaved();return{ok:true}},clearPinnedRequests:()=>{_networkSavedStore.networkSavedStore.clearPinned();return{ok:true}},setOverridesEnabled:e=>{_overrideRulesStore.overrideRulesStore.setEnabled(readBool(e,"enabled"));return{ok:true,enabled:_overrideRulesStore.overrideRulesStore.getState().enabled,...inactiveStamp()}},upsertOverrideRule:e=>{const t=baseFromRequest(e)??preservedBody(e)??existingRule(e);const r=e?.rule??e;if(r&&typeof r.bodyPath==="string"&&r.body==null){const s=t?.body??(typeof r.id==="string"?_overrideRulesStore.overrideRulesStore.getState().rules.find(u=>u.id===r.id)?.body:void 0);if(typeof s!=="string"){return{ok:false,error:"bodyPath needs something to patch: send fromRequestId (the captured request whose real response it addresses) or the id of an existing rule."}}if(r.bodyValue===void 0){return{ok:false,error:`Refused: sent \`bodyPath\` without \`bodyValue\`. Say what to set "${r.bodyPath}" to.`}}let d;try{d=JSON.parse(s)}catch{return{ok:false,error:"The captured response body is not JSON, so it cannot be addressed by path. Send a whole `body` instead."}}const i=(0,_sharedUi.patchFromPath)(d,r.bodyPath,r.bodyValue);if(!i.ok)return{ok:false,error:`Refused: ${i.error}`};r.bodyPatch=i.patch;delete r.bodyPath;delete r.bodyValue}if(r&&isPlainObject(r.bodyPatch)&&r.body==null){const s=t?.body??(typeof r.id==="string"?_overrideRulesStore.overrideRulesStore.getState().rules.find(d=>d.id===r.id)?.body:void 0);if(typeof s!=="string"){return{ok:false,error:"bodyPatch needs something to patch: send fromRequestId (the captured request whose real response the patch is merged into) or the id of an existing rule."}}if(r.force!==true){let d;try{const u=(0,_sharedUi.expandKeyedArrays)(JSON.parse(s),r.bodyPatch);d=u.error;if(u.notes.length)r.bodyPatch=u.patch}catch{}if(d){return{ok:false,error:`Refused: ${d}`}}const i=patchViolations(r,s);if(i.length>0){return{ok:false,error:(0,_sharedUi.refusalText)(i,"response body",(0,_sharedUi.suggestedPatch)(r.bodyPatch,i)),violations:i}}}}const n=readRuleDraft(e,t);if(!n){const s=e?.fromRequestId;return{ok:false,error:s?`No captured request \`${s}\` \u2014 it may have been cleared. Send a urlPattern instead.`:"A rule needs a non-empty urlPattern."}}const o=_overrideRulesStore.overrideRulesStore.upsertRule(n);if(!o)return{ok:false,error:"Override rule limit reached."};if(o.enabled)_overrideRulesStore.overrideRulesStore.setEnabled(true);return{ok:true,rule:{id:o.id,urlPattern:o.urlPattern,enabled:o.enabled,kind:o.kind,status:o.status,times:o.times,bodySize:o.body?o.body.length:0},...o.times===void 0||o.times===null?{lingers:`This rule has no \`times\` budget, so it overrides EVERY matching request until it is disabled or deleted (id \`${o.id}\`). If you meant only the next one, set times:1.`}:{},...inactiveStamp()}},setOverrideRuleEnabled:e=>{const t=readId(e);if(!t)return{ok:false,error:"Missing rule id."};_overrideRulesStore.overrideRulesStore.setRuleEnabled(t,readBool(e,"enabled"));return{ok:true,...inactiveStamp()}},deleteOverrideRule:e=>{const t=readId(e);if(!t)return{ok:false,error:"Missing rule id."};_overrideRulesStore.overrideRulesStore.removeRule(t);return{ok:true}},clearOverrideRules:()=>{_overrideRulesStore.overrideRulesStore.clearRules();return{ok:true}},listOverrideRules:()=>_overrideRulesStore.overrideRulesStore.getState(),getOverrideRuleBody:e=>{const t=readId(e);if(!t)return null;const r=_overrideRulesStore.overrideRulesStore.getState().rules.find(n=>n.id===t);if(!r)return null;return{body:r.body??null}},getCaptureStatus:()=>{const e=_networkEventStore.networkEventStore.getSubscriberCounts().total;let t=null;let r=null;try{t=(0,_networkListener.isNetworkListening)();r=(0,_networkListener.getNetworkListenerCount)()}catch{}let n=null;try{n=(0,_networkListener.isNetworkInterceptionLive)()}catch{}return{capturing:e>0,subscribers:e,interceptorInstalled:t,interceptorLive:n,listenerCount:r,eventCount:_networkEventStore.networkEventStore.getEvents().length}},debugOverrides:e=>{const t=(e&&typeof e==="object"?e.url:void 0)??"https://example.com/";return{interceptorInstalled:(0,_networkListener.isNetworkListening)(),listenerCount:(0,_networkListener.getNetworkListenerCount)(),engine:(0,_engine.inspectEngine)(t,"GET"),store:{enabled:_overrideRulesStore.overrideRulesStore.getState().enabled,ruleCount:_overrideRulesStore.overrideRulesStore.getState().rules.length,rulesVisibleToEngine:_overrideRulesStore.overrideRulesStore.getRules().length}}}}};