import{ar as v,aT as e,V as k,a5 as z,aa as P,bc as F,aY as p,aK as _,aP as H,b7 as V,a2 as W,p as C,a9 as Y,aq as $,c as T,ab as G,aR as J,ad as X,b9 as y,u as Z,an as Q}from"./chunk-02oqS8tD.js";import{e as ee}from"./chunk-Dp5WJOsV.js";import{M as A}from"./chunk-BPRhG5Pu.js";import{readTelemetrySignals as te}from"./chunk-ngFx90MH.js";import{c as se,a1 as ne,as as ae,J as oe}from"./chunk-B8Q4vgLh.js";import{C as re}from"./chunk-DATNr2Vu.js";import"./chunk-x_Z6cwvR.js";/**
 * @license lucide-react v0.451.0 - ISC
 *
 * This source code is licensed under the ISC license.
 * See the LICENSE file in the root directory of this source tree.
 */const ie=v("ArrowRight",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"m12 5 7 7-7 7",key:"xquz4c"}]]);/**
 * @license lucide-react v0.451.0 - ISC
 *
 * This source code is licensed under the ISC license.
 * See the LICENSE file in the root directory of this source tree.
 */const le=v("TrendingDown",[["polyline",{points:"22 17 13.5 8.5 8.5 13.5 2 7",key:"1r2t7k"}],["polyline",{points:"16 17 22 17 22 11",key:"11uiuu"}]]);/**
 * @license lucide-react v0.451.0 - ISC
 *
 * This source code is licensed under the ISC license.
 * See the LICENSE file in the root directory of this source tree.
 */const de=v("TrendingUp",[["polyline",{points:"22 7 13.5 15.5 8.5 10.5 2 17",key:"126l90"}],["polyline",{points:"16 7 22 7 22 13",key:"kwv8wd"}]]),O=50,I=3;function ce(t,s){const n={endpoints:[],beforeOnly:[],afterOnly:[],totalBefore:0,totalAfter:0};if(!t||t.capturing!==!0)return{...n,observed:!1,note:"Telemetry capture is off, so no requests are being watched. Turn it on, then apply a condition and use the app."};if(!s)return{...n,observed:!1,note:"No throttling is active. Apply a condition and then exercise the app — the requests made after that point are compared against the ones before it."};const o=t.requests.filter(l=>l.timestamp<s.appliedAt),r=t.requests.filter(l=>l.timestamp>=s.appliedAt);if(r.length===0)return{...n,observed:!1,conditions:s.conditions,appliedAt:s.appliedAt,totalBefore:o.length,note:o.length===0?"Nothing has been captured yet. Use the app — click through the journey you care about — and this fills in.":"The condition is applied, but the app has not made a request since. Use the app and this fills in."};const d=new Set,m=q(o,d),u=q(r,d),c=[],f=[],g=[];for(const l of[...d].sort()){const h=m.get(l),b=u.get(l);if(!h||!b){(h?f:g).push(l);continue}c.push(ue(l,L(h),L(b)))}return c.sort((l,h)=>E(l.verdict)-E(h.verdict)||(h.deltaMs??0)-(l.deltaMs??0)),{observed:!0,conditions:s.conditions,appliedAt:s.appliedAt,endpoints:c,beforeOnly:f,afterOnly:g,totalBefore:o.length,totalAfter:r.length,note:c.length===0?"No endpoint was called both before and after the change, so nothing can be compared yet. Use the same part of the app you used before applying the condition.":`Comparing ${String(o.length)} requests before the change with ${String(r.length)} after it.`}}function q(t,s){const n=new Map;for(const o of t){const r=`${o.method} ${ee(o.url)}`;s.add(r);const d=n.get(r)??[];d.push(o),n.set(r,d)}return n}function L(t){const s=t.filter(o=>!o.failed&&o.status>0).map(o=>o.duration).sort((o,r)=>o-r),n=t.filter(o=>o.failed||o.status===0||o.status>=400).length;return{requests:t.length,completed:s.length,failed:n,...s.length>0?{medianMs:me(s),slowestMs:s[s.length-1]}:{}}}function ue(t,s,n){const[o="GET",...r]=t.split(" "),d=r.join(" "),m=s.requests<I||n.requests<I,u={method:o,path:d,before:s,after:n,smallSample:m};if(s.completed>0&&n.completed===0)return{...u,verdict:"stopped-completing",explanation:`Completed ${String(s.completed)} times before the change and none after — ${String(n.requests)} attempt${n.requests===1?"":"s"} did not return.`};if(s.failed===0&&n.failed>0)return{...u,verdict:"started-failing",explanation:`Did not fail before the change; ${String(n.failed)} of ${String(n.requests)} failed after it.`};if(s.medianMs===void 0||n.medianMs===void 0)return{...u,verdict:"not-comparable",explanation:"Nothing completed on one side of the change, so there is no timing to compare."};const c=n.medianMs-s.medianMs;return Math.abs(c)<O?{...u,deltaMs:c,verdict:"no-measurable-change",explanation:`${x(s.medianMs)} → ${x(n.medianMs)}, within the ${String(O)} ms that identical calls vary by anyway.`}:{...u,deltaMs:c,verdict:c>0?"slower":"faster",explanation:`${x(s.medianMs)} → ${x(n.medianMs)} (${c>0?"+":""}${x(c)}${s.medianMs>0?`, ${pe(s.medianMs,n.medianMs)}`:""}).`}}function pe(t,s){const n=s/t;return n>=1.1?`${n.toFixed(1)}× slower`:n<=.9?`${(1/n).toFixed(1)}× faster`:"about the same multiple"}function E(t){return["stopped-completing","started-failing","slower","not-comparable","no-measurable-change","faster"].indexOf(t)}function me(t){return t.length===0?0:t[Math.min(t.length-1,Math.max(0,Math.ceil(.5*t.length)-1))]??0}function x(t){const s=Math.abs(t);return s>=1e3?`${(t/1e3).toFixed(s>=1e4?0:1)} s`:`${String(Math.round(t))} ms`}const he={"stopped-completing":{label:"Stopped completing",className:"bg-alert-orange/15 text-alert-orange",icon:P},"started-failing":{label:"Started failing",className:"bg-alert-orange/15 text-alert-orange",icon:z},slower:{label:"Slower",className:"bg-amber-500/15 text-amber-700 dark:text-amber-400",icon:de},"not-comparable":{label:"Not comparable",className:"bg-stroke/25 text-muted-foreground",icon:A},"no-measurable-change":{label:"No change",className:"bg-stroke/25 text-muted-foreground",icon:A},faster:{label:"Faster",className:"bg-emerald-500/15 text-emerald-700 dark:text-emerald-400",icon:le}};function fe({report:t}){return t.observed?e.jsxs(k,{title:"Effect on the app's API calls",hint:t.conditions?`Since ${t.conditions.presetId.toUpperCase()} was applied`:void 0,children:[e.jsx("p",{className:"mb-2 text-[9.5px] leading-snug text-muted-foreground",children:t.note}),t.endpoints.length>0&&e.jsx("div",{className:"space-y-1",children:t.endpoints.map(s=>e.jsx(ge,{endpoint:s},`${s.method} ${s.path}`))}),(t.beforeOnly.length>0||t.afterOnly.length>0)&&e.jsxs("div",{className:"mt-2 rounded-lg border border-stroke/70 px-2.5 py-2 dark:border-stroke/25",children:[e.jsx("p",{className:"text-[9.5px] font-semibold uppercase tracking-wide text-muted-foreground",children:"Not compared"}),t.beforeOnly.length>0&&e.jsxs("p",{className:"mt-1 text-[9.5px] leading-snug text-muted-foreground",children:["Called only ",e.jsx("strong",{children:"before"})," the change, so there is nothing to compare against:"," ",t.beforeOnly.slice(0,6).join(", "),t.beforeOnly.length>6?` and ${String(t.beforeOnly.length-6)} more`:"","."]}),t.afterOnly.length>0&&e.jsxs("p",{className:"mt-1 text-[9.5px] leading-snug text-muted-foreground",children:["Called only ",e.jsx("strong",{children:"after"})," the change:"," ",t.afterOnly.slice(0,6).join(", "),t.afterOnly.length>6?` and ${String(t.afterOnly.length-6)} more`:"","."]})]}),e.jsx("p",{className:"mt-2 text-[9px] leading-snug text-muted-foreground",children:"This compares what happened before and after the condition was applied. Requests can also differ because you used the app differently — it is a comparison, not proof of cause."})]}):e.jsx(k,{title:"Effect on the app's API calls",children:e.jsx("div",{className:"rounded-lg border border-dashed border-stroke px-3 py-4 text-center dark:border-stroke/30",children:e.jsx("p",{className:"text-[10.5px] leading-snug text-muted-foreground",children:t.note})})})}function ge({endpoint:t}){const s=he[t.verdict],n=s.icon;return e.jsxs("div",{className:"rounded-lg border border-stroke/70 px-2.5 py-2 dark:border-stroke/25",children:[e.jsxs("div",{className:"flex items-start gap-1.5",children:[e.jsxs("span",{className:`mt-px flex shrink-0 items-center gap-1 rounded px-1.5 py-0.5 text-[9px] font-bold uppercase tracking-wide ${s.className}`,children:[e.jsx(n,{className:"h-2.5 w-2.5"}),s.label]}),e.jsxs("span",{className:"min-w-0 flex-1 break-all font-mono text-[10px] leading-snug",children:[e.jsx("span",{className:"font-semibold",children:t.method})," ",t.path]})]}),e.jsx("p",{className:"mt-1 text-[9.5px] leading-snug text-muted-foreground",children:t.explanation}),e.jsxs("div",{className:"mt-1.5 flex items-center gap-2 text-[9px] tabular-nums text-muted-foreground",children:[e.jsx(R,{label:"Before",stats:t.before}),e.jsx(ie,{className:"h-2.5 w-2.5 shrink-0"}),e.jsx(R,{label:"After",stats:t.after}),t.smallSample&&e.jsx("span",{className:"ml-auto shrink-0 rounded bg-stroke/25 px-1 py-0.5 text-[8.5px] font-semibold",children:"small sample"})]})]})}function R({label:t,stats:s}){return s?e.jsxs("span",{children:[t,": ",s.medianMs===void 0?"no timing":x(s.medianMs)," · ",s.requests," call",s.requests===1?"":"s",s.failed>0?`, ${String(s.failed)} failed`:""]}):e.jsxs("span",{children:[t,": none"]})}function Se(){const t=F(a=>a.go),[s,n]=p.useState(null),[o,r]=p.useState(!1),[d,m]=p.useState(null),[u,c]=p.useState(!0),[f,g]=p.useState({presetId:"custom",offline:!1,latencyMs:200,downloadKbps:1e3,uploadKbps:500,packetLoss:0}),[l,h]=p.useState(!1),[b,N]=p.useState(null),w=p.useCallback(()=>{_().then(a=>{n(a),a&&a.conditions.presetId==="custom"&&(g(a.conditions),h(!0))}),H().then(a=>{if(!a.ok)return c(a.error);c(a.value.targetable===!1?"Switch to a normal web page — Chrome does not allow throttling its own pages.":a.value.tabId===null?"Open the app under test in a browser window first.":!0)})},[]);p.useEffect(()=>(w(),V(w)),[w]),p.useEffect(()=>{if(!s){N(null);return}let a=!0;const i=()=>{te().then(D=>{a&&N(D)})};i();const K=setInterval(i,3e3);return()=>{a=!1,clearInterval(K)}},[s]);const B=p.useMemo(()=>ce(b,s?{conditions:s.conditions,appliedAt:s.appliedAt}:null),[b,s]),S=async a=>{r(!0),m(null);const i=await X(a);if(r(!1),!i.ok){m(i.error);return}if(n(i.value),i.value===null){y.info("Throttling removed");return}i.value.packetLossStatus==="rejected"?y.info("Throttling applied — but this browser refused the packet-loss setting"):i.value.packetLossStatus==="unverified"?y.success(`Network set to ${i.value.conditions.presetId.toUpperCase()} — packet loss unverified`):y.success(`Network set to ${i.value.conditions.presetId.toUpperCase()}`)},U=async()=>{r(!0),await Q(),r(!1),n(null),y.info("Throttling removed")},M=s?.conditions.presetId??"online";return e.jsxs(W,{title:"Network",subtitle:"Throttle the tab under test, and record the conditions with the run.",onBack:()=>t(J("tools")),actions:s?e.jsxs(T,{size:"sm",variant:"outline",className:"h-7",onClick:U,loading:o,children:[e.jsx(G,{className:"h-3 w-3"}),"Stop"]}):void 0,sticky:s?e.jsx(xe,{state:s}):void 0,children:[u!==!0&&e.jsx(C,{title:"Not available here",message:u,onRetry:w}),d&&e.jsx(C,{message:d,onRetry:()=>m(null),retryLabel:"Dismiss"}),s&&e.jsx(fe,{report:B}),e.jsx(k,{title:"Presets",children:e.jsx("div",{className:"space-y-1.5",children:se.map(a=>e.jsxs("button",{type:"button",disabled:o||u!==!0,onClick:()=>{h(!1),S(a.conditions)},className:$("flex w-full items-center gap-2 rounded-lg border px-2.5 py-2 text-left transition-colors",M===a.id&&!l?"border-dynamic-azure bg-dynamic-azure/[0.07]":"border-stroke/70 hover:border-dynamic-azure/40 dark:border-stroke/25",(o||u!==!0)&&"cursor-not-allowed opacity-50"),children:[a.conditions.offline?e.jsx(P,{className:"h-3.5 w-3.5 shrink-0 text-alert-orange"}):e.jsx(Y,{className:$("h-3.5 w-3.5 shrink-0",M===a.id&&!l?"text-dynamic-azure":"text-muted-foreground")}),e.jsxs("span",{className:"min-w-0 flex-1",children:[e.jsx("span",{className:"block text-[11px] font-semibold",children:a.label}),e.jsx("span",{className:"block text-[10px] text-muted-foreground",children:a.hint})]}),a.id!=="online"&&!a.conditions.offline&&e.jsxs("span",{className:"shrink-0 font-mono text-[9px] text-muted-foreground",children:[String(a.conditions.latencyMs),"ms · ",ne(a.conditions.downloadKbps)]})]},a.id))})}),e.jsx(k,{title:"Custom",hint:"Latency in milliseconds, bandwidth in kilobits per second.",actions:e.jsx("button",{type:"button",onClick:()=>h(a=>!a),className:"text-[10px] font-semibold text-dynamic-azure hover:underline",children:l?"Hide":"Configure"}),children:l&&e.jsxs("div",{className:"space-y-2 rounded-lg border border-stroke/70 p-2.5 dark:border-stroke/25",children:[e.jsx(j,{label:"Latency",suffix:"ms",value:f.latencyMs,onChange:a=>g(i=>({...i,latencyMs:a}))}),e.jsx(j,{label:"Download",suffix:"kbps",value:f.downloadKbps,onChange:a=>g(i=>({...i,downloadKbps:a})),hint:f.downloadKbps===0?"Zero download is applied as fully offline.":void 0}),e.jsx(j,{label:"Upload",suffix:"kbps",value:f.uploadKbps,onChange:a=>g(i=>({...i,uploadKbps:a}))}),e.jsx(j,{label:"Packet loss",suffix:"%",value:f.packetLoss,max:100,onChange:a=>g(i=>({...i,packetLoss:a})),hint:"Only recent Chrome versions apply this. You will be told if yours does not."}),e.jsx(T,{size:"sm",className:"h-7 w-full",loading:o,disabled:u!==!0,onClick:()=>void S(ae(f)),children:"Apply custom conditions"})]})}),e.jsx(k,{title:"How this works",children:e.jsx("div",{className:"rounded-lg bg-stroke/10 p-2.5 dark:bg-white/[0.03]",children:e.jsx("p",{className:"text-[10px] leading-relaxed text-muted-foreground",children:"Throttling is applied to the tab under test through Chrome's debugger, so the tab shows a “being debugged” banner while it is active and DevTools cannot attach. It applies to one tab at a time, and the exact conditions are stored with every execution's environment snapshot — which is what makes a slow-network failure reproducible rather than anecdotal."})})})]})}function xe({state:t}){const s=oe(t.conditions);return e.jsxs("div",{className:"rounded-lg border border-dynamic-azure/40 bg-dynamic-azure/[0.07] p-2",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-x-2 gap-y-0.5",children:[e.jsxs("span",{className:"flex items-center gap-1 text-[11px] font-semibold text-dynamic-azure",children:[e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-dynamic-azure"}),t.conditions.presetId==="custom"?"Custom":t.conditions.presetId.toUpperCase()]}),s.map(n=>e.jsx("span",{className:"font-mono text-[10px] text-muted-foreground",children:n},n))]}),t.packetLossStatus==="rejected"&&e.jsxs("p",{className:"mt-1.5 flex items-start gap-1 text-[10px] leading-snug text-alert-orange",children:[e.jsx(z,{className:"mt-0.5 h-2.5 w-2.5 shrink-0"}),e.jsxs("span",{children:["Packet loss was ",e.jsx("strong",{children:"not"})," applied — this Chrome build rejected it",t.packetLossReason?` (${t.packetLossReason})`:"",". Latency and bandwidth are in force."]})]}),t.packetLossStatus==="unverified"&&e.jsxs("p",{className:"mt-1.5 flex items-start gap-1 text-[10px] leading-snug text-muted-foreground",children:[e.jsx(re,{className:"mt-0.5 h-2.5 w-2.5 shrink-0"}),e.jsx("span",{children:"Packet loss was requested and accepted, but Chrome does not report whether it is enforcing it. Treat it as best-effort; latency and bandwidth are verified."})]})]})}function j({label:t,suffix:s,value:n,onChange:o,max:r,hint:d}){return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("label",{className:"w-[86px] shrink-0 text-[11px] text-muted-foreground",children:t}),e.jsxs("div",{className:"relative flex-1",children:[e.jsx(Z,{type:"number",min:0,max:r,value:String(n),onChange:m=>o(m.target.value===""?0:Number(m.target.value)),className:"h-7 pr-11 text-xs"}),e.jsx("span",{className:"pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-[10px] text-muted-foreground",children:s})]})]}),d&&e.jsx("p",{className:"ml-[94px] mt-0.5 text-[9.5px] leading-snug text-muted-foreground/80",children:d})]})}export{Se as NetworkSimScreen};
//# sourceMappingURL=chunk-Bet5ZJVe.js.map
