@buoy-gg/network 7.0.77 → 7.0.79

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 (84) hide show
  1. package/README.md +68 -2
  2. package/lib/commonjs/expo-network.js +1 -0
  3. package/lib/commonjs/index.js +1 -1
  4. package/lib/commonjs/index.web.js +1 -1
  5. package/lib/commonjs/netinfo.js +1 -0
  6. package/lib/commonjs/network/components/NetworkCopySettingsView.js +1 -1
  7. package/lib/commonjs/network/components/NetworkEventDetailView.js +2 -2
  8. package/lib/commonjs/network/components/NetworkEventDetailView.web.js +1 -1
  9. package/lib/commonjs/network/components/NetworkEventItemCompact.js +2 -2
  10. package/lib/commonjs/network/components/NetworkEventItemCompact.web.js +1 -1
  11. package/lib/commonjs/network/components/NetworkListScreen.js +1 -1
  12. package/lib/commonjs/network/components/NetworkModal.js +1 -1
  13. package/lib/commonjs/network/components/NetworkSavedScreen.js +1 -1
  14. package/lib/commonjs/network/conditions/NetworkConditionsControl.js +1 -1
  15. package/lib/commonjs/network/conditions/NetworkConditionsControl.test.js +1 -1
  16. package/lib/commonjs/network/conditions/NetworkConditionsIcon.js +1 -1
  17. package/lib/commonjs/network/conditions/NetworkFloatingTool.js +1 -1
  18. package/lib/commonjs/network/conditions/NetworkFloatingTool.test.js +1 -1
  19. package/lib/commonjs/network/conditions/connectivity/netInfoFacade.js +1 -0
  20. package/lib/commonjs/network/conditions/connectivity/patchNetwork.js +1 -0
  21. package/lib/commonjs/network/conditions/pacer.js +1 -0
  22. package/lib/commonjs/network/conditions/profiles.js +1 -0
  23. package/lib/commonjs/network/conditions/remoteState.js +1 -0
  24. package/lib/commonjs/network/conditions/store.js +1 -1
  25. package/lib/commonjs/network/conditions/wait.js +1 -1
  26. package/lib/commonjs/network/conditions/xhr.js +1 -1
  27. package/lib/commonjs/network/overrides/engine.js +1 -1
  28. package/lib/commonjs/network/overrides/matchRule.js +1 -1
  29. package/lib/commonjs/network/overrides/overrideRulesStore.js +1 -1
  30. package/lib/commonjs/network/sync/networkSyncAdapter.js +1 -1
  31. package/lib/commonjs/network/utils/generateNetworkCopyText.js +1 -0
  32. package/lib/commonjs/network/utils/networkListener.js +4 -4
  33. package/lib/module/expo-network.js +1 -0
  34. package/lib/module/index.js +1 -1
  35. package/lib/module/index.web.js +1 -1
  36. package/lib/module/netinfo.js +1 -0
  37. package/lib/module/network/components/NetworkCopySettingsView.js +3 -3
  38. package/lib/module/network/components/NetworkEventDetailView.js +2 -2
  39. package/lib/module/network/components/NetworkEventDetailView.web.js +2 -2
  40. package/lib/module/network/components/NetworkEventItemCompact.js +2 -2
  41. package/lib/module/network/components/NetworkEventItemCompact.web.js +1 -1
  42. package/lib/module/network/components/NetworkListScreen.js +1 -1
  43. package/lib/module/network/components/NetworkModal.js +1 -1
  44. package/lib/module/network/components/NetworkSavedScreen.js +1 -1
  45. package/lib/module/network/conditions/NetworkConditionsControl.js +1 -1
  46. package/lib/module/network/conditions/NetworkConditionsControl.test.js +1 -1
  47. package/lib/module/network/conditions/NetworkConditionsIcon.js +1 -1
  48. package/lib/module/network/conditions/NetworkFloatingTool.js +1 -1
  49. package/lib/module/network/conditions/NetworkFloatingTool.test.js +1 -1
  50. package/lib/module/network/conditions/connectivity/netInfoFacade.js +1 -0
  51. package/lib/module/network/conditions/connectivity/patchNetwork.js +1 -0
  52. package/lib/module/network/conditions/pacer.js +1 -0
  53. package/lib/module/network/conditions/profiles.js +1 -0
  54. package/lib/module/network/conditions/remoteState.js +1 -0
  55. package/lib/module/network/conditions/store.js +1 -1
  56. package/lib/module/network/conditions/wait.js +1 -1
  57. package/lib/module/network/conditions/xhr.js +1 -1
  58. package/lib/module/network/overrides/engine.js +1 -1
  59. package/lib/module/network/overrides/matchRule.js +1 -1
  60. package/lib/module/network/overrides/overrideRulesStore.js +1 -1
  61. package/lib/module/network/sync/networkSyncAdapter.js +1 -1
  62. package/lib/module/network/utils/generateNetworkCopyText.js +23 -22
  63. package/lib/module/network/utils/networkListener.js +4 -4
  64. package/lib/typescript/expo-network.d.ts +2 -0
  65. package/lib/typescript/index.d.ts +3 -2
  66. package/lib/typescript/index.web.d.ts +3 -2
  67. package/lib/typescript/netinfo.d.ts +3 -0
  68. package/lib/typescript/network/conditions/NetworkConditionsControl.d.ts +5 -2
  69. package/lib/typescript/network/conditions/NetworkFloatingTool.d.ts +4 -3
  70. package/lib/typescript/network/conditions/connectivity/netInfoFacade.d.ts +3 -0
  71. package/lib/typescript/network/conditions/connectivity/patchNetwork.d.ts +24 -0
  72. package/lib/typescript/network/conditions/pacer.d.ts +16 -0
  73. package/lib/typescript/network/conditions/profiles.d.ts +57 -0
  74. package/lib/typescript/network/conditions/remoteState.d.ts +4 -0
  75. package/lib/typescript/network/conditions/store.d.ts +45 -19
  76. package/lib/typescript/network/conditions/xhr.d.ts +1 -1
  77. package/lib/typescript/network/overrides/engine.d.ts +14 -0
  78. package/lib/typescript/network/overrides/matchRule.d.ts +3 -0
  79. package/lib/typescript/network/overrides/overrideRulesStore.d.ts +3 -0
  80. package/lib/typescript/network/overrides/types.d.ts +19 -0
  81. package/lib/typescript/network/sync/networkSyncAdapter.d.ts +27 -12
  82. package/lib/typescript/network/utils/networkListener.d.ts +4 -0
  83. package/lib/web/index.mjs +58 -57
  84. package/package.json +26 -3
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NetworkModal=NetworkModal;exports.NetworkToolView=NetworkToolView;var _NetworkFloatingTool=require("../conditions/NetworkFloatingTool");var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _NetworkFilterViewV=require("./NetworkFilterViewV3");var _useTickEveryMinute=require("../hooks/useTickEveryMinute");var _NetworkEventDetailView=require("./NetworkEventDetailView");var _NetworkCopySettingsView=require("./NetworkCopySettingsView");var _NetworkHeaderLive=require("./NetworkHeaderLive");var _NetworkListScreen=require("./NetworkListScreen");var _NetworkSavedScreen=require("./NetworkSavedScreen");var _NetworkOverridesScreen=require("./NetworkOverridesScreen");var _NetworkOverridesButton=require("./NetworkOverridesButton");var _NetworkOverrideHeaderButton=require("./NetworkOverrideHeaderButton");var _NetworkHeaderMenu=require("./NetworkHeaderMenu");var _NetworkDetailStepper=require("./NetworkDetailStepper");var _useNetworkEventList=require("../hooks/useNetworkEventList");var _useLiveNetworkEvent=require("../hooks/useLiveNetworkEvent");var _useNetworkSelection=require("../hooks/useNetworkSelection");var _networkSelectionStore=require("../utils/networkSelectionStore");var _networkSavedStore=require("../utils/networkSavedStore");var _types=require("../overrides/types");var _jsxRuntime=require("react/jsx-runtime");function NetworkDetailScreen({visible:t,paused:i,ignoredPatternValues:l,onTogglePattern:d,isPro:S,filter:n,ignoredPatterns:c,fromSaved:u,savedSearch:g,applySafeAreaInset:s}){const w=(0,_useNetworkSelection.useSelectedNetworkEventId)();const M=(0,_useNetworkSelection.useNetworkBodyEventId)();const p=w!=null&&w===M;const r=(0,_useLiveNetworkEvent.useLiveNetworkEvent)(w,{paused:i||!t});(0,_react.useEffect)(()=>{if(t&&r&&p){_networkSelectionStore.networkSelectionStore.reportRendered(r.id)}},[t,r,p]);if(!t)return null;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.detailRoot,children:[r?(0,_jsxRuntime.jsx)(_NetworkEventDetailView.NetworkEventDetailView,{event:r,ignoredPatterns:l,onTogglePattern:d,showBodies:p}):(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.detailBodyFallback}),(0,_jsxRuntime.jsx)(_NetworkDetailStepper.NetworkDetailStepper,{paused:i,filter:n,ignoredPatterns:c,isPro:S,fromSaved:u,savedSearch:g,applySafeAreaInset:s})]})}function NetworkFilterScreen({visible:t,paused:i,isPro:l,filter:d,onFilterChange:S,ignoredPatterns:n,onRemovePattern:c,onAddPattern:u,onTogglePatternMode:g,isTeamPattern:s}){const{events:w}=(0,_useNetworkEventList.useNetworkEventList)({filter:d,ignoredPatterns:n,paused:i,visible:t,isPro:l});if(!t)return null;return(0,_jsxRuntime.jsx)(_NetworkFilterViewV.NetworkFilterViewV3,{events:w,filter:d,onFilterChange:S,ignoredPatterns:n,onRemovePattern:c,onAddPattern:u,onTogglePatternMode:g,isTeamPattern:s})}function NetworkCopyScreen({visible:t,paused:i,isPro:l,filter:d,ignoredPatterns:S,settings:n,onSettingsChange:c}){const{events:u}=(0,_useNetworkEventList.useNetworkEventList)({filter:d,ignoredPatterns:S,paused:i,visible:t,isPro:l});if(!t)return null;return(0,_jsxRuntime.jsx)(_NetworkCopySettingsView.NetworkCopySettingsView,{settings:n,onSettingsChange:c,events:u})}function NetworkModalInner({visible:t,onClose:i,onBack:l,onMinimize:d,enableSharedModalDimensions:S=false,inline:n=false,paused:c,onPausedChange:u,remoteConditions:g}){const{isPro:s}=(0,_sharedUi.useFeatureGate)();const[w,M]=(0,_react.useState)(false);const p=c!=null&&u!=null;const r=p?c:w;const Y=e=>{const o=typeof e==="function"?e(r):e;if(p)u(o);else M(o)};const[a,C]=(0,_react.useState)({});const v=(0,_useNetworkSelection.useHasNetworkSelection)();const[h,V]=(0,_react.useState)(false);const[b,B]=(0,_react.useState)(false);const[j,H]=(0,_react.useState)(false);const[A,k]=(0,_react.useState)(false);const[Q,Z]=(0,_react.useState)(0);const[N]=(0,_react.useState)(_NetworkFloatingTool.createRemoteConditionsSource);(0,_react.useEffect)(()=>{N.update(g)},[N,g]);(0,_react.useEffect)(()=>()=>N.update(void 0),[N]);const f=true;const[ee,R]=(0,_react.useState)(null);const[T,L]=(0,_react.useState)("filters");const[D,te]=(0,_react.useState)("");const[E,q]=(0,_react.useState)(false);const ye=(0,_react.useRef)(false);const[U,re]=(0,_react.useState)("");const oe=(0,_react.useRef)(null);const{patterns:y,values:se,add:ne,remove:ae,toggle:ie,toggleMode:le,isTeamOnly:de}=(0,_sharedUi.useIgnoredPatterns)();const[P,z]=(0,_react.useState)(_NetworkCopySettingsView.DEFAULT_COPY_SETTINGS);const I=(0,_react.useRef)(false);const[_,O]=(0,_react.useState)(false);const[x,ce]=(0,_react.useState)("export");const m=e=>{ce(e);O(true)};(0,_react.useEffect)(()=>{if(_&&s){O(false)}},[_,s]);(0,_react.useEffect)(()=>{if(!t||I.current)return;const e=async()=>{try{const o=await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.network.copyOptions());if(o){const fe=JSON.parse(o);z(fe)}}catch(o){}finally{I.current=true}};e()},[t]);(0,_react.useEffect)(()=>{if(!I.current)return;const e=async()=>{try{await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.network.copyOptions(),JSON.stringify(P))}catch(o){}};e()},[P]);const ue=()=>{_networkSelectionStore.networkSelectionStore.clear()};const K=(0,_react.useCallback)(e=>{_networkSelectionStore.networkSelectionStore.select(e.id)},[]);const ve=(0,_react.useCallback)((e,o)=>{R(o?{...e,id:o}:e);H(true);_networkSelectionStore.networkSelectionStore.clear()},[]);const Se=(0,_react.useCallback)(()=>R(null),[]);const W=(0,_react.useRef)(null);const J=e=>{te(e);C(o=>({...o,searchText:e}))};const ge=e=>{C(o=>({...o,status:o.status===e?void 0:e}))};const[$,we]=(0,_react.useState)("bottomSheet");const he=e=>{we(e)};(0,_react.useEffect)(()=>{if(E){requestAnimationFrame(()=>{oe.current?.focus()})}},[E]);const G=()=>{if(h){return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:()=>V(false)}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"",noMargin:true,children:(0,_jsxRuntime.jsx)(_sharedUi.NightSegmented,{size:"sm",tabs:[{key:"filters",label:"Filters"},{key:"copy",label:"Copy"}],activeKey:T,onChange:e=>L(e)})})]})}if(v){return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:ue}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Request Details",centered:true}),(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions,{children:[f?(0,_jsxRuntime.jsx)(_NetworkOverrideHeaderButton.NetworkOverrideHeaderButton,{onOpen:ve}):null,(0,_jsxRuntime.jsx)(_NetworkHeaderLive.NetworkDetailPinActions,{isPro:s,onUpgradePress:()=>m("saved")})]})]})}if(j&&f){return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:()=>{if(W.current?.())return;H(false);R(null)}}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Response Overrides",centered:true})]})}if(b){return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:()=>B(false)}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Saved Requests",centered:true})]})}return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[l&&(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:l}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"",children:E?(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Search,{value:D,onChangeText:J,onCancel:()=>{J("");q(false)},onDismiss:()=>q(false),dismissOnBlur:true,clearOnlyWhenText:true,placeholder:"Search URL, method, operation, error...",accessibilityLabel:"Search network requests",iconSize:14,testID:"buoy-network-search-input",clearTestID:"buoy-network-search-clear",inputProps:{"sentry-label":"ignore network search header"}}):(0,_jsxRuntime.jsx)(_NetworkHeaderLive.NetworkHeaderBadges,{activeStatus:a.status,onToggleStatus:ge,ignoredPatterns:y,paused:r})}),(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions,{children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{"sentry-label":"ignore open search",testID:"buoy-network-search-open",accessibilityLabel:"Open search",accessibilityRole:"button",onPress:()=>q(true),style:styles.headerActionButton,children:(0,_jsxRuntime.jsx)(_sharedUi.Search,{size:14,color:_sharedUi.night.color.textSecondary})}),f?(0,_jsxRuntime.jsx)(_NetworkOverridesButton.NetworkOverridesButton,{onPress:()=>H(true)}):null,(0,_jsxRuntime.jsx)(_sharedUi.PowerToggleButton,{isEnabled:!r,onToggle:()=>Y(e=>!e),accessibilityLabel:r?"Resume network capture":"Pause network capture",testID:"buoy-network-power"}),(0,_jsxRuntime.jsx)(_NetworkHeaderLive.NetworkClearButton,{paused:r}),(0,_jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuButton,{onPress:()=>k(e=>!e),isOpen:A,hasIndicator:F})]})]})};const F=!!(a.status||a.method||a.contentType);const pe=S?_sharedUi.devToolsStorageKeys.modal.root():_sharedUi.devToolsStorageKeys.network.modal();if(!t)return null;const ke=v||!h;const X=(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.container,children:[(0,_jsxRuntime.jsx)(NetworkDetailScreen,{visible:v,paused:r,ignoredPatternValues:se,onTogglePattern:ie,isPro:s,filter:a,ignoredPatterns:y,fromSaved:b,savedSearch:U,applySafeAreaInset:!n&&$==="bottomSheet"}),(0,_jsxRuntime.jsx)(NetworkFilterScreen,{visible:h&&T==="filters"&&!v,paused:r,isPro:s,filter:a,onFilterChange:C,ignoredPatterns:y,onRemovePattern:ae,onAddPattern:ne,onTogglePatternMode:le,isTeamPattern:de}),(0,_jsxRuntime.jsx)(NetworkCopyScreen,{visible:h&&T==="copy"&&!v,paused:r,isPro:s,filter:a,ignoredPatterns:y,settings:P,onSettingsChange:z}),(0,_jsxRuntime.jsx)(_NetworkOverridesScreen.NetworkOverridesScreen,{visible:f&&j&&!v&&!h,isPro:s,onUpgradePress:()=>m("overrides"),pendingDraft:ee,onPendingConsumed:Se,backHandlerRef:W,applySafeAreaInset:!n&&$==="bottomSheet"}),(0,_jsxRuntime.jsx)(_NetworkSavedScreen.NetworkSavedScreen,{visible:b&&!v&&!h&&!(j&&f),isPro:s,copySettings:P,search:U,onSearchChange:re,onEventPress:K,onUpgradePress:()=>m("saved")}),(0,_jsxRuntime.jsx)(_NetworkListScreen.NetworkListScreen,{visible:!v&&!h&&!b&&!(j&&f),paused:r,filter:a,ignoredPatterns:y,isPro:s,searchText:D,onEventPress:K,onUpgradePress:()=>m("export")})]}),A?(0,_jsxRuntime.jsxs)(_NetworkHeaderMenu.NetworkHeaderMenu,{onClose:()=>k(false),children:[(0,_jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuItem,{icon:(0,_jsxRuntime.jsx)(_sharedUi.Wifi,{size:14,color:_sharedUi.night.color.textSecondary}),label:"Network throttling",testID:"buoy-network-menu-throttling",onPress:()=>{k(false);(0,_NetworkFloatingTool.openNetworkFloatingTool)(g?N:void 0);if(!n)Z(e=>e+1)}}),(0,_jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuItem,{icon:(0,_jsxRuntime.jsx)(_sharedUi.Filter,{size:14,color:F?_sharedUi.night.color.accent:_sharedUi.night.color.textSecondary}),label:"Filters",detail:F?"Active":void 0,onPress:()=>{k(false);L("filters");V(true)}}),(0,_jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuItem,{icon:(0,_jsxRuntime.jsx)(_sharedUi.Bookmark,{size:14,color:_sharedUi.night.color.textSecondary}),label:"Saved requests",onPress:()=>{k(false);B(true)}}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.menuCopyRow,children:(0,_jsxRuntime.jsx)(_NetworkHeaderLive.NetworkHeaderCopyButton,{isPro:s,filter:a,ignoredPatterns:y,copySettings:P,paused:r,onUpgradePress:()=>{k(false);m("export")},label:"Copy requests"})})]}):null,(0,_jsxRuntime.jsx)(_sharedUi.UpgradeModal,{visible:_,onClose:()=>O(false),featureName:x==="saved"?"Saved Requests":x==="overrides"?"Response Overrides":"Network Export",description:x==="saved"?"Keep the requests that matter. Saved requests survive Clear, app restarts, and the 500-request history cap.":x==="overrides"?"Force any endpoint to fail, stall or return something else \u2014 no backend changes, no code changes. Free keeps one active rule.":"Export network requests to share with your team, debug APIs, or feed into AI tools.",benefits:x==="overrides"?[`Run ${_types.MAX_RULES} rules at once (free keeps ${_types.FREE_TIER_RULE_LIMIT})`,"Force a 500, a 401 or an empty list in one tap","Simulate offline, timeouts and slow connections","Rules survive an app reload, so you can test the boot path"]:x==="saved"?[`Save up to ${_networkSavedStore.MAX_SAVED} requests (free keeps ${_networkSavedStore.FREE_TIER_SAVED_LIMIT})`,"Failed requests stay put through a Clear","Snapshots survive an app restart","Export saved requests to teammates or AI assistants"]:["Export to JSON, Markdown, or plain text","Customizable copy presets (URLs only, LLM-ready, full data)","Share request details with teammates","Feed network data directly to AI assistants"]})]});if(n){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.inlineRoot,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.inlineHeader,..._sharedUi.windowDragProps,children:G()}),X]})}return(0,_jsxRuntime.jsx)(_sharedUi.JsModal,{visible:t,onClose:i,onMinimize:d,minimizeRequest:Q,persistenceKey:pe,variant:"night",header:{showToggleButton:true,customContent:G()},onModeChange:he,enablePersistence:true,initialMode:"bottomSheet",enableGlitchEffects:true,disableScrollWrapper:ke,styles:{},children:X})}const styles=_reactNative.StyleSheet.create({container:{flex:1,backgroundColor:"transparent"},detailRoot:{flex:1,minHeight:0},detailBodyFallback:{flex:1},inlineRoot:{flex:1,minHeight:0,backgroundColor:"transparent"},inlineHeader:{paddingHorizontal:12,paddingVertical:8,borderBottomWidth:1,borderBottomColor:_sharedUi.macOSColors.border.default,backgroundColor:"transparent"},menuCopyRow:{paddingHorizontal:6},headerActionButton:{width:32,height:32,borderRadius:8,backgroundColor:_sharedUi.night.color.buttonSurface,borderWidth:1,borderColor:_sharedUi.night.color.border,alignItems:"center",justifyContent:"center"},activeFilterButton:{backgroundColor:_sharedUi.night.color.accentSoft,borderColor:_sharedUi.night.color.accentBorderStrong}});function NetworkModal(t){return(0,_jsxRuntime.jsx)(_useTickEveryMinute.TickProvider,{children:(0,_jsxRuntime.jsx)(NetworkModalInner,{...t})})}function NetworkToolView(t={}){return(0,_jsxRuntime.jsx)(_useTickEveryMinute.TickProvider,{children:(0,_jsxRuntime.jsx)(NetworkModalInner,{...t,inline:true,visible:true,onClose:noop})})}const noop=()=>{};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NetworkModal=NetworkModal;exports.NetworkToolView=NetworkToolView;var _NetworkFloatingTool=require("../conditions/NetworkFloatingTool");var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _NetworkFilterViewV=require("./NetworkFilterViewV3");var _useTickEveryMinute=require("../hooks/useTickEveryMinute");var _NetworkEventDetailView=require("./NetworkEventDetailView");var _NetworkCopySettingsView=require("./NetworkCopySettingsView");var _NetworkHeaderLive=require("./NetworkHeaderLive");var _NetworkListScreen=require("./NetworkListScreen");var _NetworkSavedScreen=require("./NetworkSavedScreen");var _NetworkOverridesScreen=require("./NetworkOverridesScreen");var _NetworkOverridesButton=require("./NetworkOverridesButton");var _NetworkOverrideHeaderButton=require("./NetworkOverrideHeaderButton");var _NetworkHeaderMenu=require("./NetworkHeaderMenu");var _NetworkDetailStepper=require("./NetworkDetailStepper");var _useNetworkEventList=require("../hooks/useNetworkEventList");var _useLiveNetworkEvent=require("../hooks/useLiveNetworkEvent");var _useNetworkSelection=require("../hooks/useNetworkSelection");var _networkSelectionStore=require("../utils/networkSelectionStore");var _networkSavedStore=require("../utils/networkSavedStore");var _types=require("../overrides/types");var _jsxRuntime=require("react/jsx-runtime");function NetworkDetailScreen({visible:t,paused:i,ignoredPatternValues:l,onTogglePattern:d,isPro:g,filter:n,ignoredPatterns:c,fromSaved:u,savedSearch:S,applySafeAreaInset:s}){const w=(0,_useNetworkSelection.useSelectedNetworkEventId)();const M=(0,_useNetworkSelection.useNetworkBodyEventId)();const k=w!=null&&w===M;const r=(0,_useLiveNetworkEvent.useLiveNetworkEvent)(w,{paused:i||!t});(0,_react.useEffect)(()=>{if(t&&r&&k){_networkSelectionStore.networkSelectionStore.reportRendered(r.id)}},[t,r,k]);if(!t)return null;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.detailRoot,children:[r?(0,_jsxRuntime.jsx)(_NetworkEventDetailView.NetworkEventDetailView,{event:r,ignoredPatterns:l,onTogglePattern:d,showBodies:k}):(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.detailBodyFallback}),(0,_jsxRuntime.jsx)(_NetworkDetailStepper.NetworkDetailStepper,{paused:i,filter:n,ignoredPatterns:c,isPro:g,fromSaved:u,savedSearch:S,applySafeAreaInset:s})]})}function NetworkFilterScreen({visible:t,paused:i,isPro:l,filter:d,onFilterChange:g,ignoredPatterns:n,onRemovePattern:c,onAddPattern:u,onTogglePatternMode:S,isTeamPattern:s}){const{events:w}=(0,_useNetworkEventList.useNetworkEventList)({filter:d,ignoredPatterns:n,paused:i,visible:t,isPro:l});if(!t)return null;return(0,_jsxRuntime.jsx)(_NetworkFilterViewV.NetworkFilterViewV3,{events:w,filter:d,onFilterChange:g,ignoredPatterns:n,onRemovePattern:c,onAddPattern:u,onTogglePatternMode:S,isTeamPattern:s})}function NetworkCopyScreen({visible:t,paused:i,isPro:l,filter:d,ignoredPatterns:g,settings:n,onSettingsChange:c}){const{events:u}=(0,_useNetworkEventList.useNetworkEventList)({filter:d,ignoredPatterns:g,paused:i,visible:t,isPro:l});if(!t)return null;return(0,_jsxRuntime.jsx)(_NetworkCopySettingsView.NetworkCopySettingsView,{settings:n,onSettingsChange:c,events:u})}function NetworkModalInner({visible:t,onClose:i,onBack:l,onMinimize:d,enableSharedModalDimensions:g=false,inline:n=false,paused:c,onPausedChange:u,remoteConditions:S}){const{isPro:s}=(0,_sharedUi.useFeatureGate)();const[w,M]=(0,_react.useState)(false);const k=c!=null&&u!=null;const r=k?c:w;const Q=e=>{const o=typeof e==="function"?e(r):e;if(k)u(o);else M(o)};const[a,C]=(0,_react.useState)({});const v=(0,_useNetworkSelection.useHasNetworkSelection)();const[h,V]=(0,_react.useState)(false);const[m,B]=(0,_react.useState)(false);const[j,H]=(0,_react.useState)(false);const[A,p]=(0,_react.useState)(false);const[Z,L]=(0,_react.useState)(0);const[f]=(0,_react.useState)(_NetworkFloatingTool.createRemoteConditionsSource);(0,_react.useEffect)(()=>{f.update(S)},[f,S]);(0,_react.useEffect)(()=>()=>f.update(void 0),[f]);const y=true;const[ee,T]=(0,_react.useState)(null);const[R,D]=(0,_react.useState)("filters");const[U,te]=(0,_react.useState)("");const[E,q]=(0,_react.useState)(false);const ye=(0,_react.useRef)(false);const[z,re]=(0,_react.useState)("");const oe=(0,_react.useRef)(null);const{patterns:x,values:se,add:ne,remove:ae,toggle:ie,toggleMode:le,isTeamOnly:de}=(0,_sharedUi.useIgnoredPatterns)();const[P,K]=(0,_react.useState)(_NetworkCopySettingsView.DEFAULT_COPY_SETTINGS);const I=(0,_react.useRef)(false);const[_,O]=(0,_react.useState)(false);const[N,ce]=(0,_react.useState)("export");const b=e=>{ce(e);O(true)};(0,_react.useEffect)(()=>{if(_&&s){O(false)}},[_,s]);(0,_react.useEffect)(()=>{if(!t||I.current)return;const e=async()=>{try{const o=await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.network.copyOptions());if(o){const fe=JSON.parse(o);K(fe)}}catch(o){}finally{I.current=true}};e()},[t]);(0,_react.useEffect)(()=>{if(!I.current)return;const e=async()=>{try{await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.network.copyOptions(),JSON.stringify(P))}catch(o){}};e()},[P]);const ue=()=>{_networkSelectionStore.networkSelectionStore.clear()};const W=(0,_react.useCallback)(e=>{_networkSelectionStore.networkSelectionStore.select(e.id)},[]);const Se=(0,_react.useCallback)((e,o)=>{T(o?{...e,id:o}:e);H(true);_networkSelectionStore.networkSelectionStore.clear()},[]);const ve=(0,_react.useCallback)(()=>T(null),[]);const J=(0,_react.useRef)(null);const $=e=>{te(e);C(o=>({...o,searchText:e}))};const ge=e=>{C(o=>({...o,status:o.status===e?void 0:e}))};const[G,we]=(0,_react.useState)("bottomSheet");const he=e=>{we(e)};(0,_react.useEffect)(()=>{if(E){requestAnimationFrame(()=>{oe.current?.focus()})}},[E]);const X=()=>{if(h){return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:()=>V(false)}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"",noMargin:true,children:(0,_jsxRuntime.jsx)(_sharedUi.NightSegmented,{size:"sm",tabs:[{key:"filters",label:"Filters"},{key:"copy",label:"Copy"}],activeKey:R,onChange:e=>D(e)})})]})}if(v){return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:ue}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Request Details",centered:true}),(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions,{children:[y?(0,_jsxRuntime.jsx)(_NetworkOverrideHeaderButton.NetworkOverrideHeaderButton,{onOpen:Se}):null,(0,_jsxRuntime.jsx)(_NetworkHeaderLive.NetworkDetailPinActions,{isPro:s,onUpgradePress:()=>b("saved")})]})]})}if(j&&y){return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:()=>{if(J.current?.())return;H(false);T(null)}}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Response Overrides",centered:true})]})}if(m){return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:()=>B(false)}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Saved Requests",centered:true})]})}return(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[l&&(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:l}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"",children:E?(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Search,{value:U,onChangeText:$,onCancel:()=>{$("");q(false)},onDismiss:()=>q(false),dismissOnBlur:true,clearOnlyWhenText:true,placeholder:"Search URL, method, operation, error...",accessibilityLabel:"Search network requests",iconSize:14,testID:"buoy-network-search-input",clearTestID:"buoy-network-search-clear",inputProps:{"sentry-label":"ignore network search header"}}):(0,_jsxRuntime.jsx)(_NetworkHeaderLive.NetworkHeaderBadges,{activeStatus:a.status,onToggleStatus:ge,ignoredPatterns:x,paused:r})}),(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions,{children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{"sentry-label":"ignore open search",testID:"buoy-network-search-open",accessibilityLabel:"Open search",accessibilityRole:"button",onPress:()=>q(true),style:styles.headerActionButton,children:(0,_jsxRuntime.jsx)(_sharedUi.Search,{size:14,color:_sharedUi.night.color.textSecondary})}),y?(0,_jsxRuntime.jsx)(_NetworkOverridesButton.NetworkOverridesButton,{onPress:()=>H(true)}):null,(0,_jsxRuntime.jsx)(_sharedUi.PowerToggleButton,{isEnabled:!r,onToggle:()=>Q(e=>!e),accessibilityLabel:r?"Resume network capture":"Pause network capture",testID:"buoy-network-power"}),(0,_jsxRuntime.jsx)(_NetworkHeaderLive.NetworkClearButton,{paused:r}),(0,_jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuButton,{onPress:()=>p(e=>!e),isOpen:A,hasIndicator:F})]})]})};const F=!!(a.status||a.method||a.contentType);const pe=g?_sharedUi.devToolsStorageKeys.modal.root():_sharedUi.devToolsStorageKeys.network.modal();if(!t)return null;const ke=v||!h;const Y=(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.container,children:[(0,_jsxRuntime.jsx)(NetworkDetailScreen,{visible:v,paused:r,ignoredPatternValues:se,onTogglePattern:ie,isPro:s,filter:a,ignoredPatterns:x,fromSaved:m,savedSearch:z,applySafeAreaInset:!n&&G==="bottomSheet"}),(0,_jsxRuntime.jsx)(NetworkFilterScreen,{visible:h&&R==="filters"&&!v,paused:r,isPro:s,filter:a,onFilterChange:C,ignoredPatterns:x,onRemovePattern:ae,onAddPattern:ne,onTogglePatternMode:le,isTeamPattern:de}),(0,_jsxRuntime.jsx)(NetworkCopyScreen,{visible:h&&R==="copy"&&!v,paused:r,isPro:s,filter:a,ignoredPatterns:x,settings:P,onSettingsChange:K}),(0,_jsxRuntime.jsx)(_NetworkOverridesScreen.NetworkOverridesScreen,{visible:y&&j&&!v&&!h,isPro:s,onUpgradePress:()=>b("overrides"),pendingDraft:ee,onPendingConsumed:ve,backHandlerRef:J,applySafeAreaInset:!n&&G==="bottomSheet"}),(0,_jsxRuntime.jsx)(_NetworkSavedScreen.NetworkSavedScreen,{visible:m&&!v&&!h&&!(j&&y),isPro:s,copySettings:P,search:z,onSearchChange:re,onEventPress:W,onUpgradePress:()=>b("saved")}),(0,_jsxRuntime.jsx)(_NetworkListScreen.NetworkListScreen,{visible:!v&&!h&&!m&&!(j&&y),paused:r,filter:a,ignoredPatterns:x,isPro:s,searchText:U,onEventPress:W,onUpgradePress:()=>b("export")})]}),A?(0,_jsxRuntime.jsxs)(_NetworkHeaderMenu.NetworkHeaderMenu,{onClose:()=>p(false),children:[(0,_jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuItem,{icon:(0,_jsxRuntime.jsx)(_sharedUi.Wifi,{size:14,color:_sharedUi.night.color.textSecondary}),label:"Network throttling",testID:"buoy-network-menu-throttling",onPress:()=>{p(false);(0,_NetworkFloatingTool.openNetworkFloatingTool)(S?f:void 0);if(!n)L(e=>e+1)}}),(0,_jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuItem,{icon:(0,_jsxRuntime.jsx)(_sharedUi.Wifi,{size:14,color:_sharedUi.night.color.textSecondary}),label:"Speed and link state",testID:"buoy-network-menu-conditions",onPress:()=>{p(false);(0,_NetworkFloatingTool.openNetworkFloatingTool)(S?f:void 0,true);if(!n)L(e=>e+1)}}),(0,_jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuItem,{icon:(0,_jsxRuntime.jsx)(_sharedUi.Filter,{size:14,color:F?_sharedUi.night.color.accent:_sharedUi.night.color.textSecondary}),label:"Filters",detail:F?"Active":void 0,onPress:()=>{p(false);D("filters");V(true)}}),(0,_jsxRuntime.jsx)(_NetworkHeaderMenu.NetworkHeaderMenuItem,{icon:(0,_jsxRuntime.jsx)(_sharedUi.Bookmark,{size:14,color:_sharedUi.night.color.textSecondary}),label:"Saved requests",onPress:()=>{p(false);B(true)}}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.menuCopyRow,children:(0,_jsxRuntime.jsx)(_NetworkHeaderLive.NetworkHeaderCopyButton,{isPro:s,filter:a,ignoredPatterns:x,copySettings:P,paused:r,onUpgradePress:()=>{p(false);b("export")},label:"Copy requests"})})]}):null,(0,_jsxRuntime.jsx)(_sharedUi.UpgradeModal,{visible:_,onClose:()=>O(false),featureName:N==="saved"?"Saved Requests":N==="overrides"?"Response Overrides":"Network Export",description:N==="saved"?"Keep the requests that matter. Saved requests survive Clear, app restarts, and the 500-request history cap.":N==="overrides"?"Force any endpoint to fail, stall or return something else \u2014 no backend changes, no code changes. Free keeps one active rule.":"Export network requests to share with your team, debug APIs, or feed into AI tools.",benefits:N==="overrides"?[`Run ${_types.MAX_RULES} rules at once (free keeps ${_types.FREE_TIER_RULE_LIMIT})`,"Force a 500, a 401 or an empty list in one tap","Simulate offline, timeouts and slow connections","Rules survive an app reload, so you can test the boot path"]:N==="saved"?[`Save up to ${_networkSavedStore.MAX_SAVED} requests (free keeps ${_networkSavedStore.FREE_TIER_SAVED_LIMIT})`,"Failed requests stay put through a Clear","Snapshots survive an app restart","Export saved requests to teammates or AI assistants"]:["Export to JSON, Markdown, or plain text","Customizable copy presets (URLs only, LLM-ready, full data)","Share request details with teammates","Feed network data directly to AI assistants"]})]});if(n){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.inlineRoot,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.inlineHeader,..._sharedUi.windowDragProps,children:X()}),Y]})}return(0,_jsxRuntime.jsx)(_sharedUi.JsModal,{visible:t,onClose:i,onMinimize:d,minimizeRequest:Z,persistenceKey:pe,variant:"night",header:{showToggleButton:true,customContent:X()},onModeChange:he,enablePersistence:true,initialMode:"bottomSheet",enableGlitchEffects:true,disableScrollWrapper:ke,styles:{},children:Y})}const styles=_reactNative.StyleSheet.create({container:{flex:1,backgroundColor:"transparent"},detailRoot:{flex:1,minHeight:0},detailBodyFallback:{flex:1},inlineRoot:{flex:1,minHeight:0,backgroundColor:"transparent"},inlineHeader:{paddingHorizontal:12,paddingVertical:8,borderBottomWidth:1,borderBottomColor:_sharedUi.macOSColors.border.default,backgroundColor:"transparent"},menuCopyRow:{paddingHorizontal:6},headerActionButton:{width:32,height:32,borderRadius:8,backgroundColor:_sharedUi.night.color.buttonSurface,borderWidth:1,borderColor:_sharedUi.night.color.border,alignItems:"center",justifyContent:"center"},activeFilterButton:{backgroundColor:_sharedUi.night.color.accentSoft,borderColor:_sharedUi.night.color.accentBorderStrong}});function NetworkModal(t){return(0,_jsxRuntime.jsx)(_useTickEveryMinute.TickProvider,{children:(0,_jsxRuntime.jsx)(NetworkModalInner,{...t})})}function NetworkToolView(t={}){return(0,_jsxRuntime.jsx)(_useTickEveryMinute.TickProvider,{children:(0,_jsxRuntime.jsx)(NetworkModalInner,{...t,inline:true,visible:true,onClose:noop})})}const noop=()=>{};
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NetworkSavedScreen=NetworkSavedScreen;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _NetworkEventItemCompact=require("./NetworkEventItemCompact");var _NetworkUpgradeBanner=require("./NetworkUpgradeBanner");var _generateNetworkCopyText=require("../utils/generateNetworkCopyText");var _selectSavedEvents=require("../utils/selectSavedEvents");var _useNetworkSaved=require("../hooks/useNetworkSaved");var _networkSavedStore=require("../utils/networkSavedStore");var _jsxRuntime=require("react/jsx-runtime");const keyExtractor=l=>l.id;function NetworkSavedScreen({visible:l,isPro:u,copySettings:v,search:n,onSearchChange:i,onEventPress:g,onUpgradePress:p}){const{savedRecords:e,pinnedLiveIds:c,toggleSave:S,clearSaved:m}=(0,_useNetworkSaved.useNetworkSaved)();const t=(0,_sharedUi.useLimit)("network.saved");const[h,x]=(0,_react.useState)("");const d=n!=null&&i!=null;const r=d?n:h;const b=d?i:x;if(!l)return null;const{events:o,lockedCount:a}=(0,_selectSavedEvents.selectSavedEvents)(e,t,r);const C=s=>{S(s)};const y=({item:s})=>(0,_jsxRuntime.jsx)(_NetworkEventItemCompact.NetworkEventItemCompact,{event:s,onPress:g,onLongPress:C,saved:true,pinned:c.has(s.id)});const k=()=>{if(a===0)return null;return(0,_jsxRuntime.jsx)(_NetworkUpgradeBanner.NetworkUpgradeBanner,{title:`${a} saved ${a===1?"request":"requests"} locked`,subtitle:`Your plan keeps ${t}. Upgrade to Pro to unlock the rest.`,onPress:p})};return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.root,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.toolbar,children:[(0,_jsxRuntime.jsx)(_sharedUi.Bookmark,{size:11,color:_sharedUi.macOSColors.semantic.debug}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.toolbarTitle,children:["SAVED \xB7 ",e.length,t>=_networkSavedStore.MAX_SAVED?"":`/${t}`]}),u?(0,_jsxRuntime.jsx)(_sharedUi.CopyButton,{value:()=>(0,_generateNetworkCopyText.generateNetworkCopyText)(o,v),size:13,buttonStyle:styles.toolbarButton,colors:{idle:_sharedUi.macOSColors.text.secondary,success:_sharedUi.macOSColors.semantic.success,error:_sharedUi.macOSColors.semantic.error},disabled:o.length===0}):null,(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:m,"sentry-label":"ignore clear saved",style:styles.toolbarClear,disabled:e.length===0,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.toolbarClearText,e.length===0&&styles.toolbarClearTextDisabled],children:"Clear all"})})]}),e.length>0?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.searchRow,children:[(0,_jsxRuntime.jsx)(_sharedUi.Search,{size:13,color:_sharedUi.macOSColors.text.secondary}),(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.searchInput,placeholder:"Search saved requests\u2026",placeholderTextColor:_sharedUi.macOSColors.text.muted,value:r,onChangeText:b,"sentry-label":"ignore saved search",accessibilityLabel:"Search saved requests",autoCapitalize:"none",autoCorrect:false,returnKeyType:"search"})]}):null,e.length===0||r.trim().length>0&&o.length===0&&a===0?(0,_jsxRuntime.jsx)(_sharedUi.ToolEmptyState,{testID:"buoy-network-saved-empty",...(0,_sharedUi.resolveListEmptyState)({subject:"saved requests",verb:"kept",search:e.length===0?"":r,total:e.length,waiting:{otto:"empty",title:"No saved requests",message:"Open a request and tap the bookmark to keep it here \u2014 saved requests survive Clear and app restarts."}})}):(0,_jsxRuntime.jsx)(_reactNative.FlatList,{data:o,renderItem:y,keyExtractor,contentContainerStyle:styles.listContent,showsVerticalScrollIndicator:true,scrollEnabled:true,..._sharedUi.EVENT_LIST_PRESET,extraData:c,"sentry-label":"ignore saved requests list",ListFooterComponent:k})]})}const styles=_reactNative.StyleSheet.create({root:{flex:1,minHeight:0},toolbar:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:20,paddingTop:10,paddingBottom:6},toolbarTitle:{flex:1,color:_sharedUi.macOSColors.semantic.debug,fontSize:10,fontWeight:"700",letterSpacing:.6,fontFamily:_sharedUi.monoFont},toolbarButton:{width:26,height:26,borderRadius:6,alignItems:"center",justifyContent:"center"},toolbarClear:{paddingHorizontal:6,paddingVertical:2},toolbarClearText:{color:_sharedUi.macOSColors.text.muted,fontSize:10},toolbarClearTextDisabled:{color:_sharedUi.macOSColors.text.disabled},searchRow:{flexDirection:"row",alignItems:"center",gap:6,marginHorizontal:12,marginBottom:8,paddingHorizontal:10,paddingVertical:5,backgroundColor:_sharedUi.macOSColors.background.input,borderRadius:10,borderWidth:1,borderColor:_sharedUi.macOSColors.border.default},searchInput:{flex:1,color:_sharedUi.macOSColors.text.primary,fontSize:13,paddingVertical:2},listContent:{paddingTop:4}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NetworkSavedScreen=NetworkSavedScreen;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _NetworkEventItemCompact=require("./NetworkEventItemCompact");var _NetworkUpgradeBanner=require("./NetworkUpgradeBanner");var _generateNetworkCopyText=require("../utils/generateNetworkCopyText");var _selectSavedEvents=require("../utils/selectSavedEvents");var _useNetworkSaved=require("../hooks/useNetworkSaved");var _networkSavedStore=require("../utils/networkSavedStore");var _jsxRuntime=require("react/jsx-runtime");const keyExtractor=l=>l.id;function NetworkSavedScreen({visible:l,isPro:u,copySettings:v,search:n,onSearchChange:i,onEventPress:p,onUpgradePress:g}){const{savedRecords:e,pinnedLiveIds:c,toggleSave:S,clearSaved:h}=(0,_useNetworkSaved.useNetworkSaved)();const t=(0,_sharedUi.useLimit)("network.saved");const[m,x]=(0,_react.useState)("");const d=n!=null&&i!=null;const r=d?n:m;const b=d?i:x;if(!l)return null;const{events:o,lockedCount:a}=(0,_selectSavedEvents.selectSavedEvents)(e,t,r);const C=s=>{S(s)};const y=({item:s})=>(0,_jsxRuntime.jsx)(_NetworkEventItemCompact.NetworkEventItemCompact,{event:s,onPress:p,onLongPress:C,saved:true,pinned:c.has(s.id)});const k=()=>{if(a===0)return null;return(0,_jsxRuntime.jsx)(_NetworkUpgradeBanner.NetworkUpgradeBanner,{title:`${a} saved ${a===1?"request":"requests"} locked`,subtitle:`Your plan keeps ${t}. Upgrade to Pro to unlock the rest.`,onPress:g})};return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.root,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.toolbar,children:[(0,_jsxRuntime.jsx)(_sharedUi.Bookmark,{size:11,color:_sharedUi.macOSColors.semantic.debug}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.toolbarTitle,children:["SAVED \xB7 ",e.length,t>=_networkSavedStore.MAX_SAVED?"":`/${t}`]}),u?(0,_jsxRuntime.jsx)(_sharedUi.CopyButton,{value:()=>(0,_generateNetworkCopyText.generateNetworkCopyText)(o,v),size:13,buttonStyle:styles.toolbarButton,colors:{idle:_sharedUi.macOSColors.text.secondary,success:_sharedUi.macOSColors.semantic.success,error:_sharedUi.macOSColors.semantic.error},disabled:o.length===0}):null,(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:h,"sentry-label":"ignore clear saved",style:styles.toolbarClear,disabled:e.length===0,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.toolbarClearText,e.length===0&&styles.toolbarClearTextDisabled],children:"Clear all"})})]}),e.length>0?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.searchRow,children:[(0,_jsxRuntime.jsx)(_sharedUi.Search,{size:13,color:_sharedUi.macOSColors.text.secondary}),(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.searchInput,placeholder:"Search saved requests\u2026",placeholderTextColor:_sharedUi.macOSColors.text.muted,value:r,onChangeText:b,"sentry-label":"ignore saved search",accessibilityLabel:"Search saved requests",autoCapitalize:"none",autoCorrect:false,returnKeyType:"search"})]}):null,e.length===0||r.trim().length>0&&o.length===0&&a===0?(0,_jsxRuntime.jsx)(_sharedUi.ToolEmptyState,{testID:"buoy-network-saved-empty",...(0,_sharedUi.resolveListEmptyState)({subject:"saved requests",verb:"kept",search:e.length===0?"":r,total:e.length,waiting:{otto:"empty",title:"No saved requests",message:"Open a request and tap the bookmark to keep it here \u2014 saved requests survive Clear and app restarts."}})}):(0,_jsxRuntime.jsx)(_reactNative.FlatList,{keyboardShouldPersistTaps:"handled",data:o,renderItem:y,keyExtractor,contentContainerStyle:styles.listContent,showsVerticalScrollIndicator:true,scrollEnabled:true,..._sharedUi.EVENT_LIST_PRESET,extraData:c,"sentry-label":"ignore saved requests list",ListFooterComponent:k})]})}const styles=_reactNative.StyleSheet.create({root:{flex:1,minHeight:0},toolbar:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:20,paddingTop:10,paddingBottom:6},toolbarTitle:{flex:1,color:_sharedUi.macOSColors.semantic.debug,fontSize:10,fontWeight:"700",letterSpacing:.6,fontFamily:_sharedUi.monoFont},toolbarButton:{width:26,height:26,borderRadius:6,alignItems:"center",justifyContent:"center"},toolbarClear:{paddingHorizontal:6,paddingVertical:2},toolbarClearText:{color:_sharedUi.macOSColors.text.muted,fontSize:10},toolbarClearTextDisabled:{color:_sharedUi.macOSColors.text.disabled},searchRow:{flexDirection:"row",alignItems:"center",gap:6,marginHorizontal:12,marginBottom:8,paddingHorizontal:10,paddingVertical:5,backgroundColor:_sharedUi.macOSColors.background.input,borderRadius:10,borderWidth:1,borderColor:_sharedUi.macOSColors.border.default},searchInput:{flex:1,color:_sharedUi.macOSColors.text.primary,fontSize:13,paddingVertical:2},listContent:{paddingTop:4}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NetworkConditionsControl=NetworkConditionsControl;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _store=require("./store");var _jsxRuntime=require("react/jsx-runtime");const options=[{profile:"normal",label:"No throttling"},{profile:"slow",label:"Slow"},{profile:"verySlow",label:"Very slow"},{profile:"offline",label:"Offline"}];const summaries={normal:"No added delay",slow:"+500 ms before each new request",verySlow:"+2 seconds before each new request",offline:"New requests fail before sending"};function NetworkConditionsControl({remote:i}){const b=(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.getNetworkCondition,_store.getNetworkCondition);const y=(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.conditionsCanApply,_store.conditionsCanApply);const[s,a]=(0,_react.useState)(false);const[g,u]=(0,_react.useState)();const[r,h]=(0,_react.useState)(false);const c=(0,_react.useRef)(false);const l=(0,_react.useRef)(true);(0,_react.useEffect)(()=>{l.current=true;return()=>{l.current=false}},[]);const t=i?i.profile:b;const n=i?i.available:y;const f=t!==null&&t!=="normal";const d=t==="offline"?_sharedUi.night.color.danger:f?_sharedUi.night.color.warning:_sharedUi.night.color.accent;async function x(e){if(!n||c.current)return;if(e===t){a(false);return}c.current=true;h(true);u(void 0);try{if(i)await i.onChange(e);else(0,_store.setNetworkCondition)(e);if(l.current)a(false)}catch(o){if(l.current)u(o instanceof Error?o.message:String(o))}finally{c.current=false;if(l.current)h(false)}}const p=options.find(e=>e.profile===t)?.label??"Unavailable";return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.container,testID:"buoy-network-throttling-screen",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.heading,children:"Connection profile"}),(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:"buoy-network-conditions",accessibilityRole:"button",accessibilityLabel:`Network throttling: ${p}`,accessibilityState:{expanded:s,disabled:!n||r},disabled:!n||r,onPress:()=>a(e=>!e),style:[styles.dropdown,s&&styles.dropdownOpen,!n&&styles.disabled],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.value,f&&{color:d}],children:p}),r?(0,_jsxRuntime.jsx)(_reactNative.ActivityIndicator,{size:"small",color:_sharedUi.night.color.textSecondary}):(0,_jsxRuntime.jsx)(_sharedUi.ChevronDown,{size:16,color:_sharedUi.night.color.textSecondary})]}),s&&(0,_jsxRuntime.jsx)(_reactNative.View,{accessibilityRole:"radiogroup",accessibilityLabel:"Connection profile",style:styles.options,children:options.map(e=>{const o=t===e.profile;return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:`buoy-network-condition-${e.profile}`,accessibilityRole:"radio",accessibilityLabel:e.label,accessibilityState:{checked:o,disabled:!n||r},disabled:!n||r,onPress:()=>void x(e.profile),style:[styles.option,o&&styles.selected],children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.optionBody,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.optionTitle,o&&{color:d}],children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.caption,children:summaries[e.profile]})]}),o&&(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:16,color:d})]},e.profile)})}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.caption,accessibilityLiveRegion:"polite",children:r?"Applying to device\u2026":!n?i?"Conditions unavailable on this device":"Requires a signed-in account and a development build":t?summaries[t]:"Waiting for device status"}),!!g&&(0,_jsxRuntime.jsx)(_reactNative.Text,{accessibilityRole:"alert",style:styles.error,children:g}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.help,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.heading,children:"How it works"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.caption,children:"Affects new HTTP requests through global fetch and XHR. Slow adds a wait before sending; download speed stays unchanged."}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.caption,children:"Stays active when you close this tool or pause capture. Choose No throttling to stop. Reloading the app resets it."})]})]})}const styles=_reactNative.StyleSheet.create({container:{padding:_sharedUi.night.gutter,gap:10},heading:{fontSize:_sharedUi.night.font.caption,fontWeight:"600",color:_sharedUi.night.color.textSecondary},dropdown:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:44,paddingHorizontal:12,paddingVertical:10,borderRadius:_sharedUi.night.radius.segment,borderWidth:1,borderColor:_sharedUi.night.color.separator,backgroundColor:_sharedUi.night.color.surfaceElevated},dropdownOpen:{borderColor:_sharedUi.night.color.accentBorderStrong},value:{flex:1,fontSize:_sharedUi.night.font.body,color:_sharedUi.night.color.text},options:{padding:4,borderRadius:_sharedUi.night.radius.row,borderWidth:1,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface},option:{flexDirection:"row",alignItems:"center",gap:12,minHeight:54,padding:10,borderRadius:_sharedUi.night.radius.segment},optionBody:{flex:1,gap:4},optionTitle:{fontSize:_sharedUi.night.font.caption,fontWeight:"600",color:_sharedUi.night.color.text},selected:{backgroundColor:_sharedUi.night.color.surfaceElevated},disabled:{opacity:.45},caption:{fontSize:_sharedUi.night.font.caption,lineHeight:19,color:_sharedUi.night.color.textSecondary},help:{marginTop:14,paddingTop:16,gap:10,borderTopWidth:1,borderTopColor:_sharedUi.night.color.separator},error:{fontSize:_sharedUi.night.font.caption,lineHeight:18,color:_sharedUi.night.color.danger}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NetworkConditionsControl=NetworkConditionsControl;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _store=require("./store");var _jsxRuntime=require("react/jsx-runtime");const options=[{profile:"normal",label:"No throttling"},{profile:"slow",label:"Slow"},{profile:"verySlow",label:"Very slow"},{profile:"offline",label:"Offline"},{profile:"slow3g",label:"Slow 3G"},{profile:"slow4g",label:"Slow 4G"},{profile:"fast4g",label:"Fast 4G"}];const summaries={normal:"No added delay",slow:"+500 ms before each new request",verySlow:"+2 seconds before each new request",offline:"New requests fail before sending",slow3g:"50 KB/s down, 50 KB/s up; +2000 ms",slow4g:"180 KB/s down, 84.375 KB/s up; +562.5 ms",fast4g:"1012.5 KB/s down, 168.75 KB/s up; +165 ms"};function NetworkConditionsControl({remote:t,compact:v=false}){(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.getConditionsRevision,_store.getConditionsRevision);const o=t?t.state:(0,_store.getNetworkConditions)();const[j,y]=(0,_react.useState)(false);const T=(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.getNetworkCondition,_store.getNetworkCondition);const N=(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.conditionsCanApply,_store.conditionsCanApply);const[f,h]=(0,_react.useState)(false);const[w,p]=(0,_react.useState)();const[r,u]=(0,_react.useState)(false);const c=(0,_react.useRef)(false);const l=(0,_react.useRef)(true);const s=(0,_react.useRef)(0);(0,_react.useEffect)(()=>{s.current++;c.current=false;u(false);p(void 0)},[t?.targetId]);(0,_react.useEffect)(()=>{l.current=true;return()=>{l.current=false}},[]);const a=t?t.profile:T;const n=t?t.available:N;const x=o?.active??(a!==null&&a!=="normal");const g=a==="offline"?_sharedUi.night.color.danger:x?_sharedUi.night.color.warning:_sharedUi.night.color.accent;async function R(e){if(!n||c.current)return;if(e===a&&(e!=="normal"||!o?.active)){h(false);return}const i=++s.current;c.current=true;u(true);p(void 0);try{if(t)await t.onChange(e);else(0,_store.setNetworkCondition)(e);if(l.current&&s.current===i)h(false)}catch(d){if(l.current&&s.current===i)p(d instanceof Error?d.message:String(d))}finally{if(s.current===i){c.current=false;if(l.current)u(false)}}}const k=[["auto","Follow speed"],["real","Real link"],["offline","Offline"],["wifi","Wi-Fi"],["cellular","Cellular"],["noInternet","No internet"]];const S=(!t||!!t.onConnectionChange)&&(o?.capabilities.netInfo.supported||o?.capabilities.expoNetwork.supported);const C=options.find(e=>e.profile===a)?.label??"Unavailable";return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.container,testID:"buoy-network-throttling-screen",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.heading,children:"Connection profile"}),(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:"buoy-network-conditions",accessibilityRole:"button",accessibilityLabel:`Network throttling: ${C}`,accessibilityState:{expanded:f,disabled:!n||r},disabled:!n||r,onPress:()=>h(e=>!e),style:[styles.dropdown,f&&styles.dropdownOpen,!n&&styles.disabled],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.value,x&&{color:g}],children:C}),r?(0,_jsxRuntime.jsx)(_reactNative.ActivityIndicator,{size:"small",color:_sharedUi.night.color.textSecondary}):(0,_jsxRuntime.jsx)(_sharedUi.ChevronDown,{size:16,color:_sharedUi.night.color.textSecondary})]}),f&&(0,_jsxRuntime.jsx)(_reactNative.View,{accessibilityRole:"radiogroup",accessibilityLabel:"Connection profile",style:styles.options,children:options.map(e=>{const i=a===e.profile;return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:`buoy-network-condition-${e.profile}`,accessibilityRole:"radio",accessibilityLabel:e.label,accessibilityState:{checked:i,disabled:!n||r},disabled:!n||r,onPress:()=>void R(e.profile),style:[styles.option,i&&styles.selected],children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.optionBody,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.optionTitle,i&&{color:g}],children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.caption,children:summaries[e.profile]})]}),i&&(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:16,color:g})]},e.profile)})}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.caption,accessibilityLiveRegion:"polite",children:r?"Applying to device\u2026":!n?t?"Conditions unavailable on this device":"Requires a signed-in account and a development build":a?summaries[a]:"Waiting for device status"}),!!w&&(0,_jsxRuntime.jsx)(_reactNative.Text,{accessibilityRole:"alert",style:styles.error,children:w}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:"buoy-network-link-state",accessibilityRole:"button",accessibilityLabel:"App link state",disabled:!n||r||!S,onPress:()=>y(e=>!e),style:styles.dropdown,children:(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.value,children:["App link: ",k.find(([e])=>e===o?.connection)?.[1]??"Unavailable"]})}),j&&k.map(([e,i])=>(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:`buoy-network-link-${e}`,accessibilityRole:"radio",accessibilityState:{checked:o?.connection===e,disabled:r||!n},disabled:r||!n,style:styles.option,onPress:async()=>{if(c.current)return;const d=++s.current;c.current=true;u(true);p(void 0);try{if(t)await t.onConnectionChange?.(e);else(0,_store.setNetworkConditions)({connection:e});if(l.current&&s.current===d)y(false)}catch(b){if(l.current&&s.current===d)p(b instanceof Error?b.message:String(b))}finally{if(s.current===d){c.current=false;if(l.current)u(false)}}},children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.optionTitle,children:i})},e)),!S&&(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.caption,children:o?.capabilities.netInfo.reason??"This device has no link hook."}),!v&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.help,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.heading,children:"How it works"}),o&&(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.caption,children:["NetInfo: ",o.capabilities.netInfo.supported?"Hook on":o.capabilities.netInfo.reason??"No hook",". Expo Network: ",o.capabilities.expoNetwork.supported?"Hook on":o.capabilities.expoNetwork.reason??"No hook","."]}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.caption,children:"Down caps pace bytes to the app in JS. The socket stays at its real speed."}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.caption,children:"Up caps wait before send for known bytes. Upload time is simulated. The socket is not paced. Unknown sizes pass through with latency only. Each call shows any cap gap."}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.caption,children:"Caps apply per call through global fetch and RN XHR. WebSocket, native images, native SDKs and file transfers are not affected."}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.caption,children:"Link state changes what NetInfo and Expo Network report. It does not change the radio or web calls."}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.caption,children:"Stays on when this tool closes or capture pauses. No throttling clears both controls. App reload clears them too."})]})]})}const styles=_reactNative.StyleSheet.create({container:{padding:_sharedUi.night.gutter,gap:10},heading:{fontSize:_sharedUi.night.font.caption,fontWeight:"600",color:_sharedUi.night.color.textSecondary},dropdown:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:12,minHeight:44,paddingHorizontal:12,paddingVertical:10,borderRadius:_sharedUi.night.radius.segment,borderWidth:1,borderColor:_sharedUi.night.color.separator,backgroundColor:_sharedUi.night.color.surfaceElevated},dropdownOpen:{borderColor:_sharedUi.night.color.accentBorderStrong},value:{flex:1,fontSize:_sharedUi.night.font.body,color:_sharedUi.night.color.text},options:{padding:4,borderRadius:_sharedUi.night.radius.row,borderWidth:1,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface},option:{flexDirection:"row",alignItems:"center",gap:12,minHeight:54,padding:10,borderRadius:_sharedUi.night.radius.segment},optionBody:{flex:1,gap:4},optionTitle:{fontSize:_sharedUi.night.font.caption,fontWeight:"600",color:_sharedUi.night.color.text},selected:{backgroundColor:_sharedUi.night.color.surfaceElevated},disabled:{opacity:.45},caption:{fontSize:_sharedUi.night.font.caption,lineHeight:19,color:_sharedUi.night.color.textSecondary},help:{marginTop:14,paddingTop:16,gap:10,borderTopWidth:1,borderTopColor:_sharedUi.night.color.separator},error:{fontSize:_sharedUi.night.font.caption,lineHeight:18,color:_sharedUi.night.color.danger}});
@@ -1 +1 @@
1
- "use strict";var _react=require("react");var _client=require("react-dom/client");var _vitest=require("vitest");var _NetworkConditionsControl=require("./NetworkConditionsControl");_vitest.vi.mock("@buoy-gg/shared-ui",async()=>({ChevronDown:()=>null,Check:()=>null,night:(await _vitest.vi.importActual("../../../../shared/src/ui/night/nightTheme")).night}));_vitest.vi.mock("react-native",()=>({StyleSheet:{create:e=>e},View:({children:e})=>(0,_react.createElement)("div",null,e),Text:({children:e})=>(0,_react.createElement)("span",null,e),ActivityIndicator:()=>(0,_react.createElement)("span",null,"pending"),TouchableOpacity:({children:e,onPress:t,disabled:o,accessibilityLabel:n,accessibilityState:a,testID:l})=>(0,_react.createElement)("button",{onClick:t,disabled:o,"aria-label":n,"aria-checked":a?.checked,"data-testid":l},e)}));_vitest.vi.mock("./store",()=>({NETWORK_CONDITIONS:{normal:{label:"Normal"},slow:{label:"Slow"},verySlow:{label:"Very slow"},offline:{label:"Offline"}},getNetworkCondition:()=>"normal",conditionsCanApply:()=>true,subscribeNetworkConditions:()=>()=>{},setNetworkCondition:_vitest.vi.fn()}));let root;let container;(0,_vitest.beforeEach)(()=>{globalThis.IS_REACT_ACT_ENVIRONMENT=true;container=document.createElement("div");root=(0,_client.createRoot)(container)});(0,_vitest.afterEach)(()=>(0,_react.act)(()=>root.unmount()));const button=e=>container.querySelector(`[data-testid="buoy-network-condition-${e}"]`);function render(e){(0,_react.act)(()=>root.render((0,_react.createElement)(_NetworkConditionsControl.NetworkConditionsControl,{remote:e})))}const dropdown=()=>container.querySelector('[data-testid="buoy-network-conditions"]');const open=()=>(0,_react.act)(()=>dropdown().click());(0,_vitest.it)("defaults to a closed No throttling dropdown and closes when the current option is chosen",()=>{const e=_vitest.vi.fn();render({profile:"normal",available:true,onChange:e});(0,_vitest.expect)(dropdown().textContent).toBe("No throttling");(0,_vitest.expect)(button("normal")).toBeNull();open();(0,_vitest.expect)(["normal","slow","verySlow","offline"].every(t=>!!button(t))).toBe(true);(0,_react.act)(()=>button("normal").click());(0,_vitest.expect)(button("normal")).toBeNull();(0,_vitest.expect)(e).not.toHaveBeenCalled()});(0,_vitest.it)("blocks duplicate remote changes and waits for the device profile before selecting it",async()=>{let e;const t=_vitest.vi.fn(()=>new Promise(o=>{e=o}));render({profile:"normal",available:true,onChange:t});open();(0,_react.act)(()=>button("slow").click());(0,_vitest.expect)(button("offline").disabled).toBe(true);(0,_vitest.expect)(button("normal").getAttribute("aria-checked")).toBe("true");(0,_react.act)(()=>button("offline").click());(0,_vitest.expect)(t).toHaveBeenCalledExactlyOnceWith("slow");await(0,_react.act)(async()=>e());render({profile:"slow",available:true,onChange:t});(0,_vitest.expect)(dropdown().textContent).toBe("Slow");(0,_vitest.expect)(button("slow")).toBeNull();open();(0,_vitest.expect)(button("slow").getAttribute("aria-checked")).toBe("true")});(0,_vitest.it)("reports a remote error, permits retry, and disables unavailable devices",async()=>{const e=_vitest.vi.fn().mockRejectedValue(new Error("Device disconnected"));render({profile:"normal",available:true,onChange:e});open();await(0,_react.act)(async()=>button("offline").click());(0,_vitest.expect)(container.textContent).toContain("Device disconnected");(0,_vitest.expect)(button("offline").disabled).toBe(false);render({profile:null,available:false,onChange:e});(0,_vitest.expect)(button("normal").disabled).toBe(true);(0,_vitest.expect)(container.textContent).toContain("Conditions unavailable on this device")});
1
+ "use strict";var _react=require("react");var _client=require("react-dom/client");var _vitest=require("vitest");var _NetworkConditionsControl=require("./NetworkConditionsControl");_vitest.vi.mock("@buoy-gg/shared-ui",async()=>({ChevronDown:()=>null,Check:()=>null,night:(await _vitest.vi.importActual("../../../../shared/src/ui/night/nightTheme")).night}));_vitest.vi.mock("react-native",()=>({StyleSheet:{create:e=>e},View:({children:e})=>(0,_react.createElement)("div",null,e),Text:({children:e})=>(0,_react.createElement)("span",null,e),ActivityIndicator:()=>(0,_react.createElement)("span",null,"pending"),TouchableOpacity:({children:e,onPress:t,disabled:o,accessibilityLabel:n,accessibilityState:a,testID:i})=>(0,_react.createElement)("button",{onClick:t,disabled:o,"aria-label":n,"aria-checked":a?.checked,"data-testid":i},e)}));_vitest.vi.mock("./store",()=>({NETWORK_CONDITIONS:{normal:{label:"Normal"},slow:{label:"Slow"},verySlow:{label:"Very slow"},offline:{label:"Offline"}},getConditionsRevision:()=>0,getNetworkConditions:()=>({capabilities:{netInfo:{supported:false},expoNetwork:{supported:false}}}),setNetworkConditions:_vitest.vi.fn(),getNetworkCondition:()=>"normal",conditionsCanApply:()=>true,subscribeNetworkConditions:()=>()=>{},setNetworkCondition:_vitest.vi.fn()}));let root;let container;(0,_vitest.beforeEach)(()=>{globalThis.IS_REACT_ACT_ENVIRONMENT=true;container=document.createElement("div");root=(0,_client.createRoot)(container)});(0,_vitest.afterEach)(()=>(0,_react.act)(()=>root.unmount()));const button=e=>container.querySelector(`[data-testid="buoy-network-condition-${e}"]`);function render(e){(0,_react.act)(()=>root.render((0,_react.createElement)(_NetworkConditionsControl.NetworkConditionsControl,{remote:e})))}const dropdown=()=>container.querySelector('[data-testid="buoy-network-conditions"]');const open=()=>(0,_react.act)(()=>dropdown().click());(0,_vitest.it)("defaults to a closed No throttling dropdown and closes when the current option is chosen",()=>{const e=_vitest.vi.fn();render({profile:"normal",available:true,onChange:e});(0,_vitest.expect)(dropdown().textContent).toBe("No throttling");(0,_vitest.expect)(button("normal")).toBeNull();open();(0,_vitest.expect)(["normal","slow","verySlow","offline"].every(t=>!!button(t))).toBe(true);(0,_react.act)(()=>button("normal").click());(0,_vitest.expect)(button("normal")).toBeNull();(0,_vitest.expect)(e).not.toHaveBeenCalled()});(0,_vitest.it)("blocks duplicate remote changes and waits for the device profile before selecting it",async()=>{let e;const t=_vitest.vi.fn(()=>new Promise(o=>{e=o}));render({profile:"normal",available:true,onChange:t});open();(0,_react.act)(()=>button("slow").click());(0,_vitest.expect)(button("offline").disabled).toBe(true);(0,_vitest.expect)(button("normal").getAttribute("aria-checked")).toBe("true");(0,_react.act)(()=>button("offline").click());(0,_vitest.expect)(t).toHaveBeenCalledExactlyOnceWith("slow");await(0,_react.act)(async()=>e());render({profile:"slow",available:true,onChange:t});(0,_vitest.expect)(dropdown().textContent).toBe("Slow");(0,_vitest.expect)(button("slow")).toBeNull();open();(0,_vitest.expect)(button("slow").getAttribute("aria-checked")).toBe("true")});(0,_vitest.it)("reports a remote error, permits retry, and disables unavailable devices",async()=>{const e=_vitest.vi.fn().mockRejectedValue(new Error("Device disconnected"));render({profile:"normal",available:true,onChange:e});open();await(0,_react.act)(async()=>button("offline").click());(0,_vitest.expect)(container.textContent).toContain("Device disconnected");(0,_vitest.expect)(button("offline").disabled).toBe(false);render({profile:null,available:false,onChange:e});(0,_vitest.expect)(button("normal").disabled).toBe(true);(0,_vitest.expect)(container.textContent).toContain("Conditions unavailable on this device")});(0,_vitest.it)("offers all v2 speed profiles on the remote control",async()=>{const e=_vitest.vi.fn().mockResolvedValue(void 0);render({profile:"normal",available:true,onChange:e});open();for(const t of["slow3g","slow4g","fast4g"])(0,_vitest.expect)(button(t)).not.toBeNull();await(0,_react.act)(async()=>button("slow4g").click());(0,_vitest.expect)(e).toHaveBeenCalledExactlyOnceWith("slow4g");(0,_vitest.expect)(container.textContent).toContain("socket is not paced")});(0,_vitest.it)("forwards a link change and keeps device readback as the selected state",async()=>{const e=_vitest.vi.fn().mockResolvedValue(void 0);const t={version:2,connection:"real",capabilities:{netInfo:{supported:true},expoNetwork:{supported:false}}};render({profile:"normal",available:true,onChange:_vitest.vi.fn(),state:t,onConnectionChange:e});(0,_react.act)(()=>container.querySelector('[data-testid="buoy-network-link-state"]').click());await(0,_react.act)(async()=>container.querySelector('[data-testid="buoy-network-link-cellular"]').click());(0,_vitest.expect)(e).toHaveBeenCalledExactlyOnceWith("cellular");(0,_vitest.expect)(container.textContent).toContain("App link: Real link")});(0,_vitest.it)("shows a late peer gap even when the other hook works",()=>{const e={version:2,connection:"real",capabilities:{netInfo:{supported:false,reason:"Link hook loaded too late."},expoNetwork:{supported:true}}};render({profile:"normal",available:true,onChange:_vitest.vi.fn(),state:e,onConnectionChange:_vitest.vi.fn()});(0,_vitest.expect)(container.textContent).toContain("NetInfo: Link hook loaded too late.");(0,_vitest.expect)(container.textContent).toContain("Expo Network: Hook on")});(0,_vitest.it)("ignores an old device action result after switching devices",async()=>{let e;render({targetId:"first",profile:"normal",available:true,onChange:()=>new Promise((t,o)=>{e=o})});open();(0,_react.act)(()=>button("slow3g").click());render({targetId:"second",profile:"fast4g",available:true,onChange:_vitest.vi.fn()});await(0,_react.act)(async()=>e(new Error("Old device failed")));(0,_vitest.expect)(container.textContent).not.toContain("Old device failed");(0,_vitest.expect)(dropdown().textContent).toBe("Fast 4G");(0,_vitest.expect)(dropdown().disabled).toBe(false)});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NetworkConditionsIcon=NetworkConditionsIcon;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _store=require("./store");var _jsxRuntime=require("react/jsx-runtime");function NetworkConditionsIcon({size:t}){const e=(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.getNetworkCondition,_store.getNetworkCondition);return(0,_jsxRuntime.jsxs)(_reactNative.View,{accessibilityLabel:e==="normal"?"Network":`Network: ${_store.NETWORK_CONDITIONS[e].label}`,children:[(0,_jsxRuntime.jsx)(_sharedUi.NetworkIcon,{size:t}),e!=="normal"&&(0,_jsxRuntime.jsx)(_reactNative.View,{pointerEvents:"none",style:{position:"absolute",top:-6,right:-8,width:48,alignItems:"flex-end"},children:(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:"buoy-network-condition-indicator",numberOfLines:1,style:{color:"#FFCC66",fontSize:10,fontWeight:"700"},children:e==="offline"?"OFF":`+${_store.NETWORK_CONDITIONS[e].delayMs}`})})]})}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NetworkConditionsIcon=NetworkConditionsIcon;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _store=require("./store");var _jsxRuntime=require("react/jsx-runtime");function NetworkConditionsIcon({size:t}){(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.getConditionsRevision,_store.getConditionsRevision);const i=(0,_store.networkConditionsActive)();const e=(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.getNetworkCondition,_store.getNetworkCondition);return(0,_jsxRuntime.jsxs)(_reactNative.View,{accessibilityLabel:e==="normal"?"Network":`Network: ${_store.NETWORK_CONDITIONS[e].label}`,children:[(0,_jsxRuntime.jsx)(_sharedUi.NetworkIcon,{size:t}),i&&(0,_jsxRuntime.jsx)(_reactNative.View,{pointerEvents:"none",style:{position:"absolute",top:-6,right:-8,width:48,alignItems:"flex-end"},children:(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:"buoy-network-condition-indicator",numberOfLines:1,style:{color:"#FFCC66",fontSize:10,fontWeight:"700"},children:e==="normal"?"LINK":e==="offline"?"OFF":`+${_store.NETWORK_CONDITIONS[e].delayMs}`})})]})}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NetworkFloatingTool=NetworkFloatingTool;exports.createRemoteConditionsSource=createRemoteConditionsSource;exports.openNetworkFloatingTool=openNetworkFloatingTool;exports.registerLocalNetworkFloatingTool=registerLocalNetworkFloatingTool;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _store=require("./store");var _jsxRuntime=require("react/jsx-runtime");function createRemoteConditionsSource(){let i;const n=new Set;return{getSnapshot:()=>i,subscribe:r=>{n.add(r);return()=>{n.delete(r)}},update(r){i=r;n.forEach(t=>t())}}}const noSubscribe=()=>()=>{};const noRemote=()=>void 0;const options=[{id:"normal",label:"No throttling",detail:"No added delay"},{id:"slow",label:"Slow",detail:"+500 ms before sending"},{id:"verySlow",label:"Very slow",detail:"+2 seconds before sending"},{id:"offline",label:"Offline",detail:"New requests fail"}];const localRegistration={id:"network-throttling",render:i=>(0,_jsxRuntime.jsx)(NetworkFloatingTool,{...i})};function registerLocalNetworkFloatingTool(){if(typeof __DEV__==="undefined"||!__DEV__)return()=>{};return(0,_sharedUi.registerPersistentFloatingTool)(localRegistration,_sharedUi.persistentStorage)}if(typeof __DEV__!=="undefined"&&__DEV__&&typeof navigator!=="undefined"&&navigator.product==="ReactNative"){registerLocalNetworkFloatingTool()}function openNetworkFloatingTool(i){(0,_sharedUi.openFloatingTool)({id:"network-throttling",render:n=>(0,_jsxRuntime.jsx)(NetworkFloatingTool,{...n,source:i})})}function NetworkFloatingTool({id:i,revealToken:n,dismiss:r,source:t}){const k=(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.getNetworkCondition,_store.getNetworkCondition);const _=(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.conditionsCanApply,_store.conditionsCanApply);const g=(0,_react.useSyncExternalStore)(t?.subscribe??noSubscribe,t?.getSnapshot??noRemote,noRemote);const c=t?g?.profile??null:k;const d=t?g?.available===true:_;const[l,f]=(0,_react.useState)(false);const[x,h]=(0,_react.useState)();const u=(0,_react.useRef)(false);const a=(0,_react.useRef)(0);const s=(0,_react.useRef)(true);const{width:j}=(0,_reactNative.useWindowDimensions)();(0,_react.useEffect)(()=>{s.current=true;return()=>{s.current=false}},[]);(0,_react.useEffect)(()=>{a.current+=1;u.current=false;f(false);h(void 0)},[t,g?.targetId]);const C=c!==null&&c!=="normal";const e=c??"normal";const b=options.find(o=>o.id===e);const m=options[(options.findIndex(o=>o.id===e)+1)%options.length];const R=!d||e==="offline"?0:e==="verySlow"?1:e==="slow"?2:4;const T=l?"Applying\u2026":!d?"Unavailable":e==="normal"?"0 ms":e==="slow"?"+500 ms":e==="verySlow"?"+2000 ms":"Blocked";async function S(o,p=false){if(u.current)return;const y=++a.current;u.current=true;f(true);h(void 0);const v=t?.getSnapshot();try{if(t){if(!v?.available)throw new Error("Device unavailable. Open Network again to reconnect these controls.");await v.onChange(o)}else(0,_store.setNetworkCondition)(o);if(s.current&&a.current===y){if(p)r()}}catch(w){if(s.current&&a.current===y)h(w instanceof Error?w.message:String(w))}finally{if(a.current===y){u.current=false;if(s.current)f(false)}}}const N=x?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.menu,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{accessibilityRole:"alert",style:styles.error,children:x})}):void 0;return(0,_jsxRuntime.jsx)(_sharedUi.FloatingTool,{id:i,revealToken:n,variant:"strip",dragFromSurface:true,accessibilityLabel:`Move or hide network throttling. ${C?"Active":"Off"}`,accessory:N,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.row,{width:Math.max(220,Math.min(292,j-64))}],children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:"throttling-cycle",accessibilityRole:"button",accessibilityLabel:`Network: ${b.label}. Switch to ${m.label}`,accessibilityState:{disabled:l||!d},disabled:l||!d,onPress:()=>void S(m.id),style:styles.signalButton,children:l?(0,_jsxRuntime.jsx)(_reactNative.ActivityIndicator,{size:"small",color:_sharedUi.night.color.accent}):(0,_jsxRuntime.jsxs)(_reactNative.View,{testID:`throttling-signal-${e}`,style:styles.signal,children:[[7,12,18,24].map((o,p)=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:{width:4,height:o,borderRadius:2,backgroundColor:p<R?e==="offline"?_sharedUi.night.color.danger:_sharedUi.night.color.accent:_sharedUi.night.color.fillTertiary}},o)),e==="offline"&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.slash})]})}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.profile,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:"throttling-profile",accessibilityLabel:`Connection profile: ${b.label}`,accessibilityLiveRegion:"polite",numberOfLines:1,style:styles.profileLabel,children:b.label})}),(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:"throttling-status",numberOfLines:1,accessibilityLiveRegion:"polite",style:styles.status,children:T}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.separator}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:"throttling-close",accessibilityRole:"button",accessibilityLabel:"Close and turn off throttling",disabled:l,accessibilityState:{disabled:l},onPress:()=>{if(c==="normal")r();else void S("normal",true)},style:[styles.action,l&&styles.disabled],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:"Close"})})]})})}const styles=_reactNative.StyleSheet.create({row:{flexDirection:"row",alignItems:"center",gap:6,paddingVertical:4,minHeight:48},signalButton:{width:36,minHeight:44,alignItems:"center",justifyContent:"center"},signal:{flexDirection:"row",alignItems:"flex-end",gap:3,height:24},slash:{position:"absolute",width:30,height:2,backgroundColor:_sharedUi.night.color.danger,top:11,left:-2,transform:[{rotate:"-45deg"}]},separator:{height:20,width:1,backgroundColor:_sharedUi.night.color.separator,marginHorizontal:2},status:{color:_sharedUi.night.color.textSecondary,fontSize:10,lineHeight:15,flexShrink:1},profile:{flex:1,flexDirection:"row",alignItems:"center",gap:6,minHeight:44},profileLabel:{color:_sharedUi.night.color.text,fontSize:13,fontWeight:"500",flexShrink:1},action:{minHeight:36,minWidth:52,borderRadius:_sharedUi.night.radius.input,borderWidth:1,borderColor:_sharedUi.night.color.accentBorderStrong,alignItems:"center",justifyContent:"center",paddingHorizontal:10},actionText:{color:_sharedUi.night.color.accent,fontSize:12,fontWeight:"600"},disabled:{opacity:.4},menu:{marginVertical:8,padding:6,borderRadius:_sharedUi.night.radius.card,borderWidth:1,borderColor:_sharedUi.night.color.separator,backgroundColor:_sharedUi.night.color.surface,shadowColor:"#000",shadowOffset:{width:0,height:6},shadowOpacity:.25,shadowRadius:16,elevation:8},error:{color:_sharedUi.night.color.danger,fontSize:12,lineHeight:18,padding:10}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NetworkFloatingTool=NetworkFloatingTool;exports.createRemoteConditionsSource=createRemoteConditionsSource;exports.openNetworkFloatingTool=openNetworkFloatingTool;exports.registerLocalNetworkFloatingTool=registerLocalNetworkFloatingTool;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _store=require("./store");var _NetworkConditionsControl=require("./NetworkConditionsControl");var _jsxRuntime=require("react/jsx-runtime");function createRemoteConditionsSource(){let n;const r=new Set;return{getSnapshot:()=>n,subscribe:o=>{r.add(o);return()=>{r.delete(o)}},update(o){n=o;r.forEach(t=>t())}}}const noSubscribe=()=>()=>{};const noRemote=()=>void 0;const options=[{id:"normal",label:"No throttling",detail:"No added delay"},{id:"slow",label:"Slow",detail:"+500 ms before sending"},{id:"verySlow",label:"Very slow",detail:"+2 seconds before sending"},{id:"offline",label:"Offline",detail:"New requests fail"}];const localRegistration={id:"network-throttling",render:n=>(0,_jsxRuntime.jsx)(NetworkFloatingTool,{...n})};function registerLocalNetworkFloatingTool(){if(typeof __DEV__==="undefined"||!__DEV__)return()=>{};return(0,_sharedUi.registerPersistentFloatingTool)(localRegistration,_sharedUi.persistentStorage)}if(typeof __DEV__!=="undefined"&&__DEV__&&typeof navigator!=="undefined"&&navigator.product==="ReactNative"){registerLocalNetworkFloatingTool()}function openNetworkFloatingTool(n,r=false){(0,_sharedUi.openFloatingTool)({id:"network-throttling",render:o=>(0,_jsxRuntime.jsx)(NetworkFloatingTool,{...o,source:n,showControls:r})})}function NetworkFloatingTool({id:n,revealToken:r,dismiss:o,source:t,showControls:f=false}){(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.getConditionsRevision,_store.getConditionsRevision);const R=(0,_store.getNetworkConditions)();const E=(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.getNetworkCondition,_store.getNetworkCondition);const O=(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.conditionsCanApply,_store.conditionsCanApply);const s=(0,_react.useSyncExternalStore)(t?.subscribe??noSubscribe,t?.getSnapshot??noRemote,noRemote);const h=t?s?.profile??null:E;const u=t?s?.available===true:O;const[a,C]=(0,_react.useState)(f);(0,_react.useEffect)(()=>{C(f)},[f,r]);const[l,b]=(0,_react.useState)(false);const[y,p]=(0,_react.useState)();const g=(0,_react.useRef)(false);const c=(0,_react.useRef)(0);const d=(0,_react.useRef)(true);const{width:k,height:D}=(0,_reactNative.useWindowDimensions)();(0,_react.useEffect)(()=>{d.current=true;return()=>{d.current=false}},[]);(0,_react.useEffect)(()=>{c.current+=1;g.current=false;b(false);p(void 0)},[t,s?.targetId]);const w=t?s?.state?.active??(h!==null&&h!=="normal"):R.active;const e=h??"normal";const x=options.find(i=>i.id===e)??{label:_store.NETWORK_CONDITIONS[e].label};const N=options[(options.findIndex(i=>i.id===e)+1)%options.length];const I=!u||e==="offline"?0:e==="verySlow"?1:e==="slow"?2:4;const V=l?"Applying\u2026":!u?"Unavailable":e==="normal"?w?"Link set":"0 ms":e==="slow"?"+500 ms":e==="verySlow"?"+2000 ms":e==="offline"?"Blocked":`${Math.round((_store.NETWORK_CONDITIONS[e].downloadBytesPerSecond??0)/1e3)} kB/s`;async function j(i,m=false){if(g.current)return;const S=++c.current;g.current=true;b(true);p(void 0);const T=t?.getSnapshot();try{if(t){if(!T?.available)throw new Error("Device unavailable. Open Network again to reconnect these controls.");await T.onChange(i)}else(0,_store.setNetworkCondition)(i);if(d.current&&c.current===S){if(m)o()}}catch(v){if(d.current&&c.current===S)p(v instanceof Error?v.message:String(v))}finally{if(c.current===S){g.current=false;if(d.current)b(false)}}}const _=y||a?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.menu,children:[!!y&&(0,_jsxRuntime.jsx)(_reactNative.Text,{accessibilityRole:"alert",style:styles.error,children:y}),a&&(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{testID:"throttling-controls-scroll",style:{maxHeight:Math.min(420,D-180)},children:(0,_jsxRuntime.jsx)(_NetworkConditionsControl.NetworkConditionsControl,{remote:t?s??{profile:null,available:false,onChange:async()=>{throw new Error("Device unavailable.")}}:void 0})})]}):void 0;return(0,_jsxRuntime.jsx)(_sharedUi.FloatingTool,{id:n,revealToken:r,variant:"strip",dragFromSurface:_reactNative.Platform.OS!=="android"||!a,accessibilityLabel:`Move or hide network throttling. ${w?"Active":"Off"}`,accessory:_reactNative.Platform.OS==="android"?void 0:_,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:{width:Math.max(220,Math.min(336,k-64))},children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.row,{width:Math.max(220,Math.min(336,k-64))}],children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:"throttling-cycle",accessibilityRole:"button",accessibilityLabel:`Network: ${x.label}. Switch to ${N.label}`,accessibilityState:{disabled:l||!u},disabled:l||!u,onPress:()=>void j(N.id),style:styles.signalButton,children:l?(0,_jsxRuntime.jsx)(_reactNative.ActivityIndicator,{size:"small",color:_sharedUi.night.color.accent}):(0,_jsxRuntime.jsxs)(_reactNative.View,{testID:`throttling-signal-${e}`,style:styles.signal,children:[[7,12,18,24].map((i,m)=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:{width:4,height:i,borderRadius:2,backgroundColor:m<I?e==="offline"?_sharedUi.night.color.danger:_sharedUi.night.color.accent:_sharedUi.night.color.fillTertiary}},i)),e==="offline"&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.slash})]})}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.profile,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:"throttling-profile",accessibilityLabel:`Connection profile: ${x.label}`,accessibilityLiveRegion:"polite",numberOfLines:1,style:styles.profileLabel,children:x.label})}),(0,_jsxRuntime.jsx)(_reactNative.Text,{testID:"throttling-status",numberOfLines:1,accessibilityLiveRegion:"polite",style:styles.status,children:V}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:"throttling-edit",accessibilityRole:"button",accessibilityLabel:a?"Hide speed and link controls":"Edit speed and link state",onPress:()=>C(i=>!i),style:styles.action,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:a?"Done":"Edit"})}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.separator}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{testID:"throttling-close",accessibilityRole:"button",accessibilityLabel:"Close and turn off throttling",disabled:l,accessibilityState:{disabled:l},onPress:()=>{if(!w)o();else void j("normal",true)},style:[styles.action,l&&styles.disabled],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.actionText,children:"Close"})})]}),_reactNative.Platform.OS==="android"&&_]})})}const styles=_reactNative.StyleSheet.create({row:{flexDirection:"row",alignItems:"center",gap:6,paddingVertical:4,minHeight:48},signalButton:{width:36,minHeight:44,alignItems:"center",justifyContent:"center"},signal:{flexDirection:"row",alignItems:"flex-end",gap:3,height:24},slash:{position:"absolute",width:30,height:2,backgroundColor:_sharedUi.night.color.danger,top:11,left:-2,transform:[{rotate:"-45deg"}]},separator:{height:20,width:1,backgroundColor:_sharedUi.night.color.separator,marginHorizontal:2},status:{color:_sharedUi.night.color.textSecondary,fontSize:10,lineHeight:15,flexShrink:1},profile:{flex:1,flexDirection:"row",alignItems:"center",gap:6,minHeight:44},profileLabel:{color:_sharedUi.night.color.text,fontSize:13,fontWeight:"500",flexShrink:1},action:{minHeight:36,minWidth:52,borderRadius:_sharedUi.night.radius.input,borderWidth:1,borderColor:_sharedUi.night.color.accentBorderStrong,alignItems:"center",justifyContent:"center",paddingHorizontal:10},actionText:{color:_sharedUi.night.color.accent,fontSize:12,fontWeight:"600"},disabled:{opacity:.4},menu:{marginVertical:8,padding:6,borderRadius:_sharedUi.night.radius.card,borderWidth:1,borderColor:_sharedUi.night.color.separator,backgroundColor:_sharedUi.night.color.surface,shadowColor:"#000",shadowOffset:{width:0,height:6},shadowOpacity:.25,shadowRadius:16,elevation:8},error:{color:_sharedUi.night.color.danger,fontSize:12,lineHeight:18,padding:10}});
@@ -1 +1 @@
1
- "use strict";var _react=require("react");var _client=require("react-dom/client");var _vitest=require("vitest");var _NetworkFloatingTool=require("./NetworkFloatingTool");const state=_vitest.vi.hoisted(()=>({profile:"normal",available:true,listeners:new Set,set:_vitest.vi.fn()}));_vitest.vi.mock("./store",()=>({getNetworkCondition:()=>state.profile,conditionsCanApply:()=>state.available,subscribeNetworkConditions:e=>{state.listeners.add(e);return()=>state.listeners.delete(e)},setNetworkCondition:e=>{state.set(e);state.profile=e;state.listeners.forEach(t=>t())}}));_vitest.vi.mock("@buoy-gg/shared-ui",async()=>({night:(await _vitest.vi.importActual("../../../../shared/src/ui/night/nightTheme")).night,ChevronDown:()=>null,Check:()=>null,openFloatingTool:_vitest.vi.fn(),FloatingTool:({children:e,accessory:t})=>(0,_react.createElement)("div",null,e,t)}));_vitest.vi.mock("react-native",()=>({StyleSheet:{create:e=>e},useWindowDimensions:()=>({width:390,height:844}),View:({children:e,testID:t})=>(0,_react.createElement)("div",{"data-testid":t},e),Text:({children:e,testID:t})=>(0,_react.createElement)("span",{"data-testid":t},e),ActivityIndicator:()=>null,TouchableOpacity:({children:e,onPress:t,disabled:o,testID:a,accessibilityLabel:n})=>(0,_react.createElement)("button",{onClick:t,disabled:o,"data-testid":a,"aria-label":n},e)}));let root;let container;const dismiss=_vitest.vi.fn();(0,_vitest.beforeEach)(()=>{globalThis.IS_REACT_ACT_ENVIRONMENT=true;state.profile="normal";state.available=true;state.set.mockClear();dismiss.mockClear();container=document.createElement("div");root=(0,_client.createRoot)(container)});(0,_vitest.afterEach)(()=>(0,_react.act)(()=>root.unmount()));const button=e=>container.querySelector(`[data-testid="${e}"]`);const tap=async e=>(0,_react.act)(async()=>button(e).click());const status=()=>container.querySelector('[data-testid="throttling-status"]')?.textContent;function render(e){(0,_react.act)(()=>root.render((0,_react.createElement)(_NetworkFloatingTool.NetworkFloatingTool,{id:"network-throttling",revealToken:1,dismiss,source:e})))}async function choose(e){const t=["normal","slow","verySlow","offline"];const o=(t.indexOf(e)-t.indexOf(state.profile)+t.length)%t.length;for(let a=0;a<o;a++)await tap("throttling-cycle")}(0,_vitest.it)("cycles and applies every profile immediately, including wrapping to normal",async()=>{render();for(const[e,t]of[["slow","+500 ms"],["verySlow","+2000 ms"],["offline","Blocked"],["normal","0 ms"]]){await tap("throttling-cycle");(0,_vitest.expect)(state.profile).toBe(e);(0,_vitest.expect)(container.querySelector(`[data-testid="throttling-signal-${e}"]`)).not.toBeNull();(0,_vitest.expect)(status()).toBe(t)}(0,_vitest.expect)(state.set).toHaveBeenCalledTimes(4)});(0,_vitest.it)("keeps the profile label informational when tapped",async()=>{render();await tap("throttling-profile");(0,_vitest.expect)(state.set).not.toHaveBeenCalled();(0,_vitest.expect)(state.profile).toBe("normal");(0,_vitest.expect)(button("throttling-profile").closest("button")).toBeNull()});(0,_vitest.it)("changes active profiles and stops before dismissal",async()=>{state.profile="slow";render();await choose("offline");(0,_vitest.expect)(state.profile).toBe("offline");await tap("throttling-close");(0,_vitest.expect)(state.profile).toBe("normal");(0,_vitest.expect)(dismiss).toHaveBeenCalledOnce()});(0,_vitest.it)("reflects external changes and disables cycling when account admission is revoked",()=>{render();(0,_react.act)(()=>{state.profile="offline";state.listeners.forEach(e=>e())});(0,_vitest.expect)(status()).toBe("Blocked");(0,_react.act)(()=>{state.profile="normal";state.available=false;state.listeners.forEach(e=>e())});(0,_vitest.expect)(status()).toBe("Unavailable");(0,_vitest.expect)(button("throttling-cycle").disabled).toBe(true)});(0,_vitest.it)("keeps remote failures visible and does not claim a profile was applied",async()=>{const e=(0,_NetworkFloatingTool.createRemoteConditionsSource)();const t=_vitest.vi.fn().mockRejectedValue(new Error("Connection lost"));e.update({profile:"normal",available:true,onChange:t});render(e);await choose("slow");(0,_vitest.expect)(container.textContent).toContain("Connection lost");(0,_vitest.expect)(status()).toBe("0 ms");(0,_vitest.expect)(state.set).not.toHaveBeenCalled()});(0,_vitest.it)("prevents duplicate remote operations and follows confirmed snapshots",async()=>{const e=(0,_NetworkFloatingTool.createRemoteConditionsSource)();let t;const o=_vitest.vi.fn(()=>new Promise(a=>{t=a}));e.update({profile:"normal",available:true,onChange:o});render(e);await tap("throttling-cycle");await tap("throttling-cycle");(0,_vitest.expect)(o).toHaveBeenCalledOnce();(0,_vitest.expect)(status()).toBe("Applying\u2026");await(0,_react.act)(async()=>t());(0,_vitest.expect)(status()).toBe("0 ms");(0,_react.act)(()=>e.update({profile:"slow",available:true,onChange:o}));(0,_vitest.expect)(status()).toBe("+500 ms");(0,_react.act)(()=>e.update(void 0));(0,_vitest.expect)(status()).toBe("Unavailable")});(0,_vitest.it)("ignores a previous device's completion after switching devices",async()=>{const e=(0,_NetworkFloatingTool.createRemoteConditionsSource)();let t;e.update({targetId:"first",profile:"normal",available:true,onChange:()=>new Promise((o,a)=>{t=a})});render(e);await choose("slow");(0,_react.act)(()=>e.update({targetId:"second",profile:"normal",available:true,onChange:_vitest.vi.fn()}));await(0,_react.act)(async()=>t(new Error("Old device failed")));(0,_vitest.expect)(container.textContent).not.toContain("Old device failed");(0,_vitest.expect)(status()).toBe("0 ms");(0,_vitest.expect)(button("throttling-profile").textContent).toBe("No throttling")});(0,_vitest.it)("keeps the strip open when stopping a remote device fails",async()=>{const e=(0,_NetworkFloatingTool.createRemoteConditionsSource)();e.update({profile:"offline",available:true,onChange:_vitest.vi.fn().mockRejectedValue(new Error("Could not stop"))});render(e);await tap("throttling-close");(0,_vitest.expect)(dismiss).not.toHaveBeenCalled();(0,_vitest.expect)(status()).toBe("Blocked");(0,_vitest.expect)(container.textContent).toContain("Could not stop")});
1
+ "use strict";var _react=require("react");var _client=require("react-dom/client");var _vitest=require("vitest");var _NetworkFloatingTool=require("./NetworkFloatingTool");const state=_vitest.vi.hoisted(()=>({platform:"web",profile:"normal",available:true,listeners:new Set,set:_vitest.vi.fn()}));_vitest.vi.mock("./store",()=>({getConditionsRevision:()=>0,getNetworkConditions:()=>({active:state.profile!=="normal",capabilities:{netInfo:{supported:false},expoNetwork:{supported:false}}}),NETWORK_CONDITIONS:{fast4g:{label:"Fast 4G",downloadBytesPerSecond:1012500}},getNetworkCondition:()=>state.profile,conditionsCanApply:()=>state.available,subscribeNetworkConditions:e=>{state.listeners.add(e);return()=>state.listeners.delete(e)},setNetworkCondition:e=>{state.set(e);state.profile=e;state.listeners.forEach(t=>t())}}));_vitest.vi.mock("@buoy-gg/shared-ui",async()=>({night:(await _vitest.vi.importActual("../../../../shared/src/ui/night/nightTheme")).night,ChevronDown:()=>null,Check:()=>null,openFloatingTool:_vitest.vi.fn(),FloatingTool:({children:e,accessory:t})=>(0,_react.createElement)("div",null,e,t)}));_vitest.vi.mock("react-native",()=>({Platform:{get OS(){return state.platform}},StyleSheet:{create:e=>e},useWindowDimensions:()=>({width:390,height:844}),View:({children:e,testID:t})=>(0,_react.createElement)("div",{"data-testid":t},e),Text:({children:e,testID:t})=>(0,_react.createElement)("span",{"data-testid":t},e),ScrollView:({children:e})=>(0,_react.createElement)("div",null,e),ActivityIndicator:()=>null,TouchableOpacity:({children:e,onPress:t,disabled:o,testID:a,accessibilityLabel:n})=>(0,_react.createElement)("button",{onClick:t,disabled:o,"data-testid":a,"aria-label":n},e)}));let root;let container;const dismiss=_vitest.vi.fn();(0,_vitest.beforeEach)(()=>{globalThis.IS_REACT_ACT_ENVIRONMENT=true;state.platform="web";state.profile="normal";state.available=true;state.set.mockClear();dismiss.mockClear();container=document.createElement("div");root=(0,_client.createRoot)(container)});(0,_vitest.afterEach)(()=>(0,_react.act)(()=>root.unmount()));const button=e=>container.querySelector(`[data-testid="${e}"]`);const tap=async e=>(0,_react.act)(async()=>button(e).click());const status=()=>container.querySelector('[data-testid="throttling-status"]')?.textContent;function render(e){(0,_react.act)(()=>root.render((0,_react.createElement)(_NetworkFloatingTool.NetworkFloatingTool,{id:"network-throttling",revealToken:1,dismiss,source:e})))}async function choose(e){const t=["normal","slow","verySlow","offline"];const o=(t.indexOf(e)-t.indexOf(state.profile)+t.length)%t.length;for(let a=0;a<o;a++)await tap("throttling-cycle")}(0,_vitest.it)("cycles and applies every profile immediately, including wrapping to normal",async()=>{render();for(const[e,t]of[["slow","+500 ms"],["verySlow","+2000 ms"],["offline","Blocked"],["normal","0 ms"]]){await tap("throttling-cycle");(0,_vitest.expect)(state.profile).toBe(e);(0,_vitest.expect)(container.querySelector(`[data-testid="throttling-signal-${e}"]`)).not.toBeNull();(0,_vitest.expect)(status()).toBe(t)}(0,_vitest.expect)(state.set).toHaveBeenCalledTimes(4)});(0,_vitest.it)("keeps the profile label informational when tapped",async()=>{render();await tap("throttling-profile");(0,_vitest.expect)(state.set).not.toHaveBeenCalled();(0,_vitest.expect)(state.profile).toBe("normal");(0,_vitest.expect)(button("throttling-profile").closest("button")).toBeNull()});(0,_vitest.it)("changes active profiles and stops before dismissal",async()=>{state.profile="slow";render();await choose("offline");(0,_vitest.expect)(state.profile).toBe("offline");await tap("throttling-close");(0,_vitest.expect)(state.profile).toBe("normal");(0,_vitest.expect)(dismiss).toHaveBeenCalledOnce()});(0,_vitest.it)("reflects external changes and disables cycling when account admission is revoked",()=>{render();(0,_react.act)(()=>{state.profile="offline";state.listeners.forEach(e=>e())});(0,_vitest.expect)(status()).toBe("Blocked");(0,_react.act)(()=>{state.profile="normal";state.available=false;state.listeners.forEach(e=>e())});(0,_vitest.expect)(status()).toBe("Unavailable");(0,_vitest.expect)(button("throttling-cycle").disabled).toBe(true)});(0,_vitest.it)("keeps remote failures visible and does not claim a profile was applied",async()=>{const e=(0,_NetworkFloatingTool.createRemoteConditionsSource)();const t=_vitest.vi.fn().mockRejectedValue(new Error("Connection lost"));e.update({profile:"normal",available:true,onChange:t});render(e);await choose("slow");(0,_vitest.expect)(container.textContent).toContain("Connection lost");(0,_vitest.expect)(status()).toBe("0 ms");(0,_vitest.expect)(state.set).not.toHaveBeenCalled()});(0,_vitest.it)("prevents duplicate remote operations and follows confirmed snapshots",async()=>{const e=(0,_NetworkFloatingTool.createRemoteConditionsSource)();let t;const o=_vitest.vi.fn(()=>new Promise(a=>{t=a}));e.update({profile:"normal",available:true,onChange:o});render(e);await tap("throttling-cycle");await tap("throttling-cycle");(0,_vitest.expect)(o).toHaveBeenCalledOnce();(0,_vitest.expect)(status()).toBe("Applying\u2026");await(0,_react.act)(async()=>t());(0,_vitest.expect)(status()).toBe("0 ms");(0,_react.act)(()=>e.update({profile:"slow",available:true,onChange:o}));(0,_vitest.expect)(status()).toBe("+500 ms");(0,_react.act)(()=>e.update(void 0));(0,_vitest.expect)(status()).toBe("Unavailable")});(0,_vitest.it)("ignores a previous device's completion after switching devices",async()=>{const e=(0,_NetworkFloatingTool.createRemoteConditionsSource)();let t;e.update({targetId:"first",profile:"normal",available:true,onChange:()=>new Promise((o,a)=>{t=a})});render(e);await choose("slow");(0,_react.act)(()=>e.update({targetId:"second",profile:"normal",available:true,onChange:_vitest.vi.fn()}));await(0,_react.act)(async()=>t(new Error("Old device failed")));(0,_vitest.expect)(container.textContent).not.toContain("Old device failed");(0,_vitest.expect)(status()).toBe("0 ms");(0,_vitest.expect)(button("throttling-profile").textContent).toBe("No throttling")});(0,_vitest.it)("keeps the strip open when stopping a remote device fails",async()=>{const e=(0,_NetworkFloatingTool.createRemoteConditionsSource)();e.update({profile:"offline",available:true,onChange:_vitest.vi.fn().mockRejectedValue(new Error("Could not stop"))});render(e);await tap("throttling-close");(0,_vitest.expect)(dismiss).not.toHaveBeenCalled();(0,_vitest.expect)(status()).toBe("Blocked");(0,_vitest.expect)(container.textContent).toContain("Could not stop")});_vitest.it.each(["web","android"])("opens the full remote control on %s and forwards v2 changes",async e=>{state.platform=e;const t=(0,_NetworkFloatingTool.createRemoteConditionsSource)();const o=_vitest.vi.fn().mockResolvedValue(void 0);const a=_vitest.vi.fn().mockResolvedValue(void 0);const n={version:2,active:false,connection:"real",capabilities:{netInfo:{supported:true},expoNetwork:{supported:false}}};t.update({profile:"normal",available:true,onChange:o,onConnectionChange:a,state:n});render(t);await tap("throttling-edit");await tap("buoy-network-conditions");await tap("buoy-network-condition-fast4g");(0,_vitest.expect)(o).toHaveBeenCalledExactlyOnceWith("fast4g");(0,_vitest.expect)(status()).toBe("0 ms");(0,_react.act)(()=>t.update({profile:"fast4g",available:true,onChange:o,onConnectionChange:a,state:{...n,active:true}}));(0,_vitest.expect)(status()).toBe("1013 kB/s");await tap("buoy-network-link-state");await tap("buoy-network-link-cellular");(0,_vitest.expect)(a).toHaveBeenCalledExactlyOnceWith("cellular");await tap("throttling-edit");(0,_vitest.expect)(button("buoy-network-conditions")).toBeNull();(0,_vitest.expect)(status()).toBe("1013 kB/s")});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.wrapNetInfoApi=wrapNetInfoApi;var _react=require("react");var _store=require("../store");var _patchNetwork=require("./patchNetwork");function wrapNetInfoApi(o){const s=e=>(0,_patchNetwork.maskConnection)(e,(0,_store.getEffectiveNetworkConnection)());const n={};for(const e of["fetch","refresh"]){const t=o[e];n[e]=(...r)=>Promise.resolve(t(...r)).then(s)}const f=o.addEventListener;n.addEventListener=e=>f(t=>e(s(t)));const a=o.useNetInfo;n.useNetInfo=(...e)=>{const t=a(...e);(0,_react.useSyncExternalStore)(_store.subscribeNetworkConditions,_store.getConditionsRevision,_store.getConditionsRevision);return s(t)};const c=[];try{for(const[e,t]of Object.entries(n)){for(const r of new Set([o,o.default].filter(Boolean))){const i=Object.getOwnPropertyDescriptor(r,e);Object.defineProperty(r,e,{configurable:true,writable:true,enumerable:true,value:t});c.push(()=>{if(i)Object.defineProperty(r,e,i);else delete r[e]})}}}catch(e){c.reverse().forEach(t=>t());throw e}}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.maskConnection=maskConnection;exports.patchConnectionState=patchConnectionState;function maskConnection(t,n,o=false){if(n==="auto"||n==="real")return{...t};const r=n==="offline"?"none":n==="cellular"?"cellular":"wifi";return{type:o?r.toUpperCase():r,...!o?{details:n==="offline"?null:{isConnectionExpensive:n==="cellular",...n==="cellular"?{cellularGeneration:null,carrier:null}:{}}}:{},isConnected:n!=="offline",isInternetReachable:n!=="offline"&&n!=="noInternet"}}function patchConnectionState(t,n,o,r={}){const i=r.eventName??"netInfo.networkStatusDidChange";if((t.eventEmitter.listenerCount?.(i)??0)>0)throw new Error("Link hook loaded too late. Load it before app code, then reload.");const C=t.getCurrentState;const s=t.eventEmitter.addListener;const l=new Set;let a={type:r.expo?"UNKNOWN":"unknown",isConnected:null,isInternetReachable:null};let u=0;let f=false;let y=n();const d=e=>maskConnection(e,n(),r.expo);const p=()=>{if(!f)l.forEach(e=>e(d(a)))};const x=s.call(t.eventEmitter,i,e=>{u++;a=e;p()});const h=async(...e)=>{const c=u;const w=await C.apply(r.receiver??t,e);if(e[0])return d(w);if(c===u)a=w;return d(a)};const E=(e,c)=>{if(e!==i)return s.call(t.eventEmitter,e,c);l.add(c);return{remove:()=>{l.delete(c)}}};let S;const b=()=>{f=true;try{S?.()}finally{try{x.remove()}finally{l.clear();if(t.getCurrentState===h)t.getCurrentState=C;if(t.eventEmitter.addListener===E)t.eventEmitter.addListener=s}}};try{t.getCurrentState=h;t.eventEmitter.addListener=E;S=o(()=>{const e=n();if(e!==y){y=e;p()}})}catch(e){b();throw e}void h(...r.expo?[]:[void 0]).then(p).catch(()=>{});return()=>{if(f)return;try{l.forEach(e=>e({...a}))}finally{b()}}}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.bodyByteLength=bodyByteLength;exports.chunkSize=void 0;exports.createBytePacer=createBytePacer;exports.paceByteCount=paceByteCount;exports.paceResponse=paceResponse;exports.pacedStream=pacedStream;exports.uploadBodySize=uploadBodySize;exports.uploadSize=uploadSize;exports.utf8Length=void 0;var _realNow=require("../utils/realNow");var _wait=require("./wait");const chunkSize=e=>Math.max(1,Math.min(16384,Math.floor(e*.02)));exports.chunkSize=chunkSize;const utf8Length=e=>new TextEncoder().encode(e).byteLength;exports.utf8Length=utf8Length;function bodyByteLength(e){if(e==null)return 0;if(typeof e==="string")return utf8Length(e);if(e instanceof ArrayBuffer)return e.byteLength;if(ArrayBuffer.isView(e))return e.byteLength;if(typeof Blob!=="undefined"&&e instanceof Blob)return e.size;if(typeof URLSearchParams!=="undefined"&&e instanceof URLSearchParams)return utf8Length(e.toString());return null}async function paceByteCount(e,s,o,f){const y=chunkSize(s);const a=(0,_realNow.realNow)();for(let i=0;i<e;){const p=Math.min(y,e-i);await(0,_wait.waitBeforeDispatch)(Math.max(0,a+(i+p)/s*1e3-(0,_realNow.realNow)()),o);(0,_wait.throwIfAborted)(o);i+=p;f?.(i,e)}}function uploadBodySize(e,s){try{const o=typeof e==="object"&&"method"in e?e:void 0;const f=s?.body!==void 0?s.body:o&&"_bodyInit"in o?o._bodyInit:o?.body;return uploadSize(f)}catch{return uploadSizeUnknown(0)}}function uploadSizeUnknown(e){return{knownBytes:e,status:e>0?"partial":"not-applied",note:e>0?"upload cap partial: size unknown":"upload cap not applied: size unknown"}}function uploadSize(e){let s=0;try{const o=bodyByteLength(e);if(o!==null)return{knownBytes:o,status:"applied"};if(e&&typeof e==="object"){const f=e;const y=Array.isArray(f._parts)?f._parts:typeof FormData!=="undefined"&&e instanceof FormData&&f.entries?f.entries():void 0;if(y){for(const[,a]of y){try{const i=bodyByteLength(a);if(i!==null)s+=i;else if(a&&typeof a==="object"&&"uri"in a&&"size"in a&&typeof a.size==="number"&&Number.isSafeInteger(a.size)&&a.size>=0)s+=a.size}catch{}}}}}catch{}return uploadSizeUnknown(s)}function createBytePacer(e){let s=0;return async(o,f)=>{const y=o/e*1e3;const a=(0,_realNow.realNow)();const i=Math.max(0,y-s);if(i>0)await(0,_wait.waitBeforeDispatch)(i,f);(0,_wait.throwIfAborted)(f);s=Math.min(chunkSize(e)/e*1e3,Math.max(0,s+(0,_realNow.realNow)()-a-y))}}function pacedStream(e,s,o,f){const y=createBytePacer(s);let a;const i=()=>{a?.releaseLock();a=void 0};const p=t=>{void(a?a.cancel(t):e.cancel(t)).catch(()=>{});i()};const l=new AbortController;let r;let n=0;let d=false;let u;const c=(t,b=false)=>{if(d)return;d=true;o?.removeEventListener("abort",h);l.abort();r=void 0;if(b)u.error(t);else{i();u.close()}f?.(null,t)};const h=()=>{const t=o?.reason!==void 0?o.reason:Object.assign(new Error("The request was aborted."),{name:"AbortError"});c(t,true);p(t)};return new ReadableStream({start(t){u=t;o?.addEventListener("abort",h,{once:true});if(o?.aborted)h()},async pull(){try{if(!r||n===r.byteLength){const w=await(a??=e.getReader()).read();if(d)return;if(w.done){c();return}r=w.value;n=0}const t=Math.min(chunkSize(s),r.byteLength-n);const b=r.subarray(n,n+t);await y(t,l.signal);if(d)return;n+=t;f?.(b);u.enqueue(b)}catch(t){if(!d){c(t,true);p(t)}}},cancel(t){if(!d){d=true;o?.removeEventListener("abort",h);l.abort();r=void 0;f?.(null,t??new Error("Body read stopped."))}p(t)}},{highWaterMark:0})}function paceResponse(e,s,o,f,y=false){if(y||[204,205,304].includes(e.status)||e.body===null){f?.(null);return e}let a;let i=false;const p=()=>{if(!a){let r;let n=false;const d=new ReadableStream({async pull(u){i=true;try{if(e.body?.getReader){r??=e.body.getReader();const c=await r.read();if(n)return;if(c.done){n=true;r.releaseLock();r=void 0;u.close()}else u.enqueue(c.value)}else{const c=new Uint8Array(await e.arrayBuffer());if(n)return;u.enqueue(c);n=true;u.close()}}catch(c){if(!n){n=true;r?.releaseLock();r=void 0;u.error(c)}}},cancel(u){i=true;n=true;const c=r?r.cancel(u):e.body?.cancel?.(u);r?.releaseLock();r=void 0;return c}},{highWaterMark:0});a=pacedStream(d,s,o,f)}return a};const l=async(r=true)=>{if(i||a?.locked||e.bodyUsed)throw new TypeError("Body has already been read.");i=true;const n=p().getReader();const d=[];let u=0;try{for(;;){const t=await n.read();if(t.done)break;if(r){d.push(t.value);u+=t.value.byteLength}}}finally{n.releaseLock()}const c=new Uint8Array(u);let h=0;for(const t of d){c.set(t,h);h+=t.byteLength}return c};return new Proxy(e,{get(r,n){if(n==="body")return p();if(n==="bodyUsed")return i||e.bodyUsed;if(n==="arrayBuffer")return async()=>(await l()).buffer;if(n==="bytes")return l;if(n==="text")return async()=>new TextDecoder().decode(await l());if(n==="json")return async()=>JSON.parse(new TextDecoder().decode(await l()));if(n==="blob")return async()=>{if(i||a?.locked||e.bodyUsed)throw new TypeError("Body has already been read.");(0,_wait.throwIfAborted)(o);let u=false;try{new Blob([new Uint8Array(0)]);u=true}catch{}if(u)return new Blob([await l()],{type:r.headers.get("content-type")??""});const c=r.clone();let h;Object.defineProperty(c,"arrayBuffer",{configurable:true,value:async()=>{if(c.body&&!c.body.locked)void c.body.cancel().catch(()=>{});h??=l();return(await h).buffer}});try{const t=c.blob();void t.catch(()=>{});await(h??l(false));(0,_wait.throwIfAborted)(o);return await t}finally{if(c.body&&!c.body.locked)void c.body.cancel().catch(()=>{})}};if(n==="formData")return async()=>{const u=await l();return new Response(u,{headers:r.headers}).formData()};if(n==="clone")return()=>{if(i||a?.locked||e.bodyUsed)throw new TypeError("Body has already been read.");return paceResponse(r.clone(),s,o)};const d=Reflect.get(r,n,r);return typeof d==="function"?d.bind(r):d}})}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NETWORK_CONDITIONS=exports.CONNECTIONS=exports.CONDITIONS_SCOPE=void 0;const NETWORK_CONDITIONS=exports.NETWORK_CONDITIONS={normal:{label:"Normal",delayMs:0},offline:{label:"Offline (requests)",delayMs:0},slow:{label:"Slow (+500 ms)",delayMs:500},verySlow:{label:"Very slow (+2000 ms)",delayMs:2e3},slow3g:{label:"Slow 3G",delayMs:2e3,downloadBytesPerSecond:5e4,uploadBytesPerSecond:5e4},slow4g:{label:"Slow 4G",delayMs:562.5,downloadBytesPerSecond:18e4,uploadBytesPerSecond:84375},fast4g:{label:"Fast 4G",delayMs:165,downloadBytesPerSecond:1012500,uploadBytesPerSecond:168750}};const CONNECTIONS=exports.CONNECTIONS=["auto","real","offline","wifi","cellular","noInternet"];const CONDITIONS_SCOPE=exports.CONDITIONS_SCOPE={download:"Paces bytes to the app in JS. The socket stays at its real speed.",upload:"Waits before send for known body bytes. Unknown sizes pass through with latency only. Multipart overhead is not counted. Each call marks a partial or skipped cap. Upload time is simulated; the socket is not paced.",transports:"Affects global fetch and RN XHR. WebSocket, native images, native SDKs and file transfers are not affected."};
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.chooseConditionsSnapshot=chooseConditionsSnapshot;function chooseConditionsSnapshot(e,t){if(!e)return null;if(!t||t.runtimeId!==e.runtimeId||t.revision<e.revision)return e;return t}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.networkConditionsRuntimeId=exports.getNetworkCondition=exports.conditionsCanApply=exports.NETWORK_CONDITIONS=void 0;exports.setNetworkCondition=setNetworkCondition;exports.snapshotNetworkCondition=snapshotNetworkCondition;exports.subscribeNetworkConditions=void 0;var _sharedUi=require("@buoy-gg/shared-ui");var _networkListener=require("../utils/networkListener");const NETWORK_CONDITIONS=exports.NETWORK_CONDITIONS={normal:{label:"Normal",delayMs:0},offline:{label:"Offline (requests)",delayMs:0},slow:{label:"Slow (+500 ms)",delayMs:500},verySlow:{label:"Very slow (+2000 ms)",delayMs:2e3}};const networkConditionsRuntimeId=exports.networkConditionsRuntimeId=`${Date.now()}-${Math.random().toString(36).slice(2)}`;let profile="normal";let keepAlive;const listeners=new Set;const conditionsCanApply=()=>typeof __DEV__!=="undefined"&&__DEV__&&(0,_sharedUi.hasAccountAccess)();exports.conditionsCanApply=conditionsCanApply;const getNetworkCondition=()=>profile;exports.getNetworkCondition=getNetworkCondition;const subscribeNetworkConditions=e=>{listeners.add(e);return()=>{listeners.delete(e)}};exports.subscribeNetworkConditions=subscribeNetworkConditions;function setNetworkCondition(e){if(typeof e!=="string"||!Object.prototype.hasOwnProperty.call(NETWORK_CONDITIONS,e)){throw new Error("Choose normal, offline, slow, or verySlow.")}if(e!=="normal"&&!conditionsCanApply()){throw new Error("Network conditions require an admitted account and a development build.")}if(e===profile)return profile;if(e!=="normal"&&!keepAlive){(0,_networkListener.startNetworkListener)();keepAlive=(0,_networkListener.addNetworkListener)(()=>{})}else if(e==="normal"){keepAlive?.();keepAlive=void 0;if((0,_networkListener.getNetworkListenerCount)()===0)(0,_networkListener.stopNetworkListener)()}profile=e;listeners.forEach(o=>o());return profile}function snapshotNetworkCondition(e){if(profile==="normal"||!conditionsCanApply()||!/^https?:\/\//i.test(e))return;return Object.freeze({profile,delayMs:NETWORK_CONDITIONS[profile].delayMs})}(0,_sharedUi.subscribeAccountAccess)(()=>{if(!(0,_sharedUi.hasAccountAccess)())setNetworkCondition("normal");listeners.forEach(e=>e())});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"CONDITIONS_SCOPE",{enumerable:true,get:function(){return _profiles.CONDITIONS_SCOPE}});Object.defineProperty(exports,"NETWORK_CONDITIONS",{enumerable:true,get:function(){return _profiles.NETWORK_CONDITIONS}});exports.getNetworkCondition=exports.getEffectiveNetworkConnection=exports.getConditionsRevision=exports.conditionsCanApply=void 0;exports.getNetworkConditions=getNetworkConditions;exports.networkConditionsRuntimeId=exports.networkConditionsActive=exports.getNetworkConnection=void 0;exports.setConnectionSupport=setConnectionSupport;exports.setNetworkCondition=setNetworkCondition;exports.setNetworkConditions=setNetworkConditions;exports.snapshotNetworkCondition=snapshotNetworkCondition;exports.subscribeNetworkConditions=void 0;var _sharedUi=require("@buoy-gg/shared-ui");var _networkListener=require("../utils/networkListener");var _profiles=require("./profiles");const connectionSupport={netInfo:{supported:false,reason:"Load the NetInfo hook before app code."},expoNetwork:{supported:false,reason:"Load the Expo Network hook before app code."}};let connection="auto";let revision=0;const getNetworkConnection=()=>connection;exports.getNetworkConnection=getNetworkConnection;const getConditionsRevision=()=>revision;exports.getConditionsRevision=getConditionsRevision;const getEffectiveNetworkConnection=()=>!conditionsCanApply()?"real":connection==="auto"?profile==="offline"?"offline":"real":connection;exports.getEffectiveNetworkConnection=getEffectiveNetworkConnection;const networkConditionsActive=()=>profile!=="normal"||!["auto","real"].includes(connection);exports.networkConditionsActive=networkConditionsActive;function setConnectionSupport(e,o){connectionSupport[e]=o;revision++;listeners.forEach(t=>t())}function getNetworkConditions(){const e=_profiles.NETWORK_CONDITIONS[profile];return{version:2,runtimeId:networkConditionsRuntimeId,revision,profile,connection,available:conditionsCanApply(),active:networkConditionsActive(),delayMs:e.delayMs,downloadBytesPerSecond:e.downloadBytesPerSecond??null,uploadBytesPerSecond:e.uploadBytesPerSecond??null,capabilities:{...connectionSupport,fetch:"JS body delivery",xhr:"RN progress and body delivery",upload:"time-simulated",webSocket:false,nativeImages:false,nativeModules:false},scope:_profiles.CONDITIONS_SCOPE}}function setNetworkConditions(e){if(!e||typeof e!=="object"||Array.isArray(e))throw new Error("Choose a speed or link state.");const o=e;if(Object.keys(o).some(r=>r!=="profile"&&r!=="connection")||!("profile"in o)&&!("connection"in o))throw new Error("Choose a speed or link state.");const t="profile"in o?o.profile:profile;const n="connection"in o?o.connection:t==="normal"&&"profile"in o?"auto":connection;if(typeof t!=="string"||!Object.prototype.hasOwnProperty.call(_profiles.NETWORK_CONDITIONS,t))throw new Error("Choose a valid speed profile.");if(!_profiles.CONNECTIONS.includes(n))throw new Error("Choose a valid link state.");if((t!=="normal"||!["auto","real"].includes(n))&&!conditionsCanApply())throw new Error("Use a signed-in account and a dev build.");if(!["auto","real"].includes(n)&&!connectionSupport.netInfo.supported&&!connectionSupport.expoNetwork.supported)throw new Error("Load a link hook before app code.");if(t===profile&&n===connection)return getNetworkConditions();const i=t!=="normal";if(i&&!keepAlive){(0,_networkListener.startNetworkListener)();keepAlive=(0,_networkListener.addNetworkListener)(()=>{})}if(!i){keepAlive?.();keepAlive=void 0;if((0,_networkListener.getNetworkListenerCount)()===0)(0,_networkListener.stopNetworkListener)()}profile=t;connection=n;revision++;listeners.forEach(r=>r());return getNetworkConditions()}const networkConditionsRuntimeId=exports.networkConditionsRuntimeId=`${Date.now()}-${Math.random().toString(36).slice(2)}`;let profile="normal";let keepAlive;const listeners=new Set;const conditionsCanApply=()=>typeof __DEV__!=="undefined"&&__DEV__&&(0,_sharedUi.hasAccountAccess)();exports.conditionsCanApply=conditionsCanApply;const getNetworkCondition=()=>profile;exports.getNetworkCondition=getNetworkCondition;const subscribeNetworkConditions=e=>{listeners.add(e);return()=>{listeners.delete(e)}};exports.subscribeNetworkConditions=subscribeNetworkConditions;function setNetworkCondition(e){return setNetworkConditions({profile:e}).profile}function snapshotNetworkCondition(e){if(profile==="normal"||!conditionsCanApply()||!/^https?:\/\//i.test(e))return;const{label:o,...t}=_profiles.NETWORK_CONDITIONS[profile];return Object.freeze({profile,...t})}(0,_sharedUi.subscribeAccountAccess)(()=>{if(!(0,_sharedUi.hasAccountAccess)())setNetworkCondition("normal");listeners.forEach(e=>e())});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.throwIfAborted=throwIfAborted;exports.waitBeforeDispatch=waitBeforeDispatch;function throwIfAborted(e){if(!e?.aborted)return;if(e.reason!==void 0)throw e.reason;const r=new Error("The request was aborted.");r.name="AbortError";throw r}function waitBeforeDispatch(e,r){return new Promise((s,o)=>{try{throwIfAborted(r)}catch(t){o(t);return}const n=()=>r?.removeEventListener("abort",c);const c=()=>{clearTimeout(u);n();try{throwIfAborted(r)}catch(t){o(t)}};const u=setTimeout(()=>{n();s()},e);r?.addEventListener("abort",c,{once:true})})}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.throwIfAborted=throwIfAborted;exports.waitBeforeDispatch=waitBeforeDispatch;var _realNow=require("../utils/realNow");function throwIfAborted(e){if(!e?.aborted)return;if(e.reason!==void 0)throw e.reason;const r=new Error("The request was aborted.");r.name="AbortError";throw r}function waitBeforeDispatch(e,r){return new Promise((u,o)=>{try{throwIfAborted(r)}catch(t){o(t);return}const n=()=>r?.removeEventListener("abort",a);const a=()=>{(0,_realNow.realClearTimeout)(c);n();try{throwIfAborted(r)}catch(t){o(t)}};const c=(0,_realNow.realSetTimeout)(()=>{n();u()},e);r?.addEventListener("abort",a,{once:true})})}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.runConditionXhr=runConditionXhr;var _applyToXhr=require("../overrides/applyToXhr");var _realNow=require("../utils/realNow");function runConditionXhr(u,d,o,r,y){if(!(0,_applyToXhr.canSynthesize)(u)){const t={id:"condition",enabled:true,urlPattern:d,kind:"delay",hits:0,seen:0,createdAt:Date.now()};const a=o.profile==="offline"?{kind:"fail",rule:t,failKind:"network",delayMs:0}:r?{...r,delayMs:o.delayMs+r.delayMs}:{kind:"delay",rule:t,delayMs:o.delayMs};if(!(0,_applyToXhr.runOverride)(u,d,a,y))throw new Error("Network conditions are unavailable for this XMLHttpRequest implementation.");return}const e=u;if(e.readyState!==1||e._sent)throw new Error("Request is not open or has already been sent.");const b=(0,_realNow.realNow)();let n=e.timeout;let i=false;let f=false;let c;let h;const w=e.abort;const m=e.open;const v=Object.getOwnPropertyDescriptor(e,"abort");const M=Object.getOwnPropertyDescriptor(e,"open");const _=Object.getOwnPropertyDescriptor(e,"timeout");const p=(t,a)=>{if(a)Object.defineProperty(e,t,a);else delete e[t]};const l=()=>{if(i)return;i=true;clearTimeout(h);(0,_realNow.realClearTimeout)(c);e.removeEventListener("loadend",l);p("abort",v);p("open",M);p("timeout",_);e.timeout=n};const s=t=>{if(i)return;Object.assign(e,{readyState:4});w.call(e);e._aborted=false;e._hasError=true;e._timedOut=t;e._response=t?"Request timed out (Buoy conditions)":"Network request failed (Buoy Offline)";e.setReadyState(4);l()};const g=()=>n>0&&(0,_realNow.realNow)()-b>=n;const O=()=>{(0,_realNow.realClearTimeout)(c);if(n>0)c=(0,_realNow.realSetTimeout)(()=>s(true),Math.max(0,n-((0,_realNow.realNow)()-b)))};Object.defineProperty(e,"timeout",{configurable:true,get:()=>f?0:n,set:t=>{n=Math.max(0,Number(t)||0);O()}});Object.defineProperty(e,"abort",{configurable:true,value:()=>{if(!i){w.call(e);l()}}});Object.defineProperty(e,"open",{configurable:true,value:(...t)=>{const a=Reflect.apply(m,e,t);l();return a}});e._sent=true;e._requestId=null;e.addEventListener("loadend",l);O();h=setTimeout(()=>{if(i)return;if(g()){s(true);return}if(o.profile==="offline"){s(false);return}if(r&&r.kind!=="delay"){(0,_applyToXhr.completeNativeOverride)(e,d,r);return}e._sent=false;f=true;try{y()}catch{s(false)}finally{f=false}},o.delayMs+(r?.delayMs??0))}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.runConditionXhr=runConditionXhr;var _pacer=require("./pacer");var _applyToXhr=require("../overrides/applyToXhr");var _realNow=require("../utils/realNow");function runConditionXhr(R,O,a,i,k,z){if(!(0,_applyToXhr.canSynthesize)(R)){if(a.downloadBytesPerSecond)throw new Error("Byte caps need RN XHR. This XHR only supports waits and Offline.");const t={id:"condition",enabled:true,urlPattern:O,kind:"delay",hits:0,seen:0,createdAt:Date.now()};const n=a.profile==="offline"?{kind:"fail",rule:t,failKind:"network",delayMs:0}:i?{...i,delayMs:a.delayMs+i.delayMs}:{kind:"delay",rule:t,delayMs:a.delayMs};if(!(0,_applyToXhr.runOverride)(R,O,n,k))throw new Error("Network conditions are unavailable for this XMLHttpRequest implementation.");return}const e=R;if(e.readyState!==1||e._sent)throw new Error("Request is not open or has already been sent.");const E=(0,_realNow.realNow)();let u=e.timeout;let o=false;const _=new AbortController;const M=[];let D=false;let B;let q;const x=e.abort;const H=e.open;const I=Object.getOwnPropertyDescriptor(e,"abort");const A=Object.getOwnPropertyDescriptor(e,"open");const U=Object.getOwnPropertyDescriptor(e,"timeout");const v=(t,n)=>{if(n)Object.defineProperty(e,t,n);else delete e[t]};const b=()=>{if(o)return;o=true;(0,_realNow.realClearTimeout)(q);_.abort();M.forEach(t=>t());(0,_realNow.realClearTimeout)(B);e.removeEventListener("loadend",b);v("abort",I);v("open",A);v("timeout",U);e.timeout=u};const g=(t,n)=>{if(o)return;Object.assign(e,{readyState:4});x.call(e);e._aborted=false;e._hasError=true;e._timedOut=t;e._response=n??(t?"Request timed out (Buoy conditions)":"Network request failed (Buoy Offline)");e.setReadyState(4);b()};const W=()=>u>0&&(0,_realNow.realNow)()-E>=u;const N=()=>{(0,_realNow.realClearTimeout)(B);if(u>0)B=(0,_realNow.realSetTimeout)(()=>g(true),Math.max(0,u-((0,_realNow.realNow)()-E)))};Object.defineProperty(e,"timeout",{configurable:true,get:()=>D?0:u,set:t=>{u=Math.max(0,Number(t)||0);N()}});Object.defineProperty(e,"abort",{configurable:true,value:()=>{if(!o){x.call(e);b()}}});Object.defineProperty(e,"open",{configurable:true,value:(...t)=>{const n=Reflect.apply(H,e,t);b();return n}});e._sent=true;e._requestId=null;e.addEventListener("loadend",b);N();const l=e;const w=(t,n)=>{const d=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(e,t,{configurable:true,writable:true,value:n});M.push(()=>v(t,d))};const K=(t,n,d)=>{const m=new Event("progress");Object.defineProperties(m,{loaded:{value:n},total:{value:d},lengthComputable:{value:true}});t.dispatchEvent(m)};const y=a.downloadBytesPerSecond;if(y&&typeof l.__didReceiveData==="function"&&typeof l.__didCompleteResponse==="function"){const t=l.__didReceiveData.bind(e);const n=l.__didReceiveIncrementalData?.bind(e);const d=l.__didCompleteResponse.bind(e);const m=l.__didReceiveDataProgress?.bind(e);let L=Promise.resolve();let h=0;const F=(0,_pacer.createBytePacer)(y);const S=s=>{L=L.then(async()=>{if(!o)await s()}).catch(r=>{if(!o)g(false,r instanceof Error?r.message:String(r))})};const X=async(s,r,c=-1)=>{const T=!e.responseType||e.responseType==="text"||e.responseType==="json";if(T&&typeof r==="string"&&n){const p=new TextEncoder().encode(r);const j=new TextDecoder;for(let f=0;f<p.byteLength;){const P=Math.min((0,_pacer.chunkSize)(y),p.byteLength-f);await F(P,_.signal);if(o)return;const G=j.decode(p.subarray(f,f+P),{stream:f+P<p.byteLength});f+=P;h+=P;n(s,G,h,c);m?.(s,h,c)}}else{const p=typeof r==="object"&&r?r.size:e.responseType==="arraybuffer"&&typeof r==="string"?Math.max(0,r.length*3/4-(r.endsWith("==")?2:r.endsWith("=")?1:0)):(0,_pacer.bodyByteLength)(r);if(typeof p!=="number")throw new Error("Cannot read this response size.");const j=h;await(0,_pacer.paceByteCount)(p,y,_.signal,f=>{h=j+f;m?.(s,h,c<0?p:c)});if(!o)t(s,r)}};w("__didReceiveData",(s,r)=>S(()=>X(s,r)));w("__didReceiveIncrementalData",(s,r,c,T)=>S(()=>X(s,r,T)));w("__didReceiveDataProgress",()=>{});w("__didCompleteResponse",(s,r,c)=>{if(r){d(s,r,c);return}S(async()=>{if(!o)d(s,r,c)})})}else if(y){b();throw new Error("This XHR lacks the RN byte hooks.")}const C=typeof l.__didUploadProgress==="function"?l.__didUploadProgress.bind(e):void 0;if(a.uploadBytesPerSecond&&C)w("__didUploadProgress",()=>{});q=(0,_realNow.realSetTimeout)(()=>{void(async()=>{if(o)return;if(W()){g(true);return}if(a.profile==="offline"){g(false);return}if(a.uploadBytesPerSecond){const t=(a.uploadCap??(0,_pacer.uploadSize)(z)).knownBytes;await(0,_pacer.paceByteCount)(t,a.uploadBytesPerSecond,_.signal,(n,d)=>{if(C)C(e._requestId,n,d);else if(e.upload)K(e.upload,n,d)})}if(o)return;if(i&&i.kind!=="delay"){if(y&&i.kind==="respond")await(0,_pacer.paceByteCount)((0,_pacer.bodyByteLength)(i.body)??0,y,_.signal);if(!o)(0,_applyToXhr.completeNativeOverride)(e,O,i);return}e._sent=false;D=true;try{k()}finally{D=false}})().catch(t=>{if(!o)g(false,t instanceof Error?t.message:String(t))})},a.delayMs+(i?.delayMs??0))}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.OVERRIDES_INACTIVE_REASON=void 0;exports.accountCheckFor=accountCheckFor;exports.inspectEngine=inspectEngine;exports.overrideForRequest=overrideForRequest;exports.overridesCanApply=overridesCanApply;exports.setOverrideHooks=setOverrideHooks;var _sharedUi=require("@buoy-gg/shared-ui");var _resolveOverride=require("./resolveOverride");var _realNow=require("../utils/realNow");let hooks=null;function setOverrideHooks(r){hooks=r}function overridesCanApply(){return(0,_sharedUi.hasAccountAccess)()&&!(typeof __DEV__!=="undefined"&&!__DEV__)}const OVERRIDES_INACTIVE_REASON=exports.OVERRIDES_INACTIVE_REASON="Response overrides never apply in a release build \u2014 the rule is saved but will not affect any request.";function inspectEngine(r,t){return{hooksInstalled:hooks!==null,devFlag:typeof __DEV__==="undefined"?"undefined":__DEV__,ruleCount:hooks?hooks.getRules().length:0,matches:hooks?(0,_resolveOverride.findMatchingRule)(r,t,hooks.getRules())!==null:false}}const ACCOUNT_WAIT_MS=3e3;function accountCheckFor(r,t,s,i){if(!hooks||(0,_sharedUi.hasAccountAccess)())return null;if(typeof __DEV__!=="undefined"&&!__DEV__)return null;if((0,_sharedUi.getAccountAccess)().status!=="initializing")return null;if(!(0,_resolveOverride.findMatchingRule)(r,t,hooks.getRules(),s,i))return null;return new Promise(n=>{let e=()=>{};const u=()=>{(0,_realNow.realClearTimeout)(o);e();n()};const o=(0,_realNow.realSetTimeout)(u,ACCOUNT_WAIT_MS);e=(0,_sharedUi.subscribeAccountAccess)(()=>{if((0,_sharedUi.getAccountAccess)().status!=="initializing")u()})})}function overrideForRequest(r,t,s,i){if(!hooks)return null;if(!overridesCanApply())return null;const n=hooks.getRules();if(n.length===0)return null;const e=(0,_resolveOverride.findMatchingRule)(r,t,n,s,i);if(!e)return null;const u=(0,_resolveOverride.shouldApply)(e);hooks.recordMatch(e.id);if(!u)return null;hooks.recordHit(e.id);return(0,_resolveOverride.toOutcome)(e)}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.OVERRIDES_INACTIVE_REASON=void 0;exports.accountCheckFor=accountCheckFor;exports.inspectEngine=inspectEngine;exports.overrideForRequest=overrideForRequest;exports.overrideRulesLoaded=overrideRulesLoaded;exports.overrideRulesNeedBody=overrideRulesNeedBody;exports.overrideRulesReady=overrideRulesReady;exports.overridesCanApply=overridesCanApply;exports.setOverrideHooks=setOverrideHooks;var _sharedUi=require("@buoy-gg/shared-ui");var _resolveOverride=require("./resolveOverride");var _realNow=require("../utils/realNow");let hooks=null;function setOverrideHooks(e){hooks=e}function overrideRulesReady(){return hooks?.ready?.()??Promise.resolve()}function overrideRulesLoaded(){return hooks?.isReady?.()??true}function overrideRulesNeedBody(){return!!hooks?.getRules().some(e=>e.enabled&&(e.bodyIncludes||e.graphqlOperation))}function overridesCanApply(){return(0,_sharedUi.hasAccountAccess)()&&!(typeof __DEV__!=="undefined"&&!__DEV__)}const OVERRIDES_INACTIVE_REASON=exports.OVERRIDES_INACTIVE_REASON="Response overrides never apply in a release build \u2014 the rule is saved but will not affect any request.";function inspectEngine(e,n){return{hooksInstalled:hooks!==null,devFlag:typeof __DEV__==="undefined"?"undefined":__DEV__,ruleCount:hooks?hooks.getRules().length:0,matches:hooks?(0,_resolveOverride.findMatchingRule)(e,n,hooks.getRules())!==null:false}}const ACCOUNT_WAIT_MS=3e3;function accountCheckFor(e,n,o,s){if(!hooks||(0,_sharedUi.hasAccountAccess)())return null;if(typeof __DEV__!=="undefined"&&!__DEV__)return null;if((0,_sharedUi.getAccountAccess)().status!=="initializing")return null;if(!(0,_resolveOverride.findMatchingRule)(e,n,hooks.getRules(),o,s))return null;return new Promise(t=>{let r=()=>{};const u=()=>{(0,_realNow.realClearTimeout)(i);r();t()};const i=(0,_realNow.realSetTimeout)(u,ACCOUNT_WAIT_MS);r=(0,_sharedUi.subscribeAccountAccess)(()=>{if((0,_sharedUi.getAccountAccess)().status!=="initializing")u()})})}function overrideForRequest(e,n,o,s){if(!hooks)return null;if(typeof __DEV__!=="undefined"&&!__DEV__)return null;let t=hooks.getRules();if(t.length===0)return null;if(!(0,_sharedUi.hasAccountAccess)()){t=t.filter(i=>i.sandbox===true);if(t.length===0)return null}const r=(0,_resolveOverride.findMatchingRule)(e,n,t,o,s);if(!r)return null;const u=(0,_resolveOverride.shouldApply)(r);hooks.recordMatch(r.id);if(!u)return null;hooks.recordHit(r.id);return(0,_resolveOverride.toOutcome)(r)}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.compilePattern=compilePattern;exports.escapeRegex=escapeRegex;exports.ruleMatches=ruleMatches;const SPECIAL_CHARACTERS="[]{}()\\.^$+|-,?";function escapeRegex(e){let r="";for(let s=0;s<e.length;s++){const t=e.charAt(s);if(SPECIAL_CHARACTERS.indexOf(t)!==-1){r+="\\"}r+=t}return r.split("*").join(".*")}const compiled=new Map;function compilePattern(e){const r=compiled.get(e);if(r)return r;const s=e.startsWith("/")?`[a-zA-Z][a-zA-Z0-9+.-]*://[^/]*${escapeRegex(e)}`:escapeRegex(e);const t=new RegExp(`^${s}$`);if(compiled.size>200)compiled.clear();compiled.set(e,t);return t}function hasHeader(e,r){if(!e)return false;const s=r.toLowerCase();for(const t of Object.keys(e)){if(t.toLowerCase()===s&&e[t]!==void 0&&e[t]!=="")return true}return false}function ruleMatches(e,r,s,t,n){if(e.methods&&e.methods.length>0){if(!e.methods.includes(s.toUpperCase()))return false}if(e.requireHeader&&!hasHeader(t,e.requireHeader))return false;if(e.bodyIncludes&&(typeof n!=="string"||!n.includes(e.bodyIncludes)))return false;try{return compilePattern(e.urlPattern).test(r)}catch{return false}}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.canonicalJson=canonicalJson;exports.compilePattern=compilePattern;exports.escapeRegex=escapeRegex;exports.ruleMatches=ruleMatches;const SPECIAL_CHARACTERS="[]{}()\\.^$+|-,?";function escapeRegex(e){let n="";for(let t=0;t<e.length;t++){const r=e.charAt(t);if(SPECIAL_CHARACTERS.indexOf(r)!==-1){n+="\\"}n+=r}return n.split("*").join(".*")}const compiled=new Map;function compilePattern(e){const n=compiled.get(e);if(n)return n;const t=e.startsWith("/")?`[a-zA-Z][a-zA-Z0-9+.-]*://[^/]*${escapeRegex(e)}`:escapeRegex(e);const r=new RegExp(`^${t}$`);if(compiled.size>200)compiled.clear();compiled.set(e,r);return r}function hasHeader(e,n){if(!e)return false;const t=n.toLowerCase();for(const r of Object.keys(e)){if(r.toLowerCase()===t&&e[r]!==void 0&&e[r]!=="")return true}return false}function canonicalJson(e){const n=t=>Array.isArray(t)?t.map(n):t&&typeof t==="object"?Object.fromEntries(Object.keys(t).sort().map(r=>[r,n(t[r])])):t;return JSON.stringify(n(e))??"null"}function hasGraphqlOperation(e,n,t){if(typeof e!=="string"||!e.includes(n))return false;try{const r=JSON.parse(e);const s=Array.isArray(r)?r:[r];return s.some(o=>{if(!o||typeof o!=="object"||o.operationName!==n)return false;return t===void 0||canonicalJson(o.variables??{})===t})}catch{return false}}function ruleMatches(e,n,t,r,s){if(e.methods&&e.methods.length>0){if(!e.methods.includes(t.toUpperCase()))return false}if(e.requireHeader&&!hasHeader(r,e.requireHeader))return false;if(e.bodyIncludes&&(typeof s!=="string"||!s.includes(e.bodyIncludes)))return false;if(e.graphqlOperation&&!hasGraphqlOperation(s,e.graphqlOperation,e.graphqlVariables))return false;try{return compilePattern(e.urlPattern).test(n)}catch{return false}}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.overrideRulesStore=void 0;var _sharedUi=require("@buoy-gg/shared-ui");var _networkListener=require("../utils/networkListener");var _engine=require("./engine");var _resolveOverride=require("./resolveOverride");var _types=require("./types");var _realNow=require("../utils/realNow");const REMOTE_ECHO_GRACE_MS=800;const MAX_UNTOUCHED_LAUNCHES=3;function countedThisTab(){const r=`${_sharedUi.devToolsStorageKeys.network.overrides()}_launch`;try{const t=globalThis.sessionStorage;if(!t)return false;if(t.getItem(r))return true;t.setItem(r,"1")}catch{}return false}const EMPTY_RULES=Object.freeze([]);const HIT_EMIT_COALESCE_MS=250;const VALID_KINDS=["respond","fail","delay"];function parseRules(r){if(!Array.isArray(r))return[];const t=[];for(const i of r){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=VALID_KINDS.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(n=>typeof n==="string"):void 0,requireHeader:typeof e.requireHeader==="string"&&e.requireHeader?e.requireHeader:void 0,bodyIncludes:typeof e.bodyIncludes==="string"&&e.bodyIncludes?e.bodyIncludes:void 0,kind:s,status:typeof e.status==="number"?Math.min(_types.STATUS_MAX,Math.max(_types.STATUS_MIN,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,_types.MAX_RULES)}class OverrideRulesStore{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&&(0,_realNow.realNow)()<this.remoteEchoUntil)return;this.enabled=t.enabled;this.rules=t.rules;this.rebuild();this.emit()}markLocalEdit(){if(this.remote)this.remoteEchoUntil=(0,_realNow.realNow)()+REMOTE_ECHO_GRACE_MS}disableEngine(){this.engineDisabled=true;if(this.keepAlive){this.keepAlive();this.keepAlive=null;if((0,_networkListener.getNetworkListenerCount)()===0)(0,_networkListener.stopNetworkListener)()}}getState(){return this.state}getRules(){if(this.engineDisabled||!this.enabled)return EMPTY_RULES;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&&!(0,_resolveOverride.isSpent)(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>=_types.MAX_RULES)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)}replaceAllRules(t,i){if(this.remote)return null;this.markTouched();const e=t.map(s=>s&&typeof s==="object"&&typeof s.id==="string"?s:{...s,id:`ovr_${Date.now().toString(36)}_${++this.idCounter}`,createdAt:Date.now()});this.enabled=i;this.commit(parseRules(e));return this.rules.slice()}updateRule(t,i){const e=this.rules.findIndex(n=>n.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(n=>n.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(l=>l.id===t);if(i===-1)return;const e=this.rules[i];const s=e.hits+1;const n=typeof e.times==="number"&&s>=e.times;const u=[...this.rules];u[i]={...e,hits:s,enabled:n?false:e.enabled};if(n){this.commit(u);return}this.rules=u;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()=>{let t=null;try{t=await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.network.overrides())}catch{}this.hydrate(t)})();return this.loadPromise}loadNow(){if(this.remote||this.loaded||this.loadPromise)return;let t;try{t=globalThis.localStorage?.getItem(_sharedUi.devToolsStorageKeys.network.overrides())??null}catch{return}if(t===null)return;this.hydrate(t)}hydrate(t){try{if(t&&!this.dirty){const i=JSON.parse(t);this.enabled=i?.enabled!==false;this.rules=parseRules(i?.rules);this.launchStreak=typeof i?.launchStreak==="number"?i.launchStreak:0;this.autoPaused=i?.autoPaused===true&&!this.enabled;this.applyLaunchGuard();this.rebuild()}}catch{}finally{this.loaded=true;this.syncKeepAlive();this.emit()}}applyLaunchGuard(){if(!this.enabled||this.activeCount()===0){this.launchStreak=0;return}if(countedThisTab())return;this.launchStreak+=1;if(this.launchStreak>=MAX_UNTOUCHED_LAUNCHES){this.enabled=false;this.autoPaused=true;this.launchStreak=0}this.persist()}syncKeepAlive(){const t=!this.engineDisabled&&this.activeCount()>0;if(t&&!this.keepAlive){(0,_networkListener.startNetworkListener)();this.keepAlive=(0,_networkListener.addNetworkListener)(()=>{});return}if(!t&&this.keepAlive){this.keepAlive();this.keepAlive=null;if((0,_networkListener.getNetworkListenerCount)()===0)(0,_networkListener.stopNetworkListener)()}}scheduleHitEmit(){if(this.hitEmitTimer!==null)return;this.hitEmitTimer=setTimeout(()=>{this.hitEmitTimer=null;this.emit()},HIT_EMIT_COALESCE_MS)}commit(t){this.dirty=true;this.rules=t.slice(0,_types.MAX_RULES);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;_sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.network.overrides(),JSON.stringify({enabled:this.enabled,rules:this.rules,launchStreak:this.launchStreak,autoPaused:this.autoPaused})).catch(()=>{})}emit(){this.listeners.forEach(t=>t())}}const overrideRulesStore=exports.overrideRulesStore=new OverrideRulesStore;(0,_engine.setOverrideHooks)({getRules:()=>overrideRulesStore.getRules(),recordHit:r=>overrideRulesStore.recordHit(r),recordMatch:r=>overrideRulesStore.recordMatch(r)});if(typeof window!=="undefined"&&typeof document!=="undefined"&&!(typeof navigator!=="undefined"&&navigator.product==="ReactNative")){overrideRulesStore.loadNow()}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.overrideRulesStore=void 0;var _sharedUi=require("@buoy-gg/shared-ui");var _networkListener=require("../utils/networkListener");var _engine=require("./engine");var _resolveOverride=require("./resolveOverride");var _types=require("./types");var _realNow=require("../utils/realNow");const REMOTE_ECHO_GRACE_MS=800;const MAX_UNTOUCHED_LAUNCHES=3;function countedThisTab(){const r=`${_sharedUi.devToolsStorageKeys.network.overrides()}_launch`;try{const t=globalThis.sessionStorage;if(!t)return false;if(t.getItem(r))return true;t.setItem(r,"1")}catch{}return false}const EMPTY_RULES=Object.freeze([]);const HIT_EMIT_COALESCE_MS=250;const VALID_KINDS=["respond","fail","delay"];function parseRules(r){if(!Array.isArray(r))return[];const t=[];for(const s of r){if(!s||typeof s!=="object")continue;const e=s;if(typeof e.id!=="string"||typeof e.urlPattern!=="string"){continue}if(!e.urlPattern)continue;const i=VALID_KINDS.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(n=>typeof n==="string"):void 0,requireHeader:typeof e.requireHeader==="string"&&e.requireHeader?e.requireHeader:void 0,bodyIncludes:typeof e.bodyIncludes==="string"&&e.bodyIncludes?e.bodyIncludes:void 0,graphqlOperation:typeof e.graphqlOperation==="string"&&e.graphqlOperation?e.graphqlOperation:void 0,graphqlVariables:typeof e.graphqlVariables==="string"?e.graphqlVariables:void 0,sandbox:e.sandbox===true?true:void 0,kind:i,status:typeof e.status==="number"?Math.min(_types.STATUS_MAX,Math.max(_types.STATUS_MIN,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,_types.MAX_RULES)}class OverrideRulesStore{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,s=false){if(!this.remote)return;if(!s&&(0,_realNow.realNow)()<this.remoteEchoUntil)return;this.enabled=t.enabled;this.rules=t.rules;this.rebuild();this.emit()}markLocalEdit(){if(this.remote)this.remoteEchoUntil=(0,_realNow.realNow)()+REMOTE_ECHO_GRACE_MS}disableEngine(){this.engineDisabled=true;if(this.keepAlive){this.keepAlive();this.keepAlive=null;if((0,_networkListener.getNetworkListenerCount)()===0)(0,_networkListener.stopNetworkListener)()}}getState(){return this.state}getRules(){if(this.engineDisabled)return EMPTY_RULES;if(!this.enabled)return this.sandboxOnly();return this.rules}sandboxCache=null;sandboxOnly(){if(this.sandboxCache?.from!==this.rules){const t=this.rules.filter(s=>s.sandbox===true);this.sandboxCache={from:this.rules,rules:t.length?t:EMPTY_RULES}}return this.sandboxCache.rules}async fetchRuleBody(t){const s=this.rules.find(e=>e.id===t);if(!s)return null;if(!s.bodyOmitted)return s.body??null;if(!this.remote?.getRuleBody)return null;try{return await this.remote.getRuleBody(t)}catch{return null}}activeCount(){return(this.enabled?this.rules:this.sandboxOnly()).filter(t=>t.enabled&&!(0,_resolveOverride.isSpent)(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>=_types.MAX_RULES)return null;const s={...t,id:`ovr_${Date.now().toString(36)}_${++this.idCounter}`,hits:0,seen:0,createdAt:Date.now()};this.commit([s,...this.rules]);return s}upsertRule(t){this.remote?.upsertRule(t);this.markLocalEdit();this.markTouched();const{id:s,...e}=t;if(s&&this.rules.some(i=>i.id===s)){this.updateRule(s,e);return this.rules.find(i=>i.id===s)??null}return this.addRule(e)}replaceAllRules(t,s){if(this.remote)return null;this.markTouched();const e=t.map(i=>i&&typeof i==="object"&&typeof i.id==="string"?i:{...i,id:`ovr_${Date.now().toString(36)}_${++this.idCounter}`,createdAt:Date.now()});this.enabled=s;this.commit(parseRules(e));return this.rules.slice()}updateRule(t,s){const e=this.rules.findIndex(n=>n.id===t);if(e===-1)return;const i=[...this.rules];i[e]={...i[e],...s,hits:0,seen:0};this.commit(i)}setRuleEnabled(t,s){const e=this.rules.findIndex(n=>n.id===t);if(e===-1||this.rules[e].enabled===s)return;this.remote?.setRuleEnabled(t,s);this.markLocalEdit();this.markTouched();const i=[...this.rules];i[e]={...i[e],enabled:s,hits:s?0:i[e].hits,seen:s?0:i[e].seen};this.commit(i)}removeRule(t){const s=this.rules.filter(e=>e.id!==t);if(s.length===this.rules.length)return;this.remote?.removeRule(t);this.markLocalEdit();this.markTouched();this.commit(s)}clearRules(){if(this.rules.length===0)return;this.remote?.clearRules();this.markLocalEdit();this.markTouched();this.commit([])}recordMatch(t){const s=this.rules.findIndex(i=>i.id===t);if(s===-1)return;const e=[...this.rules];e[s]={...e[s],seen:e[s].seen+1};this.rules=e;this.rebuild()}recordHit(t){const s=this.rules.findIndex(l=>l.id===t);if(s===-1)return;const e=this.rules[s];const i=e.hits+1;const n=typeof e.times==="number"&&i>=e.times;const a=[...this.rules];a[s]={...e,hits:i,enabled:n?false:e.enabled};if(n){this.commit(a);return}this.rules=a;this.rebuild();this.scheduleHitEmit()}isLoaded(){return!!this.remote||this.loaded}ensureLoaded(){if(this.remote)return Promise.resolve();if(this.loaded)return Promise.resolve();if(this.loadPromise)return this.loadPromise;this.loadPromise=(async()=>{let t=null;try{t=await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.network.overrides())}catch{}this.hydrate(t)})();return this.loadPromise}loadNow(){if(this.remote||this.loaded||this.loadPromise)return;let t;try{t=globalThis.localStorage?.getItem(_sharedUi.devToolsStorageKeys.network.overrides())??null}catch{return}if(t===null)return;this.hydrate(t)}hydrate(t){try{if(t&&!this.dirty){const s=JSON.parse(t);this.enabled=s?.enabled!==false;this.rules=parseRules(s?.rules);this.launchStreak=typeof s?.launchStreak==="number"?s.launchStreak:0;this.autoPaused=s?.autoPaused===true&&!this.enabled;this.applyLaunchGuard();this.rebuild()}}catch{}finally{this.loaded=true;this.syncKeepAlive();this.emit()}}applyLaunchGuard(){if(!this.enabled||this.activeCount()===0||this.rules.some(t=>t.enabled&&t.sandbox)){this.launchStreak=0;return}if(countedThisTab())return;this.launchStreak+=1;if(this.launchStreak>=MAX_UNTOUCHED_LAUNCHES){this.enabled=false;this.autoPaused=true;this.launchStreak=0}this.persist()}syncKeepAlive(){const t=!this.engineDisabled&&this.activeCount()>0;if(t&&!this.keepAlive){(0,_networkListener.startNetworkListener)();this.keepAlive=(0,_networkListener.addNetworkListener)(()=>{});return}if(!t&&this.keepAlive){this.keepAlive();this.keepAlive=null;if((0,_networkListener.getNetworkListenerCount)()===0)(0,_networkListener.stopNetworkListener)()}}scheduleHitEmit(){if(this.hitEmitTimer!==null)return;this.hitEmitTimer=setTimeout(()=>{this.hitEmitTimer=null;this.emit()},HIT_EMIT_COALESCE_MS)}commit(t){this.dirty=true;this.rules=t.slice(0,_types.MAX_RULES);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;_sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.network.overrides(),JSON.stringify({enabled:this.enabled,rules:this.rules,launchStreak:this.launchStreak,autoPaused:this.autoPaused})).catch(()=>{})}emit(){this.listeners.forEach(t=>t())}}const overrideRulesStore=exports.overrideRulesStore=new OverrideRulesStore;(0,_engine.setOverrideHooks)({getRules:()=>overrideRulesStore.getRules(),ready:()=>overrideRulesStore.ensureLoaded(),isReady:()=>overrideRulesStore.isLoaded(),recordHit:r=>overrideRulesStore.recordHit(r),recordMatch:r=>overrideRulesStore.recordMatch(r)});if(typeof window!=="undefined"&&typeof document!=="undefined"&&!(typeof navigator!=="undefined"&&navigator.product==="ReactNative")){overrideRulesStore.loadNow()}
@@ -1 +1 @@
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 _types=require("../overrides/types");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 n;try{n=buildWireEvent(e)}catch{n=buildMetadataOnly(e)}wireCache.set(e,n);return n}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 n=1024;try{n=(0,_sharedUi.approxJsonSize)(t,SNAPSHOT_EVENTS_BUDGET).bytes}catch{}return{event:t,bytes:n}}function buildWireEvent(e){const t=shouldStripBody(e.requestData,e.requestSize);const n=shouldStripBody(e.responseData,e.responseSize);const r=toWireGraphqlVariables(e.graphqlVariables);const o=toWireHeaders(e.requestHeaders);const s=toWireHeaders(e.responseHeaders);const d=t||n||r!==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(n){i.responseData=void 0;i.responseBodyOmitted=true}if(r!==e.graphqlVariables){i.graphqlVariables=r}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:n}=toWireEvent(e);const r={...n};if(r.requestData!==void 0){r.requestData=void 0;r.requestBodyOmitted=true}if(r.responseData!==void 0){r.responseData=void 0;r.responseBodyOmitted=true}if(r.graphqlVariables!==void 0){r.graphqlVariables=toWireGraphqlVariables(r.graphqlVariables,true)}const o={event:r,bytes:(0,_sharedUi.approxJsonSize)(r,SNAPSHOT_EVENTS_BUDGET).bytes};strippedCache.set(e,o);return o}function fitEventsToBudget(e){const t=new Array(e.length);let n=0;for(let r=0;r<e.length;r++){const o=toWireEvent(e[r]);if(n+o.bytes<=SNAPSHOT_EVENTS_BUDGET){t[r]=o.event;n+=o.bytes}else{const s=toStrippedEvent(e[r]);t[r]=s.event;n+=s.bytes}}return t}function toWireGraphqlVariables(e,t=false){if(!e)return e;if(!t&&!shouldStripBody(e,void 0))return e;const n={};for(const[r,o]of Object.entries(e)){if(typeof o==="string"&&o.length<=64)n[r]=o;else if(typeof o==="number"||typeof o==="boolean"){n[r]=o}}return Object.keys(n).length>0?n:void 0}const SNAPSHOT_HEADER_VALUE_LIMIT=exports.SNAPSHOT_HEADER_VALUE_LIMIT=64;function toWireHeaders(e){if(!e)return e;let t=false;const n={};for(const[r,o]of Object.entries(e)){if(typeof o!=="string")continue;if(o.length<=SNAPSHOT_HEADER_VALUE_LIMIT){n[r]=o}else{n[r]=`${o.slice(0,SNAPSHOT_HEADER_VALUE_LIMIT)}\u2026 [${o.length-SNAPSHOT_HEADER_VALUE_LIMIT} more]`;t=true}}return t?n:e}const stripLargeRuleBodies=e=>{let t=false;const n=e.rules.map(r=>{if(!r.body||r.body.length<=SNAPSHOT_BODY_INLINE_LIMIT){return r}t=true;return{...r,body:void 0,bodyOmitted:true}});return t?{...e,rules:n}: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 n=e.rule??e;if(!n||typeof n!=="object")return null;const r=n;const o=typeof r.urlPattern==="string"&&r.urlPattern.trim()?r.urlPattern.trim():t?.urlPattern??"";if(!o)return null;const s=VALID_KINDS.includes(r.kind)?r.kind:t?.kind??"respond";return{id:typeof r.id==="string"?r.id:void 0,enabled:r.enabled!==false,name:typeof r.name==="string"?r.name:t?.name,urlPattern:o,methods:Array.isArray(r.methods)?r.methods.filter(d=>typeof d==="string").map(d=>d.toUpperCase()):t?.methods,requireHeader:typeof r.requireHeader==="string"&&r.requireHeader.trim()?r.requireHeader.trim():void 0,bodyIncludes:typeof r.bodyIncludes==="string"&&r.bodyIncludes?r.bodyIncludes.slice(0,4096):t?.bodyIncludes,kind:s,status:typeof r.status==="number"?r.status:t?.status,statusText:typeof r.statusText==="string"?r.statusText:t?.statusText,headers:r.headers&&typeof r.headers==="object"?r.headers:t?.headers,body:patchedBody(r,t),failKind:r.failKind==="timeout"?"timeout":void 0,delayMs:typeof r.delayMs==="number"?r.delayMs:void 0,times:typeof r.times==="number"?r.times:null,alternate:r.alternate===true}}const isPlainObject=e=>!!e&&typeof e==="object"&&!Array.isArray(e);function deepMerge(e,t,n="",r={shrunk:[],breaks:[]}){if(Array.isArray(e)&&Array.isArray(t)){if(t.length>0&&t.length<e.length){r.shrunk.push({path:n||"(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=n?`${n}.${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){r.breaks.push({path:i,from:u,to:l})}o[s]=deepMerge(e[s],d,i,r)}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 n=t?.body??(isPlainObject(e.bodyPatch)&&typeof e.id==="string"?_overrideRulesStore.overrideRulesStore.getState().rules.find(r=>r.id===e.id)?.body:void 0);if(isPlainObject(e.bodyPatch)&&typeof n==="string"){try{return JSON.stringify(deepMerge(JSON.parse(n),e.bodyPatch),null,2)}catch{return n}}return n}function existingRule(e){if(!e||typeof e!=="object")return null;const t=e.rule??e;if(!t||typeof t!=="object")return null;const n=t.id;if(typeof n!=="string")return null;const r=_overrideRulesStore.overrideRulesStore.getState().rules.find(o=>o.id===n);return r?{...r}:null}function preservedBody(e){if(!e||typeof e!=="object")return null;const t=e.rule??e;if(!t||typeof t!=="object")return null;const n=t;if(n.bodyOmitted!==true||typeof n.id!=="string")return null;const r=_overrideRulesStore.overrideRulesStore.getState().rules.find(o=>o.id===n.id);return r?{body:r.body}:null}function baseFromRequest(e){if(!e||typeof e!=="object")return null;const t=e.fromRequestId;if(typeof t!=="string"||!t)return null;const n=resolveEvent(t);return n?(0,_presets.draftFromEvent)(n):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 n=(0,_store.subscribeNetworkConditions)(e);const r=_networkSavedStore.networkSavedStore.subscribe(e);const o=_overrideRulesStore.overrideRulesStore.subscribe(e);return()=>{n();t();r();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 n=resolveEvent(t);if(!n)return null;return{url:n.url??null,method:n.method??null,status:n.status??null,override:n.override??null,requestData:n.requestData??null,responseData:n.responseData??null,requestHeaders:n.requestHeaders??null,responseHeaders:n.responseHeaders??null}},setPinned:e=>{const t=readId(e);if(!t)return null;const n=resolveEvent(t);if(!n)return null;const r=readBool(e,"pinned");const o=(0,_networkSavedStore.flagsForEventId)(_networkSavedStore.networkSavedStore.getState(),t).pinned;if(o===r)return{ok:true};return _networkSavedStore.networkSavedStore.togglePin(n)},setSaved:e=>{const t=readId(e);if(!t)return null;const n=resolveEvent(t);if(!n)return null;const r=readBool(e,"saved");const o=(0,_networkSavedStore.flagsForEventId)(_networkSavedStore.networkSavedStore.getState(),t).saved;if(o===r)return{ok:true};return _networkSavedStore.networkSavedStore.toggleSave(n)},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=e?.rule??e;const n=!!t&&t.body==null&&(isPlainObject(t.bodyPatch)||typeof t.bodyPath==="string");const r=baseFromRequest(e)??preservedBody(e)??(n?existingRule(e):null);if(t&&typeof t.bodyPath==="string"&&t.body==null){const d=r?.body??(typeof t.id==="string"?_overrideRulesStore.overrideRulesStore.getState().rules.find(l=>l.id===t.id)?.body:void 0);if(typeof d!=="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(t.bodyValue===void 0){return{ok:false,error:`Refused: sent \`bodyPath\` without \`bodyValue\`. Say what to set "${t.bodyPath}" to.`}}let i;try{i=JSON.parse(d)}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 u=(0,_sharedUi.patchFromPath)(i,t.bodyPath,t.bodyValue);if(!u.ok)return{ok:false,error:`Refused: ${u.error}`};t.bodyPatch=u.patch;delete t.bodyPath;delete t.bodyValue}if(t&&isPlainObject(t.bodyPatch)&&t.body==null){const d=r?.body??(typeof t.id==="string"?_overrideRulesStore.overrideRulesStore.getState().rules.find(i=>i.id===t.id)?.body:void 0);if(typeof d!=="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(t.force!==true){let i;try{const l=(0,_sharedUi.expandKeyedArrays)(JSON.parse(d),t.bodyPatch);i=l.error;if(l.notes.length)t.bodyPatch=l.patch}catch{}if(i){return{ok:false,error:`Refused: ${i}`}}const u=patchViolations(t,d);if(u.length>0){return{ok:false,error:(0,_sharedUi.refusalText)(u,"response body",(0,_sharedUi.suggestedPatch)(t.bodyPatch,u)),violations:u}}}}const o=readRuleDraft(e,r);if(!o){const d=e?.fromRequestId;return{ok:false,error:d?`No captured request \`${d}\` \u2014 it may have been cleared. Send a urlPattern instead.`:"A rule needs a non-empty urlPattern."}}const s=_overrideRulesStore.overrideRulesStore.upsertRule(o);if(!s)return{ok:false,error:"Override rule limit reached."};if(s.enabled)_overrideRulesStore.overrideRulesStore.setEnabled(true);return{ok:true,rule:{id:s.id,urlPattern:s.urlPattern,enabled:s.enabled,kind:s.kind,status:s.status,times:s.times,bodySize:s.body?s.body.length:0},...s.times===void 0||s.times===null?{lingers:`This rule has no \`times\` budget, so it overrides EVERY matching request until it is disabled or deleted (id \`${s.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}},replaceOverrideRules:async e=>{const t=e??{};if(!Array.isArray(t.rules)){return{ok:false,error:"replaceOverrideRules needs `rules`: an array of rules, first match first."}}if(t.rules.length>_types.MAX_RULES){return{ok:false,error:`Too many rules: ${t.rules.length}. The most is ${_types.MAX_RULES}.`}}await _overrideRulesStore.overrideRulesStore.ensureLoaded();const n=_overrideRulesStore.overrideRulesStore.replaceAllRules(t.rules,t.enabled!==false);if(!n)return{ok:false,error:"This copy of the Network tool only mirrors a device, so it can't replace rules."};return{ok:true,count:n.length,enabled:_overrideRulesStore.overrideRulesStore.getState().enabled,...inactiveStamp()}},listOverrideRules:async()=>{await _overrideRulesStore.overrideRulesStore.ensureLoaded();return _overrideRulesStore.overrideRulesStore.getState()},getOverrideRuleBody:e=>{const t=readId(e);if(!t)return null;const n=_overrideRulesStore.overrideRulesStore.getState().rules.find(r=>r.id===t);if(!n)return null;return{body:n.body??null}},getCaptureStatus:()=>{const e=_networkEventStore.networkEventStore.getSubscriberCounts().total;let t=null;let n=null;try{t=(0,_networkListener.isNetworkListening)();n=(0,_networkListener.getNetworkListenerCount)()}catch{}let r=null;try{r=(0,_networkListener.isNetworkInterceptionLive)()}catch{}return{capturing:e>0,subscribers:e,interceptorInstalled:t,interceptorLive:r,listenerCount:n,eventCount:_networkEventStore.networkEventStore.getEvents().length}},debugOverrides:e=>{const{url:t,method:n}=e&&typeof e==="object"?e:{};const r=typeof t==="string"?t:"https://example.com/";const o=typeof n==="string"&&n.trim()?n.trim().toUpperCase():"GET";return{tested:{url:r,method:o},interceptorInstalled:(0,_networkListener.isNetworkListening)(),listenerCount:(0,_networkListener.getNetworkListenerCount)(),engine:(0,_engine.inspectEngine)(r,o),store:{enabled:_overrideRulesStore.overrideRulesStore.getState().enabled,autoPaused:_overrideRulesStore.overrideRulesStore.getState().autoPaused,ruleCount:_overrideRulesStore.overrideRulesStore.getState().rules.length,rulesVisibleToEngine:_overrideRulesStore.overrideRulesStore.getRules().length}}}}};
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 _types=require("../overrides/types");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 n;try{n=buildWireEvent(e)}catch{n=buildMetadataOnly(e)}wireCache.set(e,n);return n}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 n=1024;try{n=(0,_sharedUi.approxJsonSize)(t,SNAPSHOT_EVENTS_BUDGET).bytes}catch{}return{event:t,bytes:n}}function buildWireEvent(e){const t=shouldStripBody(e.requestData,e.requestSize);const n=shouldStripBody(e.responseData,e.responseSize);const r=toWireGraphqlVariables(e.graphqlVariables);const o=toWireHeaders(e.requestHeaders);const s=toWireHeaders(e.responseHeaders);const d=t||n||r!==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(n){i.responseData=void 0;i.responseBodyOmitted=true}if(r!==e.graphqlVariables){i.graphqlVariables=r}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:n}=toWireEvent(e);const r={...n};if(r.requestData!==void 0){r.requestData=void 0;r.requestBodyOmitted=true}if(r.responseData!==void 0){r.responseData=void 0;r.responseBodyOmitted=true}if(r.graphqlVariables!==void 0){r.graphqlVariables=toWireGraphqlVariables(r.graphqlVariables,true)}const o={event:r,bytes:(0,_sharedUi.approxJsonSize)(r,SNAPSHOT_EVENTS_BUDGET).bytes};strippedCache.set(e,o);return o}function fitEventsToBudget(e){const t=new Array(e.length);let n=0;for(let r=0;r<e.length;r++){const o=toWireEvent(e[r]);if(n+o.bytes<=SNAPSHOT_EVENTS_BUDGET){t[r]=o.event;n+=o.bytes}else{const s=toStrippedEvent(e[r]);t[r]=s.event;n+=s.bytes}}return t}function toWireGraphqlVariables(e,t=false){if(!e)return e;if(!t&&!shouldStripBody(e,void 0))return e;const n={};for(const[r,o]of Object.entries(e)){if(typeof o==="string"&&o.length<=64)n[r]=o;else if(typeof o==="number"||typeof o==="boolean"){n[r]=o}}return Object.keys(n).length>0?n:void 0}const SNAPSHOT_HEADER_VALUE_LIMIT=exports.SNAPSHOT_HEADER_VALUE_LIMIT=64;function toWireHeaders(e){if(!e)return e;let t=false;const n={};for(const[r,o]of Object.entries(e)){if(typeof o!=="string")continue;if(o.length<=SNAPSHOT_HEADER_VALUE_LIMIT){n[r]=o}else{n[r]=`${o.slice(0,SNAPSHOT_HEADER_VALUE_LIMIT)}\u2026 [${o.length-SNAPSHOT_HEADER_VALUE_LIMIT} more]`;t=true}}return t?n:e}const stripLargeRuleBodies=e=>{let t=false;const n=e.rules.map(r=>{if(!r.body||r.body.length<=SNAPSHOT_BODY_INLINE_LIMIT){return r}t=true;return{...r,body:void 0,bodyOmitted:true}});return t?{...e,rules:n}: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 n=e.rule??e;if(!n||typeof n!=="object")return null;const r=n;const o=typeof r.urlPattern==="string"&&r.urlPattern.trim()?r.urlPattern.trim():t?.urlPattern??"";if(!o)return null;const s=VALID_KINDS.includes(r.kind)?r.kind:t?.kind??"respond";return{id:typeof r.id==="string"?r.id:void 0,enabled:r.enabled!==false,name:typeof r.name==="string"?r.name:t?.name,urlPattern:o,methods:Array.isArray(r.methods)?r.methods.filter(d=>typeof d==="string").map(d=>d.toUpperCase()):t?.methods,requireHeader:typeof r.requireHeader==="string"&&r.requireHeader.trim()?r.requireHeader.trim():void 0,bodyIncludes:typeof r.bodyIncludes==="string"&&r.bodyIncludes?r.bodyIncludes.slice(0,4096):t?.bodyIncludes,graphqlOperation:typeof r.graphqlOperation==="string"&&r.graphqlOperation?r.graphqlOperation.slice(0,200):t?.graphqlOperation,graphqlVariables:typeof r.graphqlVariables==="string"?r.graphqlVariables.slice(0,4096):t?.graphqlVariables,sandbox:r.sandbox===true?true:void 0,kind:s,status:typeof r.status==="number"?r.status:t?.status,statusText:typeof r.statusText==="string"?r.statusText:t?.statusText,headers:r.headers&&typeof r.headers==="object"?r.headers:t?.headers,body:patchedBody(r,t),failKind:r.failKind==="timeout"?"timeout":void 0,delayMs:typeof r.delayMs==="number"?r.delayMs:void 0,times:typeof r.times==="number"?r.times:null,alternate:r.alternate===true}}const isPlainObject=e=>!!e&&typeof e==="object"&&!Array.isArray(e);const isBodyPatch=e=>isPlainObject(e)||Array.isArray(e);function deepMerge(e,t,n="",r={shrunk:[],breaks:[]}){if(Array.isArray(e)&&Array.isArray(t)){if(t.length>0&&t.length<e.length){r.shrunk.push({path:n||"(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=n?`${n}.${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){r.breaks.push({path:i,from:u,to:l})}o[s]=deepMerge(e[s],d,i,r)}else{o[s]=d}}return o}function patchViolations(e,t){if(e.body!=null||!isBodyPatch(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 n=t?.body??(isBodyPatch(e.bodyPatch)&&typeof e.id==="string"?_overrideRulesStore.overrideRulesStore.getState().rules.find(r=>r.id===e.id)?.body:void 0);if(isBodyPatch(e.bodyPatch)&&typeof n==="string"){try{return JSON.stringify(deepMerge(JSON.parse(n),e.bodyPatch),null,2)}catch{return n}}return n}function existingRule(e){if(!e||typeof e!=="object")return null;const t=e.rule??e;if(!t||typeof t!=="object")return null;const n=t.id;if(typeof n!=="string")return null;const r=_overrideRulesStore.overrideRulesStore.getState().rules.find(o=>o.id===n);return r?{...r}:null}function preservedBody(e){if(!e||typeof e!=="object")return null;const t=e.rule??e;if(!t||typeof t!=="object")return null;const n=t;if(n.bodyOmitted!==true||typeof n.id!=="string")return null;const r=_overrideRulesStore.overrideRulesStore.getState().rules.find(o=>o.id===n.id);return r?{body:r.body}:null}function baseFromRequest(e){if(!e||typeof e!=="object")return null;const t=e.fromRequestId;if(typeof t!=="string"||!t)return null;const n=resolveEvent(t);return n?(0,_presets.draftFromEvent)(n):null}const networkSyncAdapter=exports.networkSyncAdapter={dispose:()=>{_overrideRulesStore.overrideRulesStore.setEnabled(false)},version:6,getSnapshot:()=>{_networkEventStore.networkEventStore.ensureInterception();return{conditions:(0,_store.getNetworkConditions)(),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 n=(0,_store.subscribeNetworkConditions)(e);const r=_networkSavedStore.networkSavedStore.subscribe(e);const o=_overrideRulesStore.overrideRulesStore.subscribe(e);return()=>{n();t();r();o()}},actions:{getNetworkConditions:_store.getNetworkConditions,setNetworkConditions:_store.setNetworkConditions,clearEvents:()=>{_networkEventStore.networkEventStore.clearEvents()},getEventBody:e=>{const t=readId(e);if(!t)return null;const n=resolveEvent(t);if(!n)return null;return{url:n.url??null,method:n.method??null,status:n.status??null,override:n.override??null,condition:n.condition??null,requestData:n.requestData??null,responseData:n.responseData??null,requestHeaders:n.requestHeaders??null,responseHeaders:n.responseHeaders??null}},setPinned:e=>{const t=readId(e);if(!t)return null;const n=resolveEvent(t);if(!n)return null;const r=readBool(e,"pinned");const o=(0,_networkSavedStore.flagsForEventId)(_networkSavedStore.networkSavedStore.getState(),t).pinned;if(o===r)return{ok:true};return _networkSavedStore.networkSavedStore.togglePin(n)},setSaved:e=>{const t=readId(e);if(!t)return null;const n=resolveEvent(t);if(!n)return null;const r=readBool(e,"saved");const o=(0,_networkSavedStore.flagsForEventId)(_networkSavedStore.networkSavedStore.getState(),t).saved;if(o===r)return{ok:true};return _networkSavedStore.networkSavedStore.toggleSave(n)},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=e?.rule??e;const n=!!t&&t.body==null&&(isBodyPatch(t.bodyPatch)||typeof t.bodyPath==="string");const r=baseFromRequest(e)??preservedBody(e)??(n?existingRule(e):null);if(t&&typeof t.bodyPath==="string"&&t.body==null){const d=r?.body??(typeof t.id==="string"?_overrideRulesStore.overrideRulesStore.getState().rules.find(l=>l.id===t.id)?.body:void 0);if(typeof d!=="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(t.bodyValue===void 0){return{ok:false,error:`Refused: sent \`bodyPath\` without \`bodyValue\`. Say what to set "${t.bodyPath}" to.`}}let i;try{i=JSON.parse(d)}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 u=(0,_sharedUi.patchFromPath)(i,t.bodyPath,t.bodyValue);if(!u.ok)return{ok:false,error:`Refused: ${u.error}`};t.bodyPatch=u.patch;delete t.bodyPath;delete t.bodyValue}if(t&&isBodyPatch(t.bodyPatch)&&t.body==null){const d=r?.body??(typeof t.id==="string"?_overrideRulesStore.overrideRulesStore.getState().rules.find(u=>u.id===t.id)?.body:void 0);if(typeof d!=="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."}}let i;try{const u=(0,_sharedUi.expandKeyedArrays)(JSON.parse(d),t.bodyPatch);i=u.error;if(u.notes.length)t.bodyPatch=u.patch}catch{}if(i){return{ok:false,error:`Refused: ${i}`}}if(t.force!==true){const u=patchViolations(t,d);if(u.length>0){return{ok:false,error:(0,_sharedUi.refusalText)(u,"response body",(0,_sharedUi.suggestedPatch)(t.bodyPatch,u)),violations:u}}}}const o=readRuleDraft(e,r);if(!o){const d=e?.fromRequestId;return{ok:false,error:d?`No captured request \`${d}\` \u2014 it may have been cleared. Send a urlPattern instead.`:"A rule needs a non-empty urlPattern."}}const s=_overrideRulesStore.overrideRulesStore.upsertRule(o);if(!s)return{ok:false,error:"Override rule limit reached."};if(s.enabled)_overrideRulesStore.overrideRulesStore.setEnabled(true);return{ok:true,rule:{id:s.id,urlPattern:s.urlPattern,enabled:s.enabled,kind:s.kind,status:s.status,times:s.times,bodySize:s.body?s.body.length:0},...s.times===void 0||s.times===null?{lingers:`This rule has no \`times\` budget, so it overrides EVERY matching request until it is disabled or deleted (id \`${s.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}},replaceOverrideRules:async e=>{const t=e??{};if(!Array.isArray(t.rules)){return{ok:false,error:"replaceOverrideRules needs `rules`: an array of rules, first match first."}}if(t.rules.length>_types.MAX_RULES){return{ok:false,error:`Too many rules: ${t.rules.length}. The most is ${_types.MAX_RULES}.`}}await _overrideRulesStore.overrideRulesStore.ensureLoaded();const n=_overrideRulesStore.overrideRulesStore.replaceAllRules(t.rules,t.enabled!==false);if(!n)return{ok:false,error:"This copy of the Network tool only mirrors a device, so it can't replace rules."};return{ok:true,count:n.length,enabled:_overrideRulesStore.overrideRulesStore.getState().enabled,...inactiveStamp()}},listOverrideRules:async()=>{await _overrideRulesStore.overrideRulesStore.ensureLoaded();return _overrideRulesStore.overrideRulesStore.getState()},getOverrideRuleBody:e=>{const t=readId(e);if(!t)return null;const n=_overrideRulesStore.overrideRulesStore.getState().rules.find(r=>r.id===t);if(!n)return null;return{body:n.body??null}},getCaptureStatus:()=>{const e=_networkEventStore.networkEventStore.getSubscriberCounts().total;let t=null;let n=null;try{t=(0,_networkListener.isNetworkListening)();n=(0,_networkListener.getNetworkListenerCount)()}catch{}let r=null;try{r=(0,_networkListener.isNetworkInterceptionLive)()}catch{}return{capturing:e>0,subscribers:e,interceptorInstalled:t,interceptorLive:r,listenerCount:n,eventCount:_networkEventStore.networkEventStore.getEvents().length}},debugOverrides:e=>{const{url:t,method:n}=e&&typeof e==="object"?e:{};const r=typeof t==="string"?t:"https://example.com/";const o=typeof n==="string"&&n.trim()?n.trim().toUpperCase():"GET";return{tested:{url:r,method:o},interceptorInstalled:(0,_networkListener.isNetworkListening)(),listenerCount:(0,_networkListener.getNetworkListenerCount)(),engine:(0,_engine.inspectEngine)(r,o),store:{enabled:_overrideRulesStore.overrideRulesStore.getState().enabled,autoPaused:_overrideRulesStore.overrideRulesStore.getState().autoPaused,ruleCount:_overrideRulesStore.overrideRulesStore.getState().rules.length,rulesVisibleToEngine:_overrideRulesStore.overrideRulesStore.getRules().length}}}}};
@@ -5,6 +5,7 @@
5
5
  `}if(s.includeStatus){const o=e.status||"Pending";r+=`**Status:** ${o}${e.statusText?` (${e.statusText})`:""}
6
6
  `}if(s.includeClient&&e.requestClient){r+=`**Client:** ${e.requestClient}
7
7
  `}if(e.condition)r+=`Conditions: ${e.condition.profile} (+${e.condition.delayMs} ms)
8
+ `;if(e.condition?.uploadCap?.note)r+=`${e.condition.uploadCap.note}
8
9
  `;if(s.includeDuration&&e.duration){r+=`**Duration:** ${e.duration}ms
9
10
  `}if(s.includeTimestamp){r+=`**Timestamp:** ${new Date(e.timestamp).toISOString()}
10
11
  `}if(s.includeSizes){const o=e.requestSize?formatBytes(e.requestSize):"N/A";const t=e.responseSize?formatBytes(e.responseSize):"N/A";r+=`**Request Size:** ${o}