@buoy-gg/network 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 (272) hide show
  1. package/README.md +11 -85
  2. package/lib/commonjs/index.js +1 -332
  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 -403
  22. package/lib/commonjs/network/components/NetworkListScreen.web.js +1 -624
  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 -135
  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 -510
  61. package/lib/commonjs/network/overrides/engine.js +1 -93
  62. package/lib/commonjs/network/overrides/matchRule.js +1 -87
  63. package/lib/commonjs/network/overrides/overriddenRows.js +1 -37
  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 -411
  80. package/lib/commonjs/network/utils/networkListener.js +4 -1352
  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 -16
  85. package/lib/commonjs/network/utils/resolveRequestUrl.js +1 -15
  86. package/lib/commonjs/network/utils/selectSavedEvents.js +1 -39
  87. package/lib/commonjs/network/utils/startNetworkCapture.js +1 -24
  88. package/lib/commonjs/network/utils/withPinnedFirst.js +1 -32
  89. package/lib/commonjs/preset.js +1 -93
  90. package/lib/module/index.js +1 -104
  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 -399
  110. package/lib/module/network/components/NetworkListScreen.web.js +1 -622
  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 -131
  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 -502
  149. package/lib/module/network/overrides/engine.js +1 -85
  150. package/lib/module/network/overrides/matchRule.js +1 -81
  151. package/lib/module/network/overrides/overriddenRows.js +1 -33
  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 -409
  168. package/lib/module/network/utils/networkListener.js +4 -1341
  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 -12
  173. package/lib/module/network/utils/resolveRequestUrl.js +1 -11
  174. package/lib/module/network/utils/selectSavedEvents.js +1 -35
  175. package/lib/module/network/utils/startNetworkCapture.js +1 -21
  176. package/lib/module/network/utils/withPinnedFirst.js +1 -28
  177. package/lib/module/preset.js +1 -91
  178. package/lib/typescript/network/overrides/engine.d.ts +1 -1
  179. package/lib/typescript/network/overrides/matchRule.d.ts +1 -1
  180. package/lib/typescript/network/overrides/resolveOverride.d.ts +2 -2
  181. package/lib/typescript/network/overrides/types.d.ts +9 -0
  182. package/lib/typescript/network/utils/networkListener.d.ts +11 -0
  183. package/lib/typescript/network/utils/realNow.d.ts +18 -0
  184. package/lib/web/index.mjs +73 -74
  185. package/package.json +3 -6
  186. package/lib/typescript/index.d.ts.map +0 -1
  187. package/lib/typescript/index.web.d.ts.map +0 -1
  188. package/lib/typescript/network/components/DataViewer.web.d.ts.map +0 -1
  189. package/lib/typescript/network/components/NetworkCopyScreen.web.d.ts.map +0 -1
  190. package/lib/typescript/network/components/NetworkCopySettingsView.d.ts.map +0 -1
  191. package/lib/typescript/network/components/NetworkCopySettingsView.web.d.ts.map +0 -1
  192. package/lib/typescript/network/components/NetworkDetailScreen.web.d.ts.map +0 -1
  193. package/lib/typescript/network/components/NetworkDetailStepper.d.ts.map +0 -1
  194. package/lib/typescript/network/components/NetworkDetailStepper.web.d.ts.map +0 -1
  195. package/lib/typescript/network/components/NetworkEventDetailView.d.ts.map +0 -1
  196. package/lib/typescript/network/components/NetworkEventDetailView.web.d.ts.map +0 -1
  197. package/lib/typescript/network/components/NetworkEventItemCompact.d.ts.map +0 -1
  198. package/lib/typescript/network/components/NetworkEventItemCompact.web.d.ts.map +0 -1
  199. package/lib/typescript/network/components/NetworkFilterScreen.web.d.ts.map +0 -1
  200. package/lib/typescript/network/components/NetworkFilterViewV3.d.ts.map +0 -1
  201. package/lib/typescript/network/components/NetworkFilterViewV3.web.d.ts.map +0 -1
  202. package/lib/typescript/network/components/NetworkHeaderLive.d.ts.map +0 -1
  203. package/lib/typescript/network/components/NetworkHeaderLive.web.d.ts.map +0 -1
  204. package/lib/typescript/network/components/NetworkHeaderMenu.d.ts.map +0 -1
  205. package/lib/typescript/network/components/NetworkListScreen.d.ts.map +0 -1
  206. package/lib/typescript/network/components/NetworkListScreen.web.d.ts.map +0 -1
  207. package/lib/typescript/network/components/NetworkModal.d.ts.map +0 -1
  208. package/lib/typescript/network/components/NetworkNumberPrompt.d.ts.map +0 -1
  209. package/lib/typescript/network/components/NetworkNumberPrompt.web.d.ts.map +0 -1
  210. package/lib/typescript/network/components/NetworkOverrideEditor.d.ts.map +0 -1
  211. package/lib/typescript/network/components/NetworkOverrideEditor.web.d.ts.map +0 -1
  212. package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts.map +0 -1
  213. package/lib/typescript/network/components/NetworkOverrideHeaderButton.web.d.ts.map +0 -1
  214. package/lib/typescript/network/components/NetworkOverridesButton.d.ts.map +0 -1
  215. package/lib/typescript/network/components/NetworkOverridesButton.web.d.ts.map +0 -1
  216. package/lib/typescript/network/components/NetworkOverridesScreen.d.ts.map +0 -1
  217. package/lib/typescript/network/components/NetworkOverridesScreen.web.d.ts.map +0 -1
  218. package/lib/typescript/network/components/NetworkSavedScreen.d.ts.map +0 -1
  219. package/lib/typescript/network/components/NetworkSavedScreen.web.d.ts.map +0 -1
  220. package/lib/typescript/network/components/NetworkUpgradeBanner.d.ts.map +0 -1
  221. package/lib/typescript/network/components/response-editor/Explorer.d.ts.map +0 -1
  222. package/lib/typescript/network/components/response-editor/Explorer.web.d.ts.map +0 -1
  223. package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts.map +0 -1
  224. package/lib/typescript/network/components/response-editor/editorContext.d.ts.map +0 -1
  225. package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts.map +0 -1
  226. package/lib/typescript/network/conditions/NetworkConditionsControl.d.ts.map +0 -1
  227. package/lib/typescript/network/conditions/NetworkConditionsControl.test.d.ts.map +0 -1
  228. package/lib/typescript/network/conditions/NetworkConditionsIcon.d.ts.map +0 -1
  229. package/lib/typescript/network/conditions/NetworkFloatingTool.d.ts.map +0 -1
  230. package/lib/typescript/network/conditions/NetworkFloatingTool.test.d.ts.map +0 -1
  231. package/lib/typescript/network/conditions/store.d.ts.map +0 -1
  232. package/lib/typescript/network/conditions/wait.d.ts.map +0 -1
  233. package/lib/typescript/network/conditions/xhr.d.ts.map +0 -1
  234. package/lib/typescript/network/hooks/useLiveNetworkEvent.d.ts.map +0 -1
  235. package/lib/typescript/network/hooks/useNetworkBadgeCounts.d.ts.map +0 -1
  236. package/lib/typescript/network/hooks/useNetworkEventList.d.ts.map +0 -1
  237. package/lib/typescript/network/hooks/useNetworkEvents.d.ts.map +0 -1
  238. package/lib/typescript/network/hooks/useNetworkHasMatches.d.ts.map +0 -1
  239. package/lib/typescript/network/hooks/useNetworkSaved.d.ts.map +0 -1
  240. package/lib/typescript/network/hooks/useNetworkSelection.d.ts.map +0 -1
  241. package/lib/typescript/network/hooks/useOverrideRules.d.ts.map +0 -1
  242. package/lib/typescript/network/hooks/useTickEveryMinute.d.ts.map +0 -1
  243. package/lib/typescript/network/overrides/applyToFetch.d.ts.map +0 -1
  244. package/lib/typescript/network/overrides/applyToXhr.d.ts.map +0 -1
  245. package/lib/typescript/network/overrides/engine.d.ts.map +0 -1
  246. package/lib/typescript/network/overrides/matchRule.d.ts.map +0 -1
  247. package/lib/typescript/network/overrides/overriddenRows.d.ts.map +0 -1
  248. package/lib/typescript/network/overrides/overrideRulesStore.d.ts.map +0 -1
  249. package/lib/typescript/network/overrides/presets.d.ts.map +0 -1
  250. package/lib/typescript/network/overrides/resolveOverride.d.ts.map +0 -1
  251. package/lib/typescript/network/overrides/types.d.ts.map +0 -1
  252. package/lib/typescript/network/sync/networkBodyResolver.d.ts.map +0 -1
  253. package/lib/typescript/network/sync/networkSyncAdapter.d.ts.map +0 -1
  254. package/lib/typescript/network/sync/overrideHonesty.release.test.d.ts.map +0 -1
  255. package/lib/typescript/network/types/index.d.ts.map +0 -1
  256. package/lib/typescript/network/utils/extractOperationName.d.ts.map +0 -1
  257. package/lib/typescript/network/utils/filterNetworkEvents.d.ts.map +0 -1
  258. package/lib/typescript/network/utils/formatGraphQLVariables.d.ts.map +0 -1
  259. package/lib/typescript/network/utils/formatting.d.ts.map +0 -1
  260. package/lib/typescript/network/utils/generateCurl.d.ts.map +0 -1
  261. package/lib/typescript/network/utils/generateNetworkCopyText.d.ts.map +0 -1
  262. package/lib/typescript/network/utils/httpCompletion.d.ts.map +0 -1
  263. package/lib/typescript/network/utils/networkEventStore.d.ts.map +0 -1
  264. package/lib/typescript/network/utils/networkListener.d.ts.map +0 -1
  265. package/lib/typescript/network/utils/networkSavedStore.d.ts.map +0 -1
  266. package/lib/typescript/network/utils/networkSelectionStore.d.ts.map +0 -1
  267. package/lib/typescript/network/utils/requestId.d.ts.map +0 -1
  268. package/lib/typescript/network/utils/resolveRequestUrl.d.ts.map +0 -1
  269. package/lib/typescript/network/utils/selectSavedEvents.d.ts.map +0 -1
  270. package/lib/typescript/network/utils/startNetworkCapture.d.ts.map +0 -1
  271. package/lib/typescript/network/utils/withPinnedFirst.d.ts.map +0 -1
  272. package/lib/typescript/preset.d.ts.map +0 -1
@@ -1,33 +1 @@
1
- "use strict";
2
-
3
- import { ruleMatches } from "./matchRule";
4
- /**
5
- * Which captured requests belong in the list's OVERRIDDEN strip.
6
- *
7
- * A row belongs there when an active rule actually changed it (it carries the
8
- * rule's override mark) or matched it after the rule existed (while overrides
9
- * are paused those pass through, and the strip is how you find the rule again).
10
- * Before a rule existed nothing overrode anything, so older matching requests
11
- * are real server responses and stay in the list, with one exception: the
12
- * newest of them, which is the request the rule was built from. That one hoists
13
- * right away, so creating a rule shows where it points without waiting for the
14
- * endpoint to be called again.
15
- */
16
- export function overriddenEvents(events, activeRules) {
17
- if (activeRules.length === 0) return [];
18
- const activeIds = new Set(activeRules.map(rule => rule.id));
19
- const picked = new Set();
20
- for (const rule of activeRules) {
21
- let source;
22
- for (const event of events) {
23
- if (event.override && activeIds.has(event.override.ruleId)) {
24
- picked.add(event.id);
25
- continue;
26
- }
27
- if (!ruleMatches(rule, event.url, String(event.method || "GET"))) continue;
28
- if (event.timestamp >= rule.createdAt) picked.add(event.id);else if (!source || event.timestamp > source.timestamp) source = event;
29
- }
30
- if (source) picked.add(source.id);
31
- }
32
- return events.filter(event => picked.has(event.id));
33
- }
1
+ "use strict";import{ruleMatches as s}from"./matchRule";export function overriddenEvents(o,d){if(d.length===0)return[];const n=new Set(d.map(t=>t.id));const i=new Set;for(const t of d){let r;for(const e of o){if(e.override&&n.has(e.override.ruleId)){i.add(e.id);continue}if(!s(t,e.url,String(e.method||"GET"),e.requestHeaders))continue;if(e.timestamp>=t.createdAt)i.add(e.id);else if(!r||e.timestamp>r.timestamp)r=e}if(r)i.add(r.id)}return o.filter(t=>i.has(t.id))}
@@ -1,547 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * The override rule list — persisted, and the source of truth for the engine.
5
- *
6
- * Shape and persistence follow `networkSavedStore` / `ignoredPatternsStore`:
7
- * lazy hydrate on first use, a `dirty` flag so a slow read can't clobber a
8
- * mutation the user just made, and commit = set + emit + persist.
9
- *
10
- * Two things here are specific to overrides and worth reading:
11
- *
12
- * - `getRules()` is on the HOT PATH. It is called inside the app's own
13
- * `XMLHttpRequest.send()`, for every request, so it does no work: the master
14
- * switch collapses to returning a frozen empty array.
15
- *
16
- * - `syncKeepAlive()` keeps the interceptor installed while any rule is
17
- * active. Without it a rule would stop firing the moment the Network tool
18
- * closed, because the swizzle is reference-counted off capture subscribers.
19
- */
20
-
21
- import { devToolsStorageKeys, persistentStorage } from "@buoy-gg/shared-ui";
22
- import { addNetworkListener, getNetworkListenerCount, startNetworkListener, stopNetworkListener } from "../utils/networkListener";
23
- import { setOverrideHooks } from "./engine";
24
- import { isSpent } from "./resolveOverride";
25
- import { MAX_RULES, STATUS_MAX, STATUS_MIN } from "./types";
26
-
27
- /**
28
- * A rule as authored. `id`/`createdAt` and the runtime counters (`hits`,
29
- * `seen`) are the store's business, never the caller's.
30
- */
31
-
32
- /**
33
- * Handlers the desktop dashboard installs to forward mutations to the device.
34
- *
35
- * Rules only DO anything on the device — a rule is applied inside the app's own
36
- * `fetch`/`XMLHttpRequest`, which the dashboard doesn't have. So in remote mode
37
- * this store becomes a MIRROR: it renders the device's rules and forwards every
38
- * edit, writing nothing to this machine's storage. Same seam
39
- * `networkSavedStore` uses for pins.
40
- */
41
-
42
- /**
43
- * How long a local optimistic write suppresses incoming mirrors.
44
- *
45
- * An edit is applied locally AND forwarded; the device echoes it back on its
46
- * next snapshot. Without this window the in-flight snapshot — the one already
47
- * on the wire when the user tapped — would land first and visibly revert the
48
- * edit for a frame.
49
- */
50
- const REMOTE_ECHO_GRACE_MS = 800;
51
-
52
- /**
53
- * Launches-with-rules-on before overrides pause themselves.
54
- *
55
- * Persisting rules is the point ("force a 500, restart, watch the boot path"),
56
- * but a body the app can't render turns that into a brick: the rule reinstates
57
- * itself on every launch and the controls to remove it live inside an app that
58
- * no longer draws. Verified in testing — the only exit was deleting the file
59
- * off the simulator.
60
- *
61
- * Three is chosen so the intended workflow survives (force, relaunch, look,
62
- * relaunch, look) while a wedge cannot outlive the second relaunch. The streak
63
- * resets whenever a rule is created or edited, so an actively-used rule set
64
- * never pauses.
65
- */
66
- const MAX_UNTOUCHED_LAUNCHES = 3;
67
- const EMPTY_RULES = Object.freeze([]);
68
-
69
- /** Hit counts change per request; the UI shouldn't re-render per request. */
70
- const HIT_EMIT_COALESCE_MS = 250;
71
- const VALID_KINDS = ["respond", "fail", "delay"];
72
-
73
- /**
74
- * Tolerate junk and older shapes rather than throwing the list away.
75
- *
76
- * Storage is forever: a shape that throws on parse would take the whole feature
77
- * down on every launch until the user cleared app data.
78
- */
79
- function parseRules(raw) {
80
- if (!Array.isArray(raw)) return [];
81
- const parsed = [];
82
- for (const entry of raw) {
83
- if (!entry || typeof entry !== "object") continue;
84
- const rule = entry;
85
- if (typeof rule.id !== "string" || typeof rule.urlPattern !== "string") {
86
- continue;
87
- }
88
- if (!rule.urlPattern) continue;
89
- const kind = VALID_KINDS.includes(rule.kind) ? rule.kind : "respond";
90
- parsed.push({
91
- id: rule.id,
92
- enabled: rule.enabled !== false,
93
- name: typeof rule.name === "string" ? rule.name : undefined,
94
- urlPattern: rule.urlPattern,
95
- methods: Array.isArray(rule.methods) ? rule.methods.filter(m => typeof m === "string") : undefined,
96
- kind,
97
- status: typeof rule.status === "number" ? Math.min(STATUS_MAX, Math.max(STATUS_MIN, rule.status)) : undefined,
98
- statusText: typeof rule.statusText === "string" ? rule.statusText : undefined,
99
- headers: rule.headers && typeof rule.headers === "object" ? rule.headers : undefined,
100
- body: typeof rule.body === "string" ? rule.body : undefined,
101
- failKind: rule.failKind === "timeout" ? "timeout" : undefined,
102
- delayMs: typeof rule.delayMs === "number" ? rule.delayMs : undefined,
103
- times: typeof rule.times === "number" ? rule.times : null,
104
- alternate: rule.alternate === true,
105
- // Runtime-only: a rule that fired 3 times last launch has fired 0 times
106
- // this one, and a persisted count would make `times` mean "ever" instead
107
- // of "this session".
108
- hits: 0,
109
- seen: 0,
110
- createdAt: typeof rule.createdAt === "number" ? rule.createdAt : 0
111
- });
112
- }
113
- return parsed.slice(0, MAX_RULES);
114
- }
115
- class OverrideRulesStore {
116
- rules = [];
117
- enabled = true;
118
- listeners = new Set();
119
- loaded = false;
120
- loadPromise = null;
121
- /** Set once a mutation happens so a slow initial load can't clobber it. */
122
- dirty = false;
123
- idCounter = 0;
124
- state = {
125
- enabled: true,
126
- rules: [],
127
- autoPaused: false
128
- };
129
- /** Consecutive launches that began with rules armed and nobody touching them. */
130
- launchStreak = 0;
131
- autoPaused = false;
132
- /** Held while any rule is active — see `syncKeepAlive`. */
133
- keepAlive = null;
134
- hitEmitTimer = null;
135
- /** Set on the desktop dashboard — see `disableEngine`. */
136
- engineDisabled = false;
137
- /** Set on the desktop dashboard — see `OverrideRulesRemote`. */
138
- remote = null;
139
- remoteEchoUntil = 0;
140
-
141
- // ===========================================================================
142
- // REMOTE MIRROR (desktop dashboard)
143
- // ===========================================================================
144
-
145
- /**
146
- * Turn this store into a mirror of a connected device's rules. Edits are
147
- * applied locally for immediate feedback AND forwarded to the device, which
148
- * is the source of truth; nothing is persisted to this machine.
149
- */
150
- enableRemoteMode(remote) {
151
- this.remote = remote;
152
- // A dashboard must never run rules against its own traffic.
153
- this.disableEngine();
154
- }
155
- disableRemoteMode() {
156
- this.remote = null;
157
- }
158
-
159
- /**
160
- * Feed the device's rules in (mirror mode only). `force` bypasses the echo
161
- * guard — used when tearing the mirror down, where there is no later snapshot
162
- * to converge on.
163
- */
164
- replaceRules(state, force = false) {
165
- if (!this.remote) return;
166
- // A local edit is still in flight — the snapshot on the wire predates it
167
- // and would flicker the change away. Drop this one; the next carries the
168
- // device's real answer.
169
- if (!force && Date.now() < this.remoteEchoUntil) return;
170
- this.enabled = state.enabled;
171
- this.rules = state.rules;
172
- this.rebuild();
173
- this.emit();
174
- }
175
-
176
- /** Mark a local optimistic write so the next in-flight mirror is ignored. */
177
- markLocalEdit() {
178
- if (this.remote) this.remoteEchoUntil = Date.now() + REMOTE_ECHO_GRACE_MS;
179
- }
180
-
181
- /**
182
- * Never intercept traffic in this runtime.
183
- *
184
- * The desktop dashboard renders the real tool (`NetworkToolView`), so this
185
- * module is imported there too — but the dashboard is a VIEWER. Its job is to
186
- * drive rules on the connected device, never to swizzle its own `fetch` and
187
- * override its own requests. The same seam `networkEventStore.disableCapture()`
188
- * uses, for the same reason.
189
- */
190
- disableEngine() {
191
- this.engineDisabled = true;
192
- if (this.keepAlive) {
193
- this.keepAlive();
194
- this.keepAlive = null;
195
- if (getNetworkListenerCount() === 0) stopNetworkListener();
196
- }
197
- }
198
- getState() {
199
- return this.state;
200
- }
201
-
202
- /**
203
- * The hot path — called inside `send()` for every request the app makes.
204
- * Returns a frozen empty array when the master switch is off so the caller
205
- * needs no second check.
206
- */
207
- getRules() {
208
- if (this.engineDisabled || !this.enabled) return EMPTY_RULES;
209
- return this.rules;
210
- }
211
-
212
- /**
213
- * The rule's real body, fetching it from the device when this surface only
214
- * has the stripped copy (see `OverrideRule.bodyOmitted`).
215
- *
216
- * On the device itself every body is already here, so this resolves
217
- * immediately and the editor never notices the difference.
218
- */
219
- async fetchRuleBody(id) {
220
- const rule = this.rules.find(candidate => candidate.id === id);
221
- if (!rule) return null;
222
- if (!rule.bodyOmitted) return rule.body ?? null;
223
- if (!this.remote?.getRuleBody) return null;
224
- try {
225
- return await this.remote.getRuleBody(id);
226
- } catch {
227
- // The editor keeps the empty body and the developer can retype it —
228
- // better than an error state over a payload they can still replace.
229
- return null;
230
- }
231
- }
232
-
233
- /** Rules that would actually fire — drives the "overrides active" banner. */
234
- activeCount() {
235
- if (!this.enabled) return 0;
236
- return this.rules.filter(rule => rule.enabled && !isSpent(rule)).length;
237
- }
238
- subscribe(listener) {
239
- this.listeners.add(listener);
240
- void this.ensureLoaded();
241
- return () => {
242
- this.listeners.delete(listener);
243
- };
244
- }
245
-
246
- // ===========================================================================
247
- // MUTATIONS
248
- // ===========================================================================
249
-
250
- setEnabled(enabled) {
251
- if (this.enabled === enabled) return;
252
- this.remote?.setEnabled(enabled);
253
- this.markLocalEdit();
254
- this.markTouched();
255
- this.enabled = enabled;
256
- this.commit(this.rules);
257
- }
258
- addRule(draft) {
259
- if (this.rules.length >= MAX_RULES) return null;
260
- const rule = {
261
- ...draft,
262
- id: `ovr_${Date.now().toString(36)}_${++this.idCounter}`,
263
- hits: 0,
264
- seen: 0,
265
- createdAt: Date.now()
266
- };
267
- // Newest first: a rule you just made should win over an older, broader one,
268
- // because first-match wins and you almost certainly meant the new one.
269
- this.commit([rule, ...this.rules]);
270
- return rule;
271
- }
272
-
273
- /**
274
- * Create or replace a rule in one call.
275
- *
276
- * THE ONLY WRITE PATH THE UI SHOULD USE. `addRule`/`updateRule` are the
277
- * primitives underneath and deliberately do NOT forward to the device — if
278
- * the UI called them directly, an edit made on the dashboard would apply to
279
- * the mirror and never reach the phone, which looks exactly like it worked.
280
- *
281
- * Returns the rule, or null when the list is full.
282
- */
283
- upsertRule(draft) {
284
- this.remote?.upsertRule(draft);
285
- this.markLocalEdit();
286
- this.markTouched();
287
- const {
288
- id,
289
- ...rest
290
- } = draft;
291
- if (id && this.rules.some(rule => rule.id === id)) {
292
- this.updateRule(id, rest);
293
- return this.rules.find(rule => rule.id === id) ?? null;
294
- }
295
- return this.addRule(rest);
296
- }
297
- updateRule(id, patch) {
298
- const index = this.rules.findIndex(rule => rule.id === id);
299
- if (index === -1) return;
300
- const next = [...this.rules];
301
- // Editing a rule resets its budget — otherwise a spent "fail once" rule
302
- // stays silently dead after you change it and looks broken.
303
- next[index] = {
304
- ...next[index],
305
- ...patch,
306
- hits: 0,
307
- seen: 0
308
- };
309
- this.commit(next);
310
- }
311
- setRuleEnabled(id, enabled) {
312
- const index = this.rules.findIndex(rule => rule.id === id);
313
- if (index === -1 || this.rules[index].enabled === enabled) return;
314
- this.remote?.setRuleEnabled(id, enabled);
315
- this.markLocalEdit();
316
- this.markTouched();
317
- const next = [...this.rules];
318
- // Re-enabling a spent rule has to clear its budget too, or the toggle
319
- // appears to do nothing.
320
- next[index] = {
321
- ...next[index],
322
- enabled,
323
- hits: enabled ? 0 : next[index].hits,
324
- seen: enabled ? 0 : next[index].seen
325
- };
326
- this.commit(next);
327
- }
328
- removeRule(id) {
329
- const next = this.rules.filter(rule => rule.id !== id);
330
- if (next.length === this.rules.length) return;
331
- this.remote?.removeRule(id);
332
- this.markLocalEdit();
333
- this.markTouched();
334
- this.commit(next);
335
- }
336
- clearRules() {
337
- if (this.rules.length === 0) return;
338
- this.remote?.clearRules();
339
- this.markLocalEdit();
340
- this.markTouched();
341
- this.commit([]);
342
- }
343
-
344
- /**
345
- * One rule matched one request.
346
- *
347
- * Replaces the rule object rather than mutating it so memoized rows actually
348
- * re-render, and coalesces the notification — this runs at request rate.
349
- */
350
- /**
351
- * One rule matched one request, applied or not.
352
- *
353
- * Deliberately silent — this fires on requests an alternating rule lets
354
- * through, where nothing visible changed. `recordHit` owns the notification.
355
- */
356
- recordMatch(ruleId) {
357
- const index = this.rules.findIndex(rule => rule.id === ruleId);
358
- if (index === -1) return;
359
- const next = [...this.rules];
360
- next[index] = {
361
- ...next[index],
362
- seen: next[index].seen + 1
363
- };
364
- this.rules = next;
365
- this.rebuild();
366
- }
367
- recordHit(ruleId) {
368
- const index = this.rules.findIndex(rule => rule.id === ruleId);
369
- if (index === -1) return;
370
- const rule = this.rules[index];
371
- const hits = rule.hits + 1;
372
- const spent = typeof rule.times === "number" && hits >= rule.times;
373
- const next = [...this.rules];
374
- next[index] = {
375
- ...rule,
376
- hits,
377
- enabled: spent ? false : rule.enabled
378
- };
379
- if (spent) {
380
- // Auto-expiry is a real state change (and releases the keep-alive), so it
381
- // commits immediately instead of waiting on the coalesce window.
382
- this.commit(next);
383
- return;
384
- }
385
- this.rules = next;
386
- this.rebuild();
387
- this.scheduleHitEmit();
388
- }
389
-
390
- // ===========================================================================
391
- // LIFECYCLE
392
- // ===========================================================================
393
-
394
- /**
395
- * Hydrate from storage. Safe to call repeatedly; only the first call reads.
396
- *
397
- * Called at package import (see `preset.tsx`) rather than on first subscribe,
398
- * because a rule has to fire from app boot — with the Network tool closed and
399
- * nothing capturing.
400
- */
401
- ensureLoaded() {
402
- // Mirror mode reads the device's rules, never this machine's storage.
403
- if (this.remote) return Promise.resolve();
404
- if (this.loaded) return Promise.resolve();
405
- if (this.loadPromise) return this.loadPromise;
406
- this.loadPromise = (async () => {
407
- try {
408
- const stored = await persistentStorage.getItem(devToolsStorageKeys.network.overrides());
409
- // A rule may have been created while this read was in flight — never
410
- // overwrite user intent with older disk state.
411
- if (stored && !this.dirty) {
412
- const parsed = JSON.parse(stored);
413
- this.enabled = parsed?.enabled !== false;
414
- this.rules = parseRules(parsed?.rules);
415
- this.launchStreak = typeof parsed?.launchStreak === "number" ? parsed.launchStreak : 0;
416
- this.applyLaunchGuard();
417
- this.rebuild();
418
- }
419
- } catch {
420
- // Corrupt or unreadable — start empty rather than taking the tool down.
421
- } finally {
422
- this.loaded = true;
423
- this.syncKeepAlive();
424
- this.emit();
425
- }
426
- })();
427
- return this.loadPromise;
428
- }
429
-
430
- /**
431
- * Count this launch, and pause overrides if they've been armed and untouched
432
- * for too many in a row. See MAX_UNTOUCHED_LAUNCHES for why.
433
- */
434
- applyLaunchGuard() {
435
- if (!this.enabled || this.activeCount() === 0) {
436
- this.launchStreak = 0;
437
- return;
438
- }
439
- this.launchStreak += 1;
440
- if (this.launchStreak >= MAX_UNTOUCHED_LAUNCHES) {
441
- this.enabled = false;
442
- this.autoPaused = true;
443
- this.launchStreak = 0;
444
- }
445
- this.persist();
446
- }
447
-
448
- /**
449
- * Keep the interceptor installed for as long as a rule could fire.
450
- *
451
- * The swizzle is reference-counted off `networkListener`'s listener count
452
- * (the event store adds one while capturing). Holding a no-op listener reuses
453
- * that existing lifecycle instead of inventing a second one.
454
- */
455
- syncKeepAlive() {
456
- const needed = !this.engineDisabled && this.activeCount() > 0;
457
- if (needed && !this.keepAlive) {
458
- startNetworkListener();
459
- this.keepAlive = addNetworkListener(() => {});
460
- return;
461
- }
462
- if (!needed && this.keepAlive) {
463
- this.keepAlive();
464
- this.keepAlive = null;
465
- // Only tear the swizzle down if nothing else wants it — the Network tool
466
- // may well still be open and capturing.
467
- if (getNetworkListenerCount() === 0) stopNetworkListener();
468
- }
469
- }
470
- scheduleHitEmit() {
471
- if (this.hitEmitTimer !== null) return;
472
- this.hitEmitTimer = setTimeout(() => {
473
- this.hitEmitTimer = null;
474
- this.emit();
475
- }, HIT_EMIT_COALESCE_MS);
476
- }
477
- commit(next) {
478
- this.dirty = true;
479
- this.rules = next.slice(0, MAX_RULES);
480
- this.rebuild();
481
- this.syncKeepAlive();
482
- this.emit();
483
- this.persist();
484
- }
485
-
486
- /** Rebuild the derived view once per mutation so renders get stable refs. */
487
- rebuild() {
488
- this.state = {
489
- enabled: this.enabled,
490
- rules: this.rules,
491
- autoPaused: this.autoPaused
492
- };
493
- }
494
-
495
- /**
496
- * The developer is actively working with the rules, so the launch guard has
497
- * nothing to protect them from — reset it and clear any auto-pause notice.
498
- */
499
- markTouched() {
500
- this.launchStreak = 0;
501
- this.autoPaused = false;
502
- }
503
-
504
- /**
505
- * The developer reached the override UI, which is proof the app still runs.
506
- *
507
- * The launch guard exists to escape a WEDGE — a body the app can't render,
508
- * where the controls are unreachable because nothing draws. If this call
509
- * happens, that isn't the situation, so the streak has nothing to protect
510
- * against. Without it the guard nags anyone who legitimately keeps a rule
511
- * armed for days, which is a real workflow ("force /checkout to 500 every
512
- * morning") and not the failure mode it was built for.
513
- */
514
- noteHealthyLaunch() {
515
- if (this.launchStreak === 0 && !this.autoPaused) return;
516
- this.markTouched();
517
- this.persist();
518
- this.rebuild();
519
- this.emit();
520
- }
521
- persist() {
522
- // The dashboard must not write the device's rules into its own storage —
523
- // they'd outlive the connection and shadow the next device.
524
- if (this.remote) return;
525
- persistentStorage.setItem(devToolsStorageKeys.network.overrides(), JSON.stringify({
526
- enabled: this.enabled,
527
- rules: this.rules,
528
- launchStreak: this.launchStreak
529
- })).catch(() => {
530
- // Silently fail — rules remain in memory for this session.
531
- });
532
- }
533
- emit() {
534
- this.listeners.forEach(listener => listener());
535
- }
536
- }
537
-
538
- /** Singleton — one rule list per JS runtime. */
539
- export const overrideRulesStore = new OverrideRulesStore();
540
-
541
- // Register with the engine so `networkListener` can reach the rules without
542
- // importing this module (which imports the listener — see engine.ts).
543
- setOverrideHooks({
544
- getRules: () => overrideRulesStore.getRules(),
545
- recordHit: ruleId => overrideRulesStore.recordHit(ruleId),
546
- recordMatch: ruleId => overrideRulesStore.recordMatch(ruleId)
547
- });
1
+ "use strict";import{devToolsStorageKeys as h,persistentStorage as a}from"@buoy-gg/shared-ui";import{addNetworkListener as f,getNetworkListenerCount as o,startNetworkListener as p,stopNetworkListener as d}from"../utils/networkListener";import{setOverrideHooks as b}from"./engine";import{isSpent as y}from"./resolveOverride";import{MAX_RULES as u,STATUS_MAX as k,STATUS_MIN as E}from"./types";import{realNow as c}from"../utils/realNow";const S=800;const g=3;const A=Object.freeze([]);const R=250;const v=["respond","fail","delay"];function T(n){if(!Array.isArray(n))return[];const t=[];for(const i of n){if(!i||typeof i!=="object")continue;const e=i;if(typeof e.id!=="string"||typeof e.urlPattern!=="string"){continue}if(!e.urlPattern)continue;const s=v.includes(e.kind)?e.kind:"respond";t.push({id:e.id,enabled:e.enabled!==false,name:typeof e.name==="string"?e.name:void 0,urlPattern:e.urlPattern,methods:Array.isArray(e.methods)?e.methods.filter(r=>typeof r==="string"):void 0,requireHeader:typeof e.requireHeader==="string"&&e.requireHeader?e.requireHeader:void 0,kind:s,status:typeof e.status==="number"?Math.min(k,Math.max(E,e.status)):void 0,statusText:typeof e.statusText==="string"?e.statusText:void 0,headers:e.headers&&typeof e.headers==="object"?e.headers:void 0,body:typeof e.body==="string"?e.body:void 0,failKind:e.failKind==="timeout"?"timeout":void 0,delayMs:typeof e.delayMs==="number"?e.delayMs:void 0,times:typeof e.times==="number"?e.times:null,alternate:e.alternate===true,hits:0,seen:0,createdAt:typeof e.createdAt==="number"?e.createdAt:0})}return t.slice(0,u)}class L{rules=[];enabled=true;listeners=new Set;loaded=false;loadPromise=null;dirty=false;idCounter=0;state={enabled:true,rules:[],autoPaused:false};launchStreak=0;autoPaused=false;keepAlive=null;hitEmitTimer=null;engineDisabled=false;remote=null;remoteEchoUntil=0;enableRemoteMode(t){this.remote=t;this.disableEngine()}disableRemoteMode(){this.remote=null}replaceRules(t,i=false){if(!this.remote)return;if(!i&&c()<this.remoteEchoUntil)return;this.enabled=t.enabled;this.rules=t.rules;this.rebuild();this.emit()}markLocalEdit(){if(this.remote)this.remoteEchoUntil=c()+S}disableEngine(){this.engineDisabled=true;if(this.keepAlive){this.keepAlive();this.keepAlive=null;if(o()===0)d()}}getState(){return this.state}getRules(){if(this.engineDisabled||!this.enabled)return A;return this.rules}async fetchRuleBody(t){const i=this.rules.find(e=>e.id===t);if(!i)return null;if(!i.bodyOmitted)return i.body??null;if(!this.remote?.getRuleBody)return null;try{return await this.remote.getRuleBody(t)}catch{return null}}activeCount(){if(!this.enabled)return 0;return this.rules.filter(t=>t.enabled&&!y(t)).length}subscribe(t){this.listeners.add(t);void this.ensureLoaded();return()=>{this.listeners.delete(t)}}setEnabled(t){if(this.enabled===t)return;this.remote?.setEnabled(t);this.markLocalEdit();this.markTouched();this.enabled=t;this.commit(this.rules)}addRule(t){if(this.rules.length>=u)return null;const i={...t,id:`ovr_${Date.now().toString(36)}_${++this.idCounter}`,hits:0,seen:0,createdAt:Date.now()};this.commit([i,...this.rules]);return i}upsertRule(t){this.remote?.upsertRule(t);this.markLocalEdit();this.markTouched();const{id:i,...e}=t;if(i&&this.rules.some(s=>s.id===i)){this.updateRule(i,e);return this.rules.find(s=>s.id===i)??null}return this.addRule(e)}updateRule(t,i){const e=this.rules.findIndex(r=>r.id===t);if(e===-1)return;const s=[...this.rules];s[e]={...s[e],...i,hits:0,seen:0};this.commit(s)}setRuleEnabled(t,i){const e=this.rules.findIndex(r=>r.id===t);if(e===-1||this.rules[e].enabled===i)return;this.remote?.setRuleEnabled(t,i);this.markLocalEdit();this.markTouched();const s=[...this.rules];s[e]={...s[e],enabled:i,hits:i?0:s[e].hits,seen:i?0:s[e].seen};this.commit(s)}removeRule(t){const i=this.rules.filter(e=>e.id!==t);if(i.length===this.rules.length)return;this.remote?.removeRule(t);this.markLocalEdit();this.markTouched();this.commit(i)}clearRules(){if(this.rules.length===0)return;this.remote?.clearRules();this.markLocalEdit();this.markTouched();this.commit([])}recordMatch(t){const i=this.rules.findIndex(s=>s.id===t);if(i===-1)return;const e=[...this.rules];e[i]={...e[i],seen:e[i].seen+1};this.rules=e;this.rebuild()}recordHit(t){const i=this.rules.findIndex(m=>m.id===t);if(i===-1)return;const e=this.rules[i];const s=e.hits+1;const r=typeof e.times==="number"&&s>=e.times;const l=[...this.rules];l[i]={...e,hits:s,enabled:r?false:e.enabled};if(r){this.commit(l);return}this.rules=l;this.rebuild();this.scheduleHitEmit()}ensureLoaded(){if(this.remote)return Promise.resolve();if(this.loaded)return Promise.resolve();if(this.loadPromise)return this.loadPromise;this.loadPromise=(async()=>{try{const t=await a.getItem(h.network.overrides());if(t&&!this.dirty){const i=JSON.parse(t);this.enabled=i?.enabled!==false;this.rules=T(i?.rules);this.launchStreak=typeof i?.launchStreak==="number"?i.launchStreak:0;this.applyLaunchGuard();this.rebuild()}}catch{}finally{this.loaded=true;this.syncKeepAlive();this.emit()}})();return this.loadPromise}applyLaunchGuard(){if(!this.enabled||this.activeCount()===0){this.launchStreak=0;return}this.launchStreak+=1;if(this.launchStreak>=g){this.enabled=false;this.autoPaused=true;this.launchStreak=0}this.persist()}syncKeepAlive(){const t=!this.engineDisabled&&this.activeCount()>0;if(t&&!this.keepAlive){p();this.keepAlive=f(()=>{});return}if(!t&&this.keepAlive){this.keepAlive();this.keepAlive=null;if(o()===0)d()}}scheduleHitEmit(){if(this.hitEmitTimer!==null)return;this.hitEmitTimer=setTimeout(()=>{this.hitEmitTimer=null;this.emit()},R)}commit(t){this.dirty=true;this.rules=t.slice(0,u);this.rebuild();this.syncKeepAlive();this.emit();this.persist()}rebuild(){this.state={enabled:this.enabled,rules:this.rules,autoPaused:this.autoPaused}}markTouched(){this.launchStreak=0;this.autoPaused=false}noteHealthyLaunch(){if(this.launchStreak===0&&!this.autoPaused)return;this.markTouched();this.persist();this.rebuild();this.emit()}persist(){if(this.remote)return;a.setItem(h.network.overrides(),JSON.stringify({enabled:this.enabled,rules:this.rules,launchStreak:this.launchStreak})).catch(()=>{})}emit(){this.listeners.forEach(t=>t())}}export const overrideRulesStore=new L;b({getRules:()=>overrideRulesStore.getRules(),recordHit:n=>overrideRulesStore.recordHit(n),recordMatch:n=>overrideRulesStore.recordMatch(n)});
@@ -1,65 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * Turning a captured request into a rule draft.
5
- *
6
- * Chrome's flow assumes a keyboard, a file tree and a second monitor. On a
7
- * phone the equivalent has to start from the request you're already looking at,
8
- * which is what this file is for — the editor never opens on a blank field.
9
- *
10
- * There used to be a list of one-tap presets here (Force 500, Empty list,
11
- * Offline…) rendered as chips. They're gone: the editor's outcome grid says the
12
- * same things in the same words, so keeping both meant two lists to maintain
13
- * and two places to look for the same choice.
14
- */
15
-
16
- /**
17
- * Turn a captured URL into a pattern that will match the request AGAIN.
18
- *
19
- * The query string is dropped and replaced with `*`, which is not a
20
- * simplification — it's the difference between a rule that works and one that
21
- * silently never fires. Plenty of clients cache-bust
22
- * (`?timestamp=1785783081234`), carry a request id, or page; pinning the exact
23
- * URL means the next call to the same endpoint doesn't match. Found exactly
24
- * that way: an "Offline" preset on a Pokémon request sat at 0 hits because the
25
- * app appends a timestamp to every call.
26
- *
27
- * The path stays exact, so this still means "this endpoint" and not "this
28
- * host" — and the editor shows the pattern, so narrowing it back down is one
29
- * edit away.
30
- */
31
- export function patternForUrl(url) {
32
- const query = url.indexOf("?");
33
- return query === -1 ? url : `${url.slice(0, query)}*`;
34
- }
35
-
36
- /** Render a captured body as editable text. */
37
- function bodyToText(data) {
38
- if (data == null) return "";
39
- if (typeof data === "string") return data;
40
- try {
41
- return JSON.stringify(data, null, 2);
42
- } catch {
43
- return "";
44
- }
45
- }
46
-
47
- /**
48
- * Prefill the rule editor from a captured request.
49
- *
50
- * Seeds the REAL response as the body so the common edit — change two fields of
51
- * a payload you just saw — starts from something true rather than from nothing.
52
- */
53
- export function draftFromEvent(event) {
54
- return {
55
- enabled: true,
56
- name: undefined,
57
- urlPattern: patternForUrl(event.url),
58
- methods: [String(event.method || "GET").toUpperCase()],
59
- kind: "respond",
60
- status: event.status && event.status >= 200 ? event.status : 200,
61
- statusText: event.statusText,
62
- body: bodyToText(event.responseData),
63
- times: null
64
- };
65
- }
1
+ "use strict";export function patternForUrl(t){const r=t.indexOf("?");return r===-1?t:`${t.slice(0,r)}*`}function n(t){if(t==null)return"";if(typeof t==="string")return t;try{return JSON.stringify(t,null,2)}catch{return""}}export function draftFromEvent(t){return{enabled:true,name:void 0,urlPattern:patternForUrl(t.url),methods:[String(t.method||"GET").toUpperCase()],kind:"respond",status:t.status&&t.status>=200?t.status:200,statusText:t.statusText,body:n(t.responseData),times:null}}