1import{c as Z,r as o,j as e,t as G,ac as ve,B as h,ai as y,s as O}from"./index-B3Cp9eUl.js";import{C as k,a as C,b as S,d as L,c as B}from"./card-BaD_Iern.js";import{I as E}from"./input-UMssmug8.js";import{L as H}from"./label-DlCm5ehQ.js";import{B as se}from"./badge-bRWHsEAY.js";import{Z as fe,T as ye,A as te,e as Ne,f as be,g as z,h as D,F as _e,a as ke}from"./AdminPage-D_xEpAqj.js";import{T as I}from"./textarea-CMl24lJD.js";import{T as Ce,a as Se,b as ae,c as m,d as Le,e as u}from"./table-r3pVM_Fz.js";import{D as V}from"./download-BJiRWPu7.js";import"./index-CU3j4Y0c.js";import"./house-CkYa7aiC.js";import"./chevron-right-ChDFvrVP.js";import"./bannerLabel-DU1N32Mz.js";import"./image-B2mEdJ-0.js";import"./youtube-BEBNoYtS.js";import"./link-2-CAEt01tY.js";import"./map-pin-BKb09OVn.js";import"./imageFallback-QdZLgMpg.js";import"./star-BkO6JcFZ.js";import"./clock-CYbZlrfS.js";import"./arrow-right-CPBovuPk.js";import"./award-BBRuFPlB.js";import"./calendar-B5CJ2pS5.js";import"./external-link-DNLIumS4.js";import"./dollar-sign-BcrykzQh.js";/** 2 * @license lucide-react v0.462.0 - ISC 3 * 4 * This source code is licensed under the ISC license. 5 * See the LICENSE file in the root directory of this source tree. 6 */const Re=Z("FileCode",[["path",{d:"M10 12.5 8 15l2 2.5",key:"1tg20x"}],["path",{d:"m14 12.5 2 2.5-2 2.5",key:"yinavb"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z",key:"1mlx9k"}]]);/** 7 * @license lucide-react v0.462.0 - ISC 8 * 9 * This source code is licensed under the ISC license. 10 * See the LICENSE file in the root directory of this source tree. 11 */const Me=Z("FileSpreadsheet",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M8 13h2",key:"yr2amv"}],["path",{d:"M14 13h2",key:"un5t4a"}],["path",{d:"M8 17h2",key:"2yhykz"}],["path",{d:"M14 17h2",key:"10kma7"}]]);/** 12 * @license lucide-react v0.462.0 - ISC 13 * 14 * This source code is licensed under the ISC license. 15 * See the LICENSE file in the root directory of this source tree. 16 */const we=Z("History",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]]),Te=ve("relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",{variants:{variant:{default:"bg-background text-foreground",destructive:"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive"}},defaultVariants:{variant:"default"}}),J=o.forwardRef(({className:t,variant:r,...a},d)=>e.jsx("div",{ref:d,role:"alert",className:G(Te({variant:r}),t),...a}));J.displayName="Alert";const Fe=o.forwardRef(({className:t,...r},a)=>e.jsx("h5",{ref:a,className:G("mb-1 font-medium leading-none tracking-tight",t),...r}));Fe.displayName="AlertTitle";const P=o.forwardRef(({className:t,...r},a)=>e.jsx("div",{ref:a,className:G("text-sm [&_p]:leading-relaxed",t),...r}));P.displayName="AlertDescription";const rs=()=>{const[t,r]=o.useState(window.location.origin+"/"),[a,d]=o.useState(100),[n,p]=o.useState(10),[g,v]=o.useState(!1),[ce,R]=o.useState(0),[i,M]=o.useState(null),[K,w]=o.useState(null),T=(s,l)=>{if(s.length===0)return 0;const N=Math.min(s.length-1,Math.floor(s.length*l/100));return s[N]},de=async()=>{if(w(null),M(null),R(0),a>5e3){w("Limite máximo: 5000 requests por execução (proteção).");return}if(n>100){w("Limite máximo: 100 conexões simultâneas (proteção do navegador).");return}v(!0);const s=[],l={};let N=0,$=0,A=0;const he=performance.now();let Y=0;const pe=async()=>{for(;Y<a&&!(Y++>=a);){const b=performance.now();try{const _=await fetch(t,{method:"GET",mode:"cors",credentials:"omit"});await _.text();const ge=performance.now()-b;s.push(ge),l[_.status]=(l[_.status]||0)+1,_.ok?N++:$++}catch{$++,l[0]=(l[0]||0)+1}A++,A%Math.max(1,Math.floor(a/50))===0&&R(Math.round(A/a*100))}};await Promise.all(Array.from({length:n},()=>pe()));const ee=performance.now()-he,f=[...s].sort((x,b)=>x-b),je=s.reduce((x,b)=>x+b,0)/(s.length||1),c={total:a,success:N,failed:$,durationMs:ee,rps:N*1e3/ee,avgLatencyMs:je,p50:T(f,50),p95:T(f,95),p99:T(f,99),minLatency:f[0]||0,maxLatency:f[f.length-1]||0,statusCounts:l};M(c),R(100),v(!1);try{const{error:x}=await O.from("load_test_results").insert({url:t,total_requests:a,concurrency:n,duration_ms:c.durationMs,rps:c.rps,avg_latency_ms:c.avgLatencyMs,p50_ms:c.p50,p95_ms:c.p95,p99_ms:c.p99,min_latency_ms:c.minLatency,max_latency_ms:c.maxLatency,success_count:c.success,failed_count:c.failed,status_counts:c.statusCounts});if(x)throw x;y({title:"Resultado salvo no histórico"}),F()}catch(x){y({title:"Não foi possÃvel salvar histórico",description:x.message,variant:"destructive"})}},[Q,xe]=o.useState([]),[me,X]=o.useState(!1),F=async()=>{X(!0);const{data:s,error:l}=await O.from("load_test_results").select("*").order("created_at",{ascending:!1}).limit(100);l?y({title:"Erro ao carregar histórico",description:l.message,variant:"destructive"}):xe(s||[]),X(!1)};o.useEffect(()=>{F()},[]);const ue=async s=>{if(!confirm("Excluir este registro do histórico?"))return;const{error:l}=await O.from("load_test_results").delete().eq("id",s);l?y({title:"Erro ao excluir",description:l.message,variant:"destructive"}):(y({title:"Registro excluÃdo"}),F())},q=s=>({total:s.total_requests,success:s.success_count,failed:s.failed_count,durationMs:s.duration_ms,rps:s.rps,avgLatencyMs:s.avg_latency_ms,p50:s.p50_ms,p95:s.p95_ms,p99:s.p99_ms,minLatency:s.min_latency_ms,maxLatency:s.max_latency_ms,statusCounts:s.status_counts});return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("h2",{className:"text-2xl font-bold flex items-center gap-2",children:[e.jsx(fe,{className:"w-6 h-6"})," Teste de Carga"]}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Mede capacidade real (RPS, latência p50/p95/p99) disparando requests do navegador."})]}),e.jsxs(J,{children:[e.jsx(ye,{className:"h-4 w-4"}),e.jsxs(P,{children:["O teste roda ",e.jsx("strong",{children:"do seu navegador"}),", então mede também a sua conexão. Ideal para medir efeito do cache. Para teste real de servidor, use ferramentas externas (k6, autocannon) após migrar o domÃnio. Não abuse â limites: 5000 reqs / 100 paralelos."]})]}),e.jsxs(k,{children:[e.jsx(C,{children:e.jsx(S,{children:"Configuração"})}),e.jsxs(L,{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(H,{children:"URL alvo"}),e.jsx(E,{value:t,onChange:s=>r(s.target.value),placeholder:"https://..."}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Use a URL pública do seu site (ou de uma página especÃfica) para testar com cache real."})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{children:[e.jsx(H,{children:"Total de requests"}),e.jsx(E,{type:"number",value:a,onChange:s=>d(Number(s.target.value)),min:1,max:5e3})]}),e.jsxs("div",{children:[e.jsx(H,{children:"Conexões simultâneas"}),e.jsx(E,{type:"number",value:n,onChange:s=>p(Number(s.target.value)),min:1,max:100})]})]}),e.jsx(h,{onClick:de,disabled:g,children:g?`Rodando... ${ce}%`:"Iniciar teste"})]})]}),K&&e.jsx(J,{variant:"destructive",children:e.jsx(P,{children:K})}),i&&e.jsxs(k,{className:"border-primary/40",children:[e.jsxs(C,{children:[e.jsxs(S,{className:"flex items-center gap-2",children:[e.jsx(te,{className:"w-5 h-5"})," Resultados"]}),e.jsxs(B,{children:[i.success,"/",i.total," requests com sucesso em ",(i.durationMs/1e3).toFixed(2),"s"]})]}),e.jsxs(L,{children:[e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-3",children:[e.jsx(j,{label:"Requests/s",value:i.rps.toFixed(1),highlight:!0}),e.jsx(j,{label:"Latência média",value:`${i.avgLatencyMs.toFixed(0)} ms`}),e.jsx(j,{label:"p50",value:`${i.p50.toFixed(0)} ms`}),e.jsx(j,{label:"p95",value:`${i.p95.toFixed(0)} ms`,highlight:!0}),e.jsx(j,{label:"p99",value:`${i.p99.toFixed(0)} ms`}),e.jsx(j,{label:"MÃn / Máx",value:`${i.minLatency.toFixed(0)} / ${i.maxLatency.toFixed(0)}`}),e.jsx(j,{label:"Sucesso",value:i.success.toString()}),e.jsx(j,{label:"Falhas",value:i.failed.toString()})]}),e.jsxs("div",{className:"mt-4",children:[e.jsx("div",{className:"text-sm font-semibold mb-2",children:"Status HTTP"}),e.jsx("div",{className:"flex flex-wrap gap-2",children:Object.entries(i.statusCounts).map(([s,l])=>e.jsxs(se,{variant:s.startsWith("2")?"default":"destructive",children:[s==="0"?"Erro de rede":s,": ",l]},s))})]}),e.jsxs("div",{className:"mt-4 flex flex-wrap gap-2",children:[e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>re(i,t,a,n),children:[e.jsx(V,{className:"w-4 h-4"})," Exportar JSON"]}),e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>ne(i,t,a,n),children:[e.jsx(V,{className:"w-4 h-4"})," Exportar CSV"]})]})]})]}),e.jsxs(k,{children:[e.jsxs(C,{children:[e.jsxs(S,{className:"flex items-center gap-2",children:[e.jsx(Re,{className:"w-5 h-5"})," Scripts para servidor externo"]}),e.jsx(B,{children:"Gere um script com os parâmetros atuais (URL, total, concorrência) para rodar contra seu servidor após migração."})]}),e.jsx(L,{children:e.jsxs(Ne,{defaultValue:"k6",children:[e.jsxs(be,{children:[e.jsx(z,{value:"k6",children:"k6"}),e.jsx(z,{value:"autocannon",children:"autocannon"}),e.jsx(z,{value:"ab",children:"Apache Bench"})]}),e.jsxs(D,{value:"k6",className:"space-y-2",children:[e.jsx(I,{readOnly:!0,value:ie(t,a,n),rows:14,className:"font-mono text-xs"}),e.jsx(U,{content:ie(t,a,n),filename:"loadtest.k6.js"}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Rodar: ",e.jsx("code",{children:"k6 run loadtest.k6.js"})]})]}),e.jsxs(D,{value:"autocannon",className:"space-y-2",children:[e.jsx(I,{readOnly:!0,value:le(t,a,n),rows:10,className:"font-mono text-xs"}),e.jsx(U,{content:le(t,a,n),filename:"loadtest.autocannon.sh"}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Instalar: ",e.jsx("code",{children:"npm i -g autocannon"})," · Rodar: ",e.jsx("code",{children:"bash loadtest.autocannon.sh"})]})]}),e.jsxs(D,{value:"ab",className:"space-y-2",children:[e.jsx(I,{readOnly:!0,value:oe(t,a,n),rows:6,className:"font-mono text-xs"}),e.jsx(U,{content:oe(t,a,n),filename:"loadtest.ab.sh"}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Apache Bench (",e.jsx("code",{children:"ab"}),") já vem em muitos sistemas Unix."]})]})]})})]}),e.jsxs(k,{children:[e.jsxs(C,{children:[e.jsxs(S,{className:"flex items-center gap-2",children:[e.jsx(we,{className:"w-5 h-5"})," Histórico de testes"]}),e.jsx(B,{children:"Resultados anteriores ficam salvos automaticamente. Baixe CSV/JSON ou exclua registros antigos."})]}),e.jsx(L,{children:me?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Carregando..."}):Q.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Nenhum teste salvo ainda. Rode um teste para começar."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(Ce,{children:[e.jsx(Se,{children:e.jsxs(ae,{children:[e.jsx(m,{children:"Data"}),e.jsx(m,{children:"URL"}),e.jsx(m,{className:"text-right",children:"Reqs"}),e.jsx(m,{className:"text-right",children:"Conc."}),e.jsx(m,{className:"text-right",children:"RPS"}),e.jsx(m,{className:"text-right",children:"p95"}),e.jsx(m,{className:"text-right",children:"p99"}),e.jsx(m,{className:"text-right",children:"Falhas"}),e.jsx(m,{className:"text-right",children:"Ações"})]})}),e.jsx(Le,{children:Q.map(s=>e.jsxs(ae,{children:[e.jsx(u,{className:"text-xs whitespace-nowrap",children:new Date(s.created_at).toLocaleStr
16ing("pt-BR")}),e.jsx(u,{className:"max-w-[260px] truncate text-xs",title:s.url,children:s.url}),e.jsx(u,{className:"text-right text-xs",children:s.total_requests}),e.jsx(u,{className:"text-right text-xs",children:s.concurrency}),e.jsx(u,{className:"text-right text-xs font-semibold",children:s.rps.toFixed(1)}),e.jsxs(u,{className:"text-right text-xs",children:[s.p95_ms.toFixed(0)," ms"]}),e.jsxs(u,{className:"text-right text-xs",children:[s.p99_ms.toFixed(0)," ms"]}),e.jsx(u,{className:"text-right text-xs",children:s.failed_count>0?e.jsx(se,{variant:"destructive",children:s.failed_count}):e.jsx("span",{className:"text-muted-foreground",children:"0"})}),e.jsx(u,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-1",children:[e.jsx(h,{variant:"ghost",size:"sm",title:"Baixar JSON",onClick:()=>re(q(s),s.url,s.total_requests,s.concurrency),children:e.jsx(_e,{className:"w-4 h-4"})}),e.jsx(h,{variant:"ghost",size:"sm",title:"Baixar CSV",onClick:()=>ne(q(s),s.url,s.total_requests,s.concurrency),children:e.jsx(Me,{className:"w-4 h-4"})}),e.jsx(h,{variant:"ghost",size:"sm",title:"Reexibir resultado",onClick:()=>{M(q(s)),r(s.url),d(s.total_requests),p(s.concurrency)},children:e.jsx(te,{className:"w-4 h-4"})}),e.jsx(h,{variant:"ghost",size:"sm",title:"Excluir",onClick:()=>ue(s.id),children:e.jsx(ke,{className:"w-4 h-4 text-destructive"})})]})})]},s.id))})]})})})]})]})},U=({content:t,filename:r})=>e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(h,{variant:"outline",size:"sm",onClick:()=>W(r,t,"text/plain"),children:[e.jsx(V,{className:"w-4 h-4"})," Baixar"]}),e.jsx(h,{variant:"outline",size:"sm",onClick:()=>{navigator.clipboard.writeText(t),y({title:"Copiado!"})},children:"Copiar"})]}),W=(t,r,a)=>{const d=new Blob([r],{type:a}),n=URL.createObjectURL(d),p=document.createElement("a");p.href=n,p.download=t,p.click(),URL.revokeObjectURL(n)},re=(t,r,a,d)=>{const n={config:{url:r,total_requests:a,concurrency:d,generated_at:new Date().toISOString()},metrics:{rps:t.rps,avg_latency_ms:t.avgLatencyMs,p50_ms:t.p50,p95_ms:t.p95,p99_ms:t.p99,min_ms:t.minLatency,max_ms:t.maxLatency,duration_ms:t.durationMs,success:t.success,failed:t.failed},status_codes:t.statusCounts};W(`loadtest-${Date.now()}.json`,JSON.stringify(n,null,2),"application/json")},ne=(t,r,a,d)=>{const p=[["metric","value"],["url",r],["total_requests",a],["concurrency",d],["generated_at",new Date().toISOString()],["rps",t.rps.toFixed(2)],["avg_latency_ms",t.avgLatencyMs.toFixed(2)],["p50_ms",t.p50.toFixed(2)],["p95_ms",t.p95.toFixed(2)],["p99_ms",t.p99.toFixed(2)],["min_ms",t.minLatency.toFixed(2)],["max_ms",t.maxLatency.toFixed(2)],["duration_ms",t.durationMs.toFixed(2)],["success",t.success],["failed",t.failed],...Object.entries(t.statusCounts).map(([g,v])=>[`status_${g}`,v])].map(g=>g.map(v=>`"${String(v).replace(/"/g,'""')}"`).join(",")).join(` 17`);W(`loadtest-${Date.now()}.csv`,p,"text/csv")},ie=(t,r,a)=>`// k6 load test - gerado pelo painel 18// Rodar: k6 run loadtest.k6.js 19import http from 'k6/http'; 20import { check } from 'k6'; 21 22export const options = { 23 vus: ${a}, 24 iterations: ${r}, 25 thresholds: { 26 http_req_failed: ['rate<0.01'], 27 http_req_duration: ['p(95)<500', 'p(99)<1000'], 28 }, 29}; 30 31export default function () { 32 const res = http.get('${t}'); 33 check(res, { 'status 200': (r) => r.status === 200 }); 34} 35`,le=(t,r,a)=>`#!/bin/bash 36# autocannon load test - gerado pelo painel 37# Instalar: npm i -g autocannon 38# Rodar: bash loadtest.autocannon.sh 39 40autocannon \\ 41 -c ${a} \\ 42 -a ${r} \\ 43 --renderStatusCodes \\ 44 --json \\ 45 '${t}' | tee loadtest-result.json 46`,oe=(t,r,a)=>`#!/bin/bash 47# Apache Bench - gerado pelo painel 48# Rodar: bash loadtest.ab.sh 49ab -n ${r} -c ${a} -r '${t}' 50`,j=({label:t,value:r,highlight:a})=>e.jsxs("div",{className:`p-3 rounded ${a?"bg-primary/10":"bg-muted"}`,children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:t}),e.jsx("div",{className:"text-xl font-bold",children:r})]});export{rs as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.