diff --git a/repeater/web/html/assets/CADCalibration-DKpo6zSS.js b/repeater/web/html/assets/CADCalibration-CCeYRLvI.js
similarity index 99%
rename from repeater/web/html/assets/CADCalibration-DKpo6zSS.js
rename to repeater/web/html/assets/CADCalibration-CCeYRLvI.js
index f0e6866..b847de0 100644
--- a/repeater/web/html/assets/CADCalibration-DKpo6zSS.js
+++ b/repeater/web/html/assets/CADCalibration-CCeYRLvI.js
@@ -1 +1 @@
-import{a as G,M as K,c as Q,r as o,o as W,P as X,e as g,f as a,h as k,j as F,t as l,l as h,n as ee,L as T,Y as te,Z as ae,q as f,y as se}from"./index-3wuaCgEh.js";import{P as M}from"./plotly.min-DO11Gp-n.js";import"./_commonjsHelpers-CqkleIqs.js";const oe={class:"p-6 space-y-6"},re={class:"glass-card rounded-[15px] p-6"},le={class:"flex justify-center"},ne={class:"flex gap-4"},ie=["disabled"],ce=["disabled"],de={class:"glass-card rounded-[15px] p-6 space-y-4"},ue={class:"text-content-primary dark:text-content-primary"},ve={key:0,class:"p-4 bg-primary/10 border border-primary/30 rounded-lg"},pe={class:"text-content-primary dark:text-primary"},me={class:"space-y-2"},be={class:"w-full bg-white/10 rounded-full h-2"},ge={class:"text-content-secondary dark:text-content-muted text-sm"},fe={class:"grid grid-cols-2 md:grid-cols-4 gap-4"},xe={class:"glass-card rounded-[15px] p-4 text-center"},ye={class:"text-2xl font-bold text-primary"},_e={class:"glass-card rounded-[15px] p-4 text-center"},ke={class:"text-2xl font-bold text-primary"},he={class:"glass-card rounded-[15px] p-4 text-center"},Ce={class:"text-2xl font-bold text-primary"},we={class:"glass-card rounded-[15px] p-4 text-center"},Re={class:"text-2xl font-bold text-primary"},Se={key:0,class:"glass-card rounded-[15px] p-6 space-y-4"},De={key:0,class:"p-4 bg-accent-green/10 border border-accent-green/30 rounded-lg"},Ae={class:"text-content-primary dark:text-content-primary mb-4"},Be={key:1,class:"p-4 bg-secondary/20 border border-secondary/40 rounded-lg"},Ee=G({name:"CADCalibrationView",__name:"CADCalibration",setup(Fe){const m=K(),I=Q(()=>document.documentElement.classList.contains("dark")),P=()=>{const e=I.value;return{title:e?"#F9FAFB":"#111827",subtitle:e?"#9CA3AF":"#6B7280",axis:e?"#D1D5DB":"#374151",tick:e?"#9CA3AF":"#6B7280",grid:e?"rgba(148, 163, 184, 0.1)":"rgba(107, 114, 128, 0.15)",zeroline:e?"rgba(148, 163, 184, 0.2)":"rgba(107, 114, 128, 0.25)",line:e?"rgba(148, 163, 184, 0.3)":"rgba(107, 114, 128, 0.35)",colorbarBorder:e?"rgba(255,255,255,0.2)":"rgba(0,0,0,0.15)",markerLine:e?"rgba(255,255,255,0.2)":"rgba(0,0,0,0.15)"}},u=o(!1),C=o(null),r=o(null),v=o({}),n=o(null),$=o([]),j=o({}),d=o("Ready to start calibration"),x=o(0),b=o(0),w=o(0),R=o(0),S=o(0),D=o(0),i=o(null),A=o(!1),B=o(!1),y=o(!1),_=o(!1);let c=null;const N={responsive:!0,displayModeBar:!0,modeBarButtonsToRemove:["pan2d","select2d","lasso2d","autoScale2d"],displaylogo:!1,toImageButtonOptions:{format:"png",filename:"cad-calibration-heatmap",height:600,width:800,scale:2}};function O(){const e=P(),t=[{x:[],y:[],z:[],mode:"markers",type:"scatter",marker:{size:12,color:[],colorscale:[[0,"rgba(75, 85, 99, 0.4)"],[.1,"rgba(6, 182, 212, 0.3)"],[.5,"rgba(6, 182, 212, 0.6)"],[1,"rgba(16, 185, 129, 0.9)"]],showscale:!0,colorbar:{title:{text:"Detection Rate (%)",font:{color:e.axis,size:14}},tickfont:{color:e.tick},bgcolor:"rgba(0,0,0,0)",bordercolor:e.colorbarBorder,borderwidth:1,thickness:15},line:{color:e.markerLine,width:1}},hovertemplate:"Peak: %{x}
Min: %{y}
Detection Rate: %{marker.color:.1f}%
Channel Activity Detection Calibration`,font:{color:e.title,size:18},x:.5},xaxis:{title:{text:"CAD Peak Threshold",font:{color:e.axis,size:14}},tickfont:{color:e.tick},gridcolor:e.grid,zerolinecolor:e.zeroline,linecolor:e.line},yaxis:{title:{text:"CAD Min Threshold",font:{color:e.axis,size:14}},tickfont:{color:e.tick},gridcolor:e.grid,zerolinecolor:e.zeroline,linecolor:e.line},plot_bgcolor:"rgba(0, 0, 0, 0)",paper_bgcolor:"rgba(0, 0, 0, 0)",font:{color:e.title,family:"Inter, system-ui, sans-serif"},margin:{l:80,r:80,t:100,b:80},showlegend:!1};M.newPlot("plotly-chart",t,s,N)}function V(){if(Object.keys(v.value).length===0)return;const e=Object.values(v.value),t=[],s=[],p=[];for(const E of e)t.push(E.det_peak),s.push(E.det_min),p.push(E.detection_rate);const Z={x:[t],y:[s],"marker.color":[p],hovertemplate:"Peak: %{x}
Min: %{y}
Detection Rate: %{marker.color:.1f}%
Status: Tested
Manage companion identities (TCP frame server)
Manage companion identities (TCP frame server)
Permit flooding
Block flooding
Permit flooding
Block flooding
API tokens are used for machine-to-machine authentication. Include the token in the X-API-Key header when making API requests.
Tokens are only shown once at creation. Store them securely.
PyMC Console must be installed at /opt/pymc_console/web/html before selecting this option.
Web frontend changes will take effect after restarting the pymc-repeater service.
How the three systems work together: Each layer can be enabled/disabled independently and the others will still function.
Decision flow when all enabled: Adaptive tier check → Penalty box check → Token bucket check → Violation recording (triggers penalty box)
Activity tiers:Quiet (bypass limiting) → Normal (lighter: 0.5x intervals) → Busy (base: 1.0x intervals) → Congested (stricter: 2.0x intervals)
Note: Adaptive mode scales refill/min-interval timing; bucket capacity stays at the configured base value.
Mesh traffic can reach your repeater through different paths, so duplicate advert packets are expected.
This is normal behavior and helps prevent repeated rebroadcasts from flooding the mesh.
Each sender has a token bucket. Every forwarded advert uses one token.
If a sender keeps hitting the limit, it is temporarily blocked.
Adaptive mode adjusts limits based on recent advert activity.
This page is served over HTTP, not HTTPS. Exported data (including identity keys) will be transmitted in plain text. Only use these features on a trusted local network.
Download a complete backup including all passwords, JWT secrets, and identity keys. Required for restoring to a new device or recovering from a failed SD card.
Contains sensitive data. The backup file will include plain-text passwords and private keys. Store it securely and never share it.
Download the repeater's private identity key for backup. This key determines the node's address and cryptographic identity on the mesh.
Sensitive data. The identity key is the repeater's private key. Anyone with this key can impersonate your node. Store the exported file securely and never share it.
Permit flooding
Block flooding
Permit flooding
Block flooding
API tokens are used for machine-to-machine authentication. Include the token in the X-API-Key header when making API requests.
Tokens are only shown once at creation. Store them securely.
PyMC Console must be installed at /opt/pymc_console/web/html before selecting this option.
Web frontend changes will take effect after restarting the pymc-repeater service.
How the three systems work together: Each layer can be enabled/disabled independently and the others will still function.
Decision flow when all enabled: Adaptive tier check → Penalty box check → Token bucket check → Violation recording (triggers penalty box)
Activity tiers:Quiet (bypass limiting) → Normal (lighter: 0.5x intervals) → Busy (base: 1.0x intervals) → Congested (stricter: 2.0x intervals)
Note: Adaptive mode scales refill/min-interval timing; bucket capacity stays at the configured base value.
Mesh traffic can reach your repeater through different paths, so duplicate advert packets are expected.
This is normal behavior and helps prevent repeated rebroadcasts from flooding the mesh.
Each sender has a token bucket. Every forwarded advert uses one token.
If a sender keeps hitting the limit, it is temporarily blocked.
Adaptive mode adjusts limits based on recent advert activity.
This page is served over HTTP, not HTTPS. Exported data (including identity keys) will be transmitted in plain text. Only use these features on a trusted local network.
Download a complete backup including all passwords, JWT secrets, and identity keys. Required for restoring to a new device or recovering from a failed SD card.
Contains sensitive data. The backup file will include plain-text passwords and private keys. Store it securely and never share it.
Download the repeater's private identity key for backup. This key determines the node's address and cryptographic identity on the mesh.
Sensitive data. The identity key is the repeater's private key. Anyone with this key can impersonate your node. Store the exported file securely and never share it.
Activity (Last 24 Hours)
Activity (Last 24 Hours)
Access documentation, setup guides, troubleshooting tips, and community resources on our official wiki.
Visit Wiki DocumentationAccess documentation, setup guides, troubleshooting tips, and community resources on our official wiki.
Visit Wiki DocumentationSign in to access your dashboard
Sign in to access your dashboard
No logs match the current filter criteria.
',3)]))):(n(),s("div",ie,[(n(!0),s(L,null,N(_.value,(r,l)=>(n(),s("div",{key:l,class:"flex items-start gap-4 p-4 hover:bg-background-mute dark:hover:bg-stroke/5 transition-colors font-mono text-sm"},[o("span",ue," ["+c(O(r.timestamp))+"] ",1),o("span",ge,c(f(r.message)),1),o("span",{class:h(["flex-shrink-0 px-2 py-1 text-xs font-medium rounded",B(r.level)])},c(r.level),3),o("span",be,c(S(r.message)),1)]))),128))]))]))])]))}});export{ve as default}; +import{a as j,r as i,c as w,o as T,b as H,e as s,f as o,l as $,k as h,t as c,h as q,F as L,i as N,j as J,L as K,q as n}from"./index-xzvnOpJo.js";const P={class:"space-y-6"},Q={class:"glass-card backdrop-blur border border-stroke-subtle dark:border-white/10 rounded-[15px] p-6"},X={class:"flex items-center justify-between mb-4"},Y=["disabled"],Z={class:"bg-gray-50 dark:bg-white/5 border border-stroke-subtle dark:border-stroke/10 rounded-lg p-4"},ee={class:"flex flex-wrap gap-2"},te=["onClick"],re={key:0,class:"w-px h-6 bg-stroke-subtle dark:bg-stroke/20 mx-2 self-center"},oe=["onClick"],se={class:"glass-card backdrop-blur border border-stroke-subtle dark:border-white/10 rounded-[15px] overflow-hidden"},ne={key:0,class:"p-8 text-center"},ae={key:1,class:"p-8 text-center"},le={class:"text-content-secondary dark:text-content-muted mb-4"},de={key:2,class:"max-h-[600px] overflow-y-auto"},ce={key:0,class:"p-8 text-center"},ie={key:1,class:"divide-y divide-gray-200 dark:divide-white/5"},ue={class:"flex-shrink-0 text-content-secondary dark:text-content-muted"},ge={class:"flex-shrink-0 px-2 py-1 text-xs font-medium rounded bg-blue-500/20 text-blue-600 dark:text-blue-400"},be={class:"text-content-primary dark:text-content-primary flex-1 break-all"},ve=j({name:"LogsView",__name:"Logs",setup(xe){const x=i([]),a=i(new Set),d=i(new Set(["DEBUG","INFO","WARNING","ERROR"])),v=i(new Set),p=i(new Set),m=i(!0),k=i(null);let u=null;const f=t=>{const e=t.match(/- ([^-]+) - (?:DEBUG|INFO|WARNING|ERROR) -/);return e?e[1].trim():"Unknown"},S=t=>{const e=t.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} - [^-]+ - (?:DEBUG|INFO|WARNING|ERROR) - (.+)$/);return e?e[1]:t},R=(t,e)=>{if(t.size!==e.size)return!1;for(const r of t)if(!e.has(r))return!1;return!0},y=async()=>{try{const t=await K.getLogs();if(t.logs&&t.logs.length>0){x.value=t.logs;const e=new Set;x.value.forEach(b=>{const z=f(b.message);e.add(z)});const r=new Set;x.value.forEach(b=>{r.add(b.level)}),a.value.size===0&&(a.value=new Set(e));const l=!R(v.value,e),g=!R(p.value,r);l&&(v.value=e),g&&(p.value=r),k.value=null}}catch(t){console.error("Error loading logs:",t),k.value=t instanceof Error?t.message:"Failed to load logs"}finally{m.value=!1}},_=w(()=>x.value.filter(e=>{const r=f(e.message),l=a.value.has(r),g=d.value.has(e.level);return l&&g})),C=w(()=>Array.from(v.value).sort()),A=w(()=>{const t=["ERROR","WARNING","WARN","INFO","DEBUG"];return Array.from(p.value).sort((r,l)=>{const g=t.indexOf(r),b=t.indexOf(l);return g!==-1&&b!==-1?g-b:r.localeCompare(l)})}),I=t=>{d.value.has(t)?d.value.delete(t):d.value.add(t),d.value=new Set(d.value)},O=t=>new Date(t).toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"}),B=t=>({ERROR:"text-red-600 dark:text-red-400 bg-red-900/20",WARNING:"text-yellow-600 dark:text-yellow-400 bg-yellow-900/20",WARN:"text-yellow-600 dark:text-yellow-400 bg-yellow-900/20",INFO:"text-blue-600 dark:text-blue-400 bg-blue-900/20",DEBUG:"text-gray-400 bg-gray-900/20"})[t]||"text-gray-400 bg-gray-900/20",E=(t,e)=>e?{ERROR:"bg-red-100 dark:bg-red-500/20 text-red-600 dark:text-red-400 border-red-500/50",WARNING:"bg-yellow-100 dark:bg-yellow-500/20 text-yellow-600 dark:text-yellow-400 border-yellow-500/50",WARN:"bg-yellow-100 dark:bg-yellow-500/20 text-yellow-600 dark:text-yellow-400 border-yellow-500/50",INFO:"bg-blue-500/20 text-blue-600 dark:text-blue-400 border-blue-500/50",DEBUG:"bg-gray-500/20 text-gray-400 border-gray-500/50"}[t]||"bg-primary/20 text-primary border-primary/50":"bg-background-mute dark:bg-white/5 text-content-muted dark:text-white/60 border-stroke-subtle dark:border-white/20 hover:bg-stroke-subtle dark:hover:bg-white/10",G=t=>{a.value.has(t)?a.value.delete(t):a.value.add(t),a.value=new Set(a.value)},F=()=>{a.value=new Set(v.value)},M=()=>{a.value=new Set},D=()=>{d.value=new Set(p.value)},U=()=>{d.value=new Set},W=()=>{u&&clearInterval(u),u=setInterval(y,5e3)},V=()=>{u&&(clearInterval(u),u=null)};return T(()=>{y(),W()}),H(()=>{V()}),(t,e)=>(n(),s("div",P,[o("div",Q,[o("div",X,[e[1]||(e[1]=o("div",null,[o("h1",{class:"text-content-primary dark:text-content-primary text-2xl font-semibold mb-2"},"System Logs"),o("p",{class:"text-content-secondary dark:text-content-muted"},"Real-time system events and diagnostics")],-1)),o("button",{onClick:y,disabled:m.value,class:"flex items-center gap-2 px-4 py-2 bg-primary/20 hover:bg-primary/30 text-primary border border-primary/50 rounded-lg transition-colors disabled:opacity-50"},[(n(),s("svg",{class:h(["w-4 h-4",{"animate-spin":m.value}]),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},e[0]||(e[0]=[o("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"},null,-1)]),2)),$(" "+c(m.value?"Loading...":"Refresh"),1)],8,Y)]),o("div",Z,[o("div",{class:"flex flex-wrap items-center gap-3 mb-4"},[e[2]||(e[2]=o("span",{class:"text-content-primary dark:text-content-primary font-medium"},"Filters:",-1)),o("button",{onClick:F,class:"px-3 py-1 text-xs bg-accent-green/20 hover:bg-accent-green/30 text-accent-green border border-accent-green/50 rounded transition-colors"}," All Loggers "),o("button",{onClick:M,class:"px-3 py-1 text-xs bg-accent-red/20 hover:bg-accent-red/30 text-accent-red border border-accent-red/50 rounded transition-colors"}," Clear Loggers "),e[3]||(e[3]=o("div",{class:"w-px h-4 bg-white/20 mx-1"},null,-1)),o("button",{onClick:D,class:"px-3 py-1 text-xs bg-accent-green/20 hover:bg-accent-green/30 text-accent-green border border-accent-green/50 rounded transition-colors"}," All Levels "),o("button",{onClick:U,class:"px-3 py-1 text-xs bg-accent-red/20 hover:bg-accent-red/30 text-accent-red border border-accent-red/50 rounded transition-colors"}," Clear Levels ")]),o("div",ee,[(n(!0),s(L,null,N(C.value,r=>(n(),s("button",{key:"logger-"+r,onClick:l=>G(r),class:h(["px-3 py-1 text-xs border rounded-full transition-colors",a.value.has(r)?"bg-primary/20 text-primary border-primary/50":"bg-background-mute dark:bg-white/5 text-content-secondary dark:text-content-muted border-stroke-subtle dark:border-stroke/20 hover:bg-stroke-subtle dark:hover:bg-white/10"])},c(r),11,te))),128)),C.value.length>0&&A.value.length>0?(n(),s("div",re)):q("",!0),(n(!0),s(L,null,N(A.value,r=>(n(),s("button",{key:"level-"+r,onClick:l=>I(r),class:h(["px-3 py-1 text-xs border rounded-full transition-colors font-medium",d.value.has(r)?E(r,!0):E(r,!1)])},c(r),11,oe))),128))])])]),o("div",se,[m.value&&x.value.length===0?(n(),s("div",ne,e[4]||(e[4]=[o("div",{class:"animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"},null,-1),o("p",{class:"text-content-secondary dark:text-content-muted"},"Loading system logs...",-1)]))):k.value?(n(),s("div",ae,[e[5]||(e[5]=o("div",{class:"text-red-600 dark:text-red-400 mb-4"},[o("svg",{class:"w-12 h-12 mx-auto mb-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[o("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"})])],-1)),e[6]||(e[6]=o("h3",{class:"text-content-primary dark:text-content-primary text-lg font-medium mb-2"},"Error Loading Logs",-1)),o("p",le,c(k.value),1),o("button",{onClick:y,class:"px-4 py-2 bg-red-100 dark:bg-red-500/20 hover:bg-red-500/30 text-red-600 dark:text-red-400 border border-red-500/50 rounded-lg transition-colors"}," Try Again ")])):(n(),s("div",de,[_.value.length===0?(n(),s("div",ce,e[7]||(e[7]=[J('No logs match the current filter criteria.
',3)]))):(n(),s("div",ie,[(n(!0),s(L,null,N(_.value,(r,l)=>(n(),s("div",{key:l,class:"flex items-start gap-4 p-4 hover:bg-background-mute dark:hover:bg-stroke/5 transition-colors font-mono text-sm"},[o("span",ue," ["+c(O(r.timestamp))+"] ",1),o("span",ge,c(f(r.message)),1),o("span",{class:h(["flex-shrink-0 px-2 py-1 text-xs font-medium rounded",B(r.level)])},c(r.level),3),o("span",be,c(S(r.message)),1)]))),128))]))]))])]))}});export{ve as default}; diff --git a/repeater/web/html/assets/MessageDialog.vue_vue_type_script_setup_true_lang-Cf46XaoJ.js b/repeater/web/html/assets/MessageDialog.vue_vue_type_script_setup_true_lang-SzTqrYUh.js similarity index 97% rename from repeater/web/html/assets/MessageDialog.vue_vue_type_script_setup_true_lang-Cf46XaoJ.js rename to repeater/web/html/assets/MessageDialog.vue_vue_type_script_setup_true_lang-SzTqrYUh.js index b148282..222fcc8 100644 --- a/repeater/web/html/assets/MessageDialog.vue_vue_type_script_setup_true_lang-Cf46XaoJ.js +++ b/repeater/web/html/assets/MessageDialog.vue_vue_type_script_setup_true_lang-SzTqrYUh.js @@ -1 +1 @@ -import{a as k,e as o,h as g,f as r,k as a,t as p,x,q as s}from"./index-3wuaCgEh.js";const f={class:"mb-6"},m={key:0,class:"w-6 h-6",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},v={key:1,class:"w-6 h-6",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},h={key:2,class:"w-6 h-6",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},w={class:"text-content-secondary dark:text-content-primary/80 text-base leading-relaxed"},C={class:"flex"},B=k({__name:"MessageDialog",props:{show:{type:Boolean},message:{},variant:{default:"success"}},emits:["close"],setup(i,{emit:d}){const t=i,l=d,c=n=>{n.target===n.currentTarget&&l("close")},u={success:"bg-green-100 dark:bg-green-500/20 border-green-600/40 dark:border-green-500/30 text-green-600 dark:text-green-400",error:"bg-red-100 dark:bg-red-500/20 border-red-500/30 text-red-600 dark:text-red-400",info:"bg-blue-500/20 border-blue-500/30 text-blue-600 dark:text-blue-400"},b={success:"bg-green-500 hover:bg-green-600",error:"bg-red-500 hover:bg-red-600",info:"bg-blue-500 hover:bg-blue-600"};return(n,e)=>t.show?(s(),o("div",{key:0,onClick:c,class:"fixed inset-0 bg-black/40 backdrop-blur-lg z-[99999] flex items-center justify-center p-4",style:{"backdrop-filter":"blur(8px) saturate(180%)",position:"fixed",top:"0",left:"0",right:"0",bottom:"0"}},[r("div",{class:"bg-white dark:bg-surface-elevated backdrop-blur-xl rounded-[20px] p-6 w-full max-w-md border border-stroke-subtle dark:border-white/10",onClick:e[1]||(e[1]=x(()=>{},["stop"]))},[r("div",f,[r("div",{class:a(["inline-flex p-3 rounded-xl mb-4",u[t.variant]])},[t.variant==="success"?(s(),o("svg",m,e[2]||(e[2]=[r("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M5 13l4 4L19 7"},null,-1)]))):t.variant==="error"?(s(),o("svg",v,e[3]||(e[3]=[r("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M6 18L18 6M6 6l12 12"},null,-1)]))):(s(),o("svg",h,e[4]||(e[4]=[r("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"},null,-1)])))],2),r("p",w,p(t.message),1)]),r("div",C,[r("button",{onClick:e[0]||(e[0]=y=>l("close")),class:a(["flex-1 px-4 py-3 rounded-xl text-white transition-all duration-200",b[t.variant]])}," OK ",2)])])])):g("",!0)}});export{B as _}; +import{a as k,e as o,h as g,f as r,k as a,t as p,x,q as s}from"./index-xzvnOpJo.js";const f={class:"mb-6"},m={key:0,class:"w-6 h-6",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},v={key:1,class:"w-6 h-6",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},h={key:2,class:"w-6 h-6",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},w={class:"text-content-secondary dark:text-content-primary/80 text-base leading-relaxed"},C={class:"flex"},B=k({__name:"MessageDialog",props:{show:{type:Boolean},message:{},variant:{default:"success"}},emits:["close"],setup(i,{emit:d}){const t=i,l=d,c=n=>{n.target===n.currentTarget&&l("close")},u={success:"bg-green-100 dark:bg-green-500/20 border-green-600/40 dark:border-green-500/30 text-green-600 dark:text-green-400",error:"bg-red-100 dark:bg-red-500/20 border-red-500/30 text-red-600 dark:text-red-400",info:"bg-blue-500/20 border-blue-500/30 text-blue-600 dark:text-blue-400"},b={success:"bg-green-500 hover:bg-green-600",error:"bg-red-500 hover:bg-red-600",info:"bg-blue-500 hover:bg-blue-600"};return(n,e)=>t.show?(s(),o("div",{key:0,onClick:c,class:"fixed inset-0 bg-black/40 backdrop-blur-lg z-[99999] flex items-center justify-center p-4",style:{"backdrop-filter":"blur(8px) saturate(180%)",position:"fixed",top:"0",left:"0",right:"0",bottom:"0"}},[r("div",{class:"bg-white dark:bg-surface-elevated backdrop-blur-xl rounded-[20px] p-6 w-full max-w-md border border-stroke-subtle dark:border-white/10",onClick:e[1]||(e[1]=x(()=>{},["stop"]))},[r("div",f,[r("div",{class:a(["inline-flex p-3 rounded-xl mb-4",u[t.variant]])},[t.variant==="success"?(s(),o("svg",m,e[2]||(e[2]=[r("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M5 13l4 4L19 7"},null,-1)]))):t.variant==="error"?(s(),o("svg",v,e[3]||(e[3]=[r("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M6 18L18 6M6 6l12 12"},null,-1)]))):(s(),o("svg",h,e[4]||(e[4]=[r("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"},null,-1)])))],2),r("p",w,p(t.message),1)]),r("div",C,[r("button",{onClick:e[0]||(e[0]=y=>l("close")),class:a(["flex-1 px-4 py-3 rounded-xl text-white transition-all duration-200",b[t.variant]])}," OK ",2)])])])):g("",!0)}});export{B as _}; diff --git a/repeater/web/html/assets/Neighbors-gx2VL33X.js b/repeater/web/html/assets/Neighbors-Iq3xu5XJ.js similarity index 99% rename from repeater/web/html/assets/Neighbors-gx2VL33X.js rename to repeater/web/html/assets/Neighbors-Iq3xu5XJ.js index e4b34da..7a200a8 100644 --- a/repeater/web/html/assets/Neighbors-gx2VL33X.js +++ b/repeater/web/html/assets/Neighbors-Iq3xu5XJ.js @@ -1,4 +1,4 @@ -import{a as bt,e as _,h as P,f as t,t as w,x as Lt,q as k,M as Yt,r as D,c as q,E as ht,N as Rt,g as it,T as Ft,m as Dt,O as jt,k as C,F as ct,i as gt,y as It,l as et,o as Xt,P as te,j as ft,H as Pt,n as At,w as wt,Q as ie,s as Wt,v as le,L as Et}from"./index-3wuaCgEh.js";import{u as Ut}from"./useSignalQuality-1X2x5Xc0.js";import{L as Q}from"./leaflet-src-BtisrQHC.js";/* empty css */import{g as _t,s as Ct}from"./preferences-DtwbSSgO.js";import"./_commonjsHelpers-CqkleIqs.js";const de={class:"bg-gray-50 dark:bg-white/5 border border-stroke-subtle dark:border-stroke/10 rounded-lg p-4 mb-6"},ce={class:"flex items-center gap-3"},ue={class:"flex-1 min-w-0"},pe={class:"text-content-primary dark:text-content-primary font-medium truncate"},ge={class:"text-content-secondary dark:text-content-muted text-sm font-mono"},me={key:0,class:"text-white/50 text-xs"},he={key:1,class:"text-white/50 text-xs"},be=bt({__name:"DeleteNeighborModal",props:{show:{type:Boolean},neighbor:{}},emits:["close","delete"],setup($,{emit:r}){const o=$,i=r,e=()=>{o.neighbor&&(i("delete",o.neighbor.id),d())},d=()=>{i("close")},h=s=>{s.target===s.currentTarget&&d()};return(s,a)=>s.show&&s.neighbor?(k(),_("div",{key:0,onClick:h,class:"fixed inset-0 bg-black/80 backdrop-blur-lg z-[99999] flex items-center justify-center p-4",style:{"backdrop-filter":"blur(8px) saturate(180%)",position:"fixed",top:"0",left:"0",right:"0",bottom:"0"}},[t("div",{class:"bg-white dark:bg-surface-elevated backdrop-blur-xl rounded-[20px] p-6 w-full max-w-md border border-stroke-subtle dark:border-white/10",onClick:a[0]||(a[0]=Lt(()=>{},["stop"]))},[t("div",{class:"flex items-center gap-3 mb-6"},[a[2]||(a[2]=t("svg",{class:"w-6 h-6 text-accent-red",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[t("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"})],-1)),a[3]||(a[3]=t("div",null,[t("h3",{class:"text-xl font-semibold text-content-primary dark:text-content-primary"},"Delete Neighbor"),t("p",{class:"text-content-secondary dark:text-content-muted text-sm mt-1"}," Are you sure you want to delete this neighbor? ")],-1)),t("button",{onClick:d,class:"ml-auto text-content-secondary dark:text-content-muted hover:text-content-primary dark:hover:text-content-primary transition-colors"},a[1]||(a[1]=[t("svg",{class:"w-5 h-5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[t("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M6 18L18 6M6 6l12 12"})],-1)]))]),t("div",de,[t("div",ce,[t("div",ue,[t("div",pe,w(s.neighbor?.node_name||s.neighbor?.long_name||s.neighbor?.short_name||"Unknown"),1),t("div",ge," ID: "+w(s.neighbor?.node_num_hex||s.neighbor?.node_num||s.neighbor?.id||"N/A"),1),s.neighbor?.contact_type?(k(),_("div",me,w(s.neighbor.contact_type),1)):P("",!0),s.neighbor?.hw_model?(k(),_("div",he,w(s.neighbor.hw_model),1)):P("",!0)])])]),a[4]||(a[4]=t("div",{class:"bg-accent-red/10 border border-accent-red/30 rounded-lg p-4 mb-6"},[t("div",{class:"flex items-center gap-2 text-accent-red text-sm"},[t("svg",{class:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[t("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 9v2m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"})]),t("span",null,"This action cannot be undone")])],-1)),t("div",{class:"flex gap-3"},[t("button",{onClick:d,class:"flex-1 px-4 py-3 bg-background-mute dark:bg-white/5 hover:bg-stroke-subtle dark:hover:bg-white/10 border border-stroke-subtle dark:border-stroke/20 text-content-primary dark:text-content-primary rounded-lg transition-colors"}," Cancel "),t("button",{onClick:e,class:"flex-1 px-4 py-3 bg-accent-red/20 hover:bg-accent-red/30 border border-accent-red/50 text-accent-red rounded-lg transition-colors font-medium"}," Delete ")])])])):P("",!0)}}),xe={class:"bg-gradient-to-r from-primary/20 to-accent-cyan/20 border-b border-stroke-subtle dark:border-stroke/10 px-6 py-4"},ye={class:"flex items-center justify-between"},ve={class:"flex items-center gap-3"},ke={key:0,class:"text-sm text-content-secondary dark:text-content-muted"},fe={class:"p-6"},we={key:0,class:"text-center py-8"},_e={key:1,class:"text-center py-8"},Ce={class:"text-content-secondary dark:text-content-muted text-sm"},Me={key:2,class:"space-y-4"},$e={class:"bg-background-mute dark:bg-background/50 border border-stroke-subtle dark:border-stroke/10 rounded-[15px] p-4"},Ae={class:"flex items-center justify-between mb-2"},Le={class:"flex items-baseline gap-2"},Te={class:"text-3xl font-bold text-content-primary dark:text-content-primary"},Ee={class:"grid grid-cols-2 gap-3"},Se={class:"bg-background-mute dark:bg-background/50 border border-stroke-subtle dark:border-stroke/10 rounded-[15px] p-4"},Be={class:"flex items-center gap-2 mb-2"},Ne={class:"flex gap-0.5"},Fe={class:"flex items-baseline gap-1"},De={class:"text-xl font-bold text-content-primary dark:text-content-primary"},Pe={class:"bg-background-mute dark:bg-background/50 border border-stroke-subtle dark:border-stroke/10 rounded-[15px] p-4"},ze={class:"flex items-baseline gap-1"},Re={class:"text-xl font-bold text-content-primary dark:text-content-primary"},je={key:0,class:"flex items-start gap-3 bg-amber-500/10 border border-amber-500/30 rounded-[12px] p-3"},Ie={class:"text-xs leading-relaxed"},Ue={class:"font-semibold text-amber-600 dark:text-amber-400 mb-0.5"},Oe={class:"bg-background-mute dark:bg-background/50 border border-stroke-subtle dark:border-stroke/10 rounded-[15px] p-4"},He={class:"relative"},Ve={class:"flex items-center gap-2 overflow-x-auto pb-2"},Ze={key:0,class:"relative flex items-center"},We={key:0,class:"absolute left-1/2 -translate-x-1/2 animate-pulse"},Qe={class:"text-content-muted dark:text-content-muted text-xs mt-2 flex items-center justify-between"},qe={key:0,class:"text-cyan-500 dark:text-primary animate-pulse"},Ke={class:"flex items-center justify-between text-xs text-content-muted dark:text-content-muted pt-2"},Ge=bt({__name:"PingResultModal",props:{show:{type:Boolean},nodeName:{default:null},result:{default:null},error:{default:null},loading:{type:Boolean,default:!1}},emits:["close"],setup($,{emit:r}){const o=$,i=r,e=Yt(),{getSignalQuality:d}=Ut(),h=D(0),s=D(!1),a=q(()=>{const g=e.stats?.config?.radio?.spreading_factor??7,c=e.stats?.config?.radio?.bandwidth??125,T=e.stats?.config?.radio?.coding_rate??5,F=Math.pow(2,g)/c,I=8+4.25*(T-4)+20;return F*I}),f=q(()=>{if(!o.result)return{color:"text-gray-400",label:"Unknown"};const g=o.result.rtt_ms,c=a.value,T=o.result.path.length,I=2*c*T+500*T;return g{if(!o.result)return{bars:0,color:"text-gray-400"};const g=d(o.result.rssi);return{bars:g.bars,color:g.color}}),v=q(()=>{if(!o.result)return 0;if(o.result.path_hash_mode!==void 0)return o.result.path_hash_mode;const g=o.result.path.reduce((c,T)=>{const F=T.replace(/^0x/i,"");return Math.max(c,F.length)},0);return g>4?2:g>2?1:0}),L=q(()=>v.value>0),B=q(()=>({0:"1-byte",1:"2-byte",2:"3-byte"})[v.value]??"1-byte");ht(()=>o.result,g=>{if(g&&!s.value){s.value=!0,h.value=0;const c=g.path.length,F=1500/(c*2);let I=0;const y=c*2-2,p=()=>{I<=y?(h.value=I/y,I++,setTimeout(p,F)):(s.value=!1,h.value=1)};setTimeout(p,100)}},{immediate:!0});const N=q(()=>{if(!o.result||!s.value)return-1;const g=o.result.path.length;if(g<=1)return-1;const c=h.value,T=.5;if(c<=T)return c/T*(g-1);{const F=(c-T)/T;return(g-1)*(1-F)}}),S=()=>{i("close")};return(g,c)=>(k(),Rt(jt,{to:"body"},[it(Ft,{name:"modal"},{default:Dt(()=>[g.show?(k(),_("div",{key:0,class:"fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-[99999] p-4",onClick:Lt(S,["self"])},[t("div",{class:"glass-card backdrop-blur-xl border border-stroke-subtle dark:border-white/20 rounded-[20px] shadow-2xl w-full max-w-md overflow-hidden",onClick:c[0]||(c[0]=Lt(()=>{},["stop"]))},[t("div",xe,[t("div",ye,[t("div",ve,[c[2]||(c[2]=t("div",{class:"p-2 bg-cyan-400/20 dark:bg-primary/20 rounded-lg"},[t("svg",{class:"w-5 h-5 text-cyan-500 dark:text-primary",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[t("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01m-7.08-7.071c3.904-3.905 10.236-3.905 14.141 0M1.394 9.393c5.857-5.857 15.355-5.857 21.213 0"})])],-1)),t("div",null,[c[1]||(c[1]=t("h2",{class:"text-xl font-bold text-content-primary dark:text-content-primary"},"Ping Result",-1)),g.nodeName?(k(),_("p",ke,w(g.nodeName),1)):P("",!0)])]),t("button",{onClick:S,class:"p-2 hover:bg-stroke-subtle dark:hover:bg-white/10 rounded-lg transition-colors text-content-secondary dark:text-content-muted hover:text-content-primary dark:hover:text-content-primary"},c[3]||(c[3]=[t("svg",{class:"w-5 h-5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[t("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M6 18L18 6M6 6l12 12"})],-1)]))])]),t("div",fe,[g.loading?(k(),_("div",we,c[4]||(c[4]=[t("div",{class:"animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto mb-4"},null,-1),t("p",{class:"text-content-secondary dark:text-content-muted"},"Sending ping...",-1),t("p",{class:"text-content-muted dark:text-content-muted text-sm mt-1"},"Waiting for response...",-1)]))):g.error?(k(),_("div",_e,[c[5]||(c[5]=t("div",{class:"p-3 bg-accent-red/10 rounded-full w-16 h-16 mx-auto mb-4 flex items-center justify-center"},[t("svg",{class:"w-8 h-8 text-accent-red",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[t("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-1.964-1.333-2.732 0L3.268 16c-.77 1.333.192 3 1.732 3z"})])],-1)),c[6]||(c[6]=t("h3",{class:"text-accent-red font-semibold mb-2"},"Ping Failed",-1)),t("p",Ce,w(g.error),1)])):g.result?(k(),_("div",Me,[t("div",$e,[t("div",Ae,[c[7]||(c[7]=t("span",{class:"text-content-secondary dark:text-content-muted text-sm"},"Round-Trip Time",-1)),t("span",{class:C(["text-xs font-medium px-2 py-1 rounded-full",f.value.color,"bg-current/10"])},w(f.value.label),3)]),t("div",Le,[t("span",Te,w(g.result.rtt_ms.toFixed(2)),1),c[8]||(c[8]=t("span",{class:"text-content-secondary dark:text-content-muted"},"ms",-1))])]),t("div",Ee,[t("div",Se,[t("div",Be,[c[9]||(c[9]=t("span",{class:"text-content-secondary dark:text-content-muted text-sm"},"RSSI",-1)),t("div",Ne,[(k(),_(ct,null,gt(5,T=>t("div",{key:T,class:C(["w-1 h-3 rounded-sm",T<=b.value.bars?b.value.color:"bg-stroke-subtle dark:bg-stroke/10"])},null,2)),64))])]),t("div",Fe,[t("span",De,w(g.result.rssi),1),c[10]||(c[10]=t("span",{class:"text-content-secondary dark:text-content-muted text-xs"},"dBm",-1))])]),t("div",Pe,[c[12]||(c[12]=t("div",{class:"text-content-secondary dark:text-content-muted text-sm mb-2"},"SNR",-1)),t("div",ze,[t("span",Re,w(g.result.snr_db),1),c[11]||(c[11]=t("span",{class:"text-content-secondary dark:text-content-muted text-xs"},"dB",-1))])])]),L.value?(k(),_("div",je,[c[14]||(c[14]=t("svg",{class:"w-5 h-5 text-amber-500 flex-shrink-0 mt-0.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[t("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-1.964-1.333-2.732 0L3.268 16c-.77 1.333.192 3 1.732 3z"})],-1)),t("div",Ie,[t("p",Ue,w(B.value)+" path hashes active ",1),c[13]||(c[13]=t("p",{class:"text-content-secondary dark:text-content-muted"}," This result uses multi-byte path hashes. The repeater being traced must be running firmware that supports multi-byte path hashes. Repeaters on older firmware will not respond to or correctly route these trace packets. ",-1))])])):P("",!0),t("div",Oe,[c[17]||(c[17]=t("div",{class:"text-content-secondary dark:text-content-muted text-sm mb-3"},"Network Path",-1)),t("div",He,[t("div",Ve,[(k(!0),_(ct,null,gt(g.result.path,(T,F)=>(k(),_("div",{key:F,class:"flex items-center gap-2 flex-shrink-0 relative"},[t("div",{class:C(["bg-cyan-400/20 dark:bg-primary/20 text-cyan-600 dark:text-primary border border-cyan-400/40 dark:border-primary/30 px-3 py-1.5 rounded-lg text-sm font-mono transition-all duration-300",s.value&&Math.floor(N.value)===F?"ring-2 ring-cyan-400/50 dark:ring-primary/50 scale-105":""])},w(T),3),FManage room server identities and messages
No messages yet
Be the first to start the conversation
Manage room server identities and messages
No messages yet
Be the first to start the conversation
Welcome to your pyMC Repeater! Let's get you set up in just a few steps.
You'll configure:
Welcome to your pyMC Repeater! Let's get you set up in just a few steps.
You'll configure:
Packet Rate (RX/TX PER HOUR)
Packet Rate (RX/TX PER HOUR)
{if(!r._listeners)return;let o=r._listeners.length;for(;o-- >0;)r._listeners[o](s);r._listeners=null}),this.promise.then=s=>{let o;const i=new Promise(a=>{r.subscribe(a),o=a}).then(s);return i.cancel=function(){r.unsubscribe(o)},i},t(function(o,i,a){r.reason||(r.reason=new Nn(o,i,a),n(r.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const n=this._listeners.indexOf(t);n!==-1&&this._listeners.splice(n,1)}toAbortSignal(){const t=new AbortController,n=r=>{t.abort(r)};return this.subscribe(n),t.signal.unsubscribe=()=>this.unsubscribe(n),t.signal}static source(){let t;return{token:new hc(function(s){t=s}),cancel:t}}};function e2(e){return function(n){return e.apply(null,n)}}function t2(e){return R.isObject(e)&&e.isAxiosError===!0}const ro={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(ro).forEach(([e,t])=>{ro[t]=e});function mc(e){const t=new pn(e),n=Wl(pn.prototype.request,t);return R.extend(n,pn.prototype,t,{allOwnKeys:!0}),R.extend(n,t,null,{allOwnKeys:!0}),n.create=function(s){return mc(mn(e,s))},n}const $e=mc(yr);$e.Axios=pn;$e.CanceledError=Nn;$e.CancelToken=Q0;$e.isCancel=ac;$e.VERSION=pc;$e.toFormData=fs;$e.AxiosError=ve;$e.Cancel=$e.CanceledError;$e.all=function(t){return Promise.all(t)};$e.spread=e2;$e.isAxiosError=t2;$e.mergeConfig=mn;$e.AxiosHeaders=st;$e.formToJSON=e=>ic(R.isHTMLForm(e)?new FormData(e):e);$e.getAdapter=fc.getAdapter;$e.HttpStatusCode=ro;$e.default=$e;const{Axios:J4,AxiosError:X4,CanceledError:Y4,isCancel:Q4,CancelToken:e6,VERSION:t6,all:n6,Cancel:r6,isAxiosError:s6,spread:o6,toFormData:i6,AxiosHeaders:a6,HttpStatusCode:l6,formToJSON:c6,getAdapter:u6,mergeConfig:d6}=$e,Io="pymc_jwt_token",ua="pymc_client_id";function gc(){let e=localStorage.getItem(ua);return e||(e=`${Date.now()}-${Math.random().toString(36).substring(2,15)}`,localStorage.setItem(ua,e)),e}function Bt(){return localStorage.getItem(Io)}function n2(e){localStorage.setItem(Io,e)}function vn(){localStorage.removeItem(Io)}function vc(){return Bt()!==null}function Do(e){try{const n=e.split(".")[1].replace(/-/g,"+").replace(/_/g,"/"),r=decodeURIComponent(atob(n).split("").map(s=>"%"+("00"+s.charCodeAt(0).toString(16)).slice(-2)).join(""));return JSON.parse(r)}catch{return null}}function yc(){const e=Bt();if(!e)return!0;const t=Do(e);return!t||!t.exp?!0:Date.now()>=t.exp*1e3-3e4}function bc(){const e=Bt();if(!e)return!1;const t=Do(e);if(!t||!t.exp)return!1;const n=t.exp*1e3-Date.now();return n>0&&n<3e5}function r2(){const e=Bt();if(!e)return null;const t=Do(e);return!t||!t.sub?null:t.sub}const s2="modulepreload",o2=function(e){return"/"+e},da={},Ge=function(t,n,r){let s=Promise.resolve();if(n&&n.length>0){let l=function(u){return Promise.all(u.map(c=>Promise.resolve(c).then(f=>({status:"fulfilled",value:f}),f=>({status:"rejected",reason:f}))))};document.getElementsByTagName("link");const i=document.querySelector("meta[property=csp-nonce]"),a=i?.nonce||i?.getAttribute("nonce");s=l(n.map(u=>{if(u=o2(u),u in da)return;da[u]=!0;const c=u.endsWith(".css"),f=c?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${u}"]${f}`))return;const p=document.createElement("link");if(p.rel=c?"stylesheet":s2,c||(p.as="script"),p.crossOrigin="",p.href=u,a&&p.setAttribute("nonce",a),document.head.appendChild(p),c)return new Promise((h,m)=>{p.addEventListener("load",h),p.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${u}`)))})}))}function o(i){const a=new Event("vite:preloadError",{cancelable:!0});if(a.payload=i,window.dispatchEvent(a),!a.defaultPrevented)throw i}return s.then(i=>{for(const a of i||[])a.status==="rejected"&&o(a.reason);return t().catch(o)})},Vt=Sf({history:nf("/"),routes:[{path:"/setup",name:"setup",component:()=>Ge(()=>import("./Setup-Je-FXF2e.js"),__vite__mapDeps([0,1])),meta:{requiresAuth:!1,requiresSetup:!1}},{path:"/login",name:"login",component:()=>Ge(()=>import("./Login-C7fQOt3C.js"),__vite__mapDeps([2,3])),meta:{requiresAuth:!1}},{path:"/",name:"dashboard",component:()=>Ge(()=>import("./Dashboard-CideT_dR.js"),__vite__mapDeps([4,5,6,7,8])),meta:{requiresAuth:!0}},{path:"/neighbors",name:"neighbors",component:()=>Ge(()=>import("./Neighbors-gx2VL33X.js"),__vite__mapDeps([9,6,10,11,7,12,13])),meta:{requiresAuth:!0}},{path:"/statistics",name:"statistics",component:()=>Ge(()=>import("./Statistics-CF2_n4mI.js"),__vite__mapDeps([14,15,5,16,7,17,11,18])),meta:{requiresAuth:!0}},{path:"/system-stats",name:"system-stats",component:()=>Ge(()=>import("./SystemStats-B8lsqaxi.js"),__vite__mapDeps([19,15,5,16,20])),meta:{requiresAuth:!0}},{path:"/configuration",name:"configuration",component:()=>Ge(()=>import("./Configuration-Ep01Mou3.js"),__vite__mapDeps([21,22,7,23,13])),meta:{requiresAuth:!0}},{path:"/cad-calibration",name:"cad-calibration",component:()=>Ge(()=>import("./CADCalibration-DKpo6zSS.js"),__vite__mapDeps([24,17,11,25])),meta:{requiresAuth:!0}},{path:"/sessions",name:"sessions",component:()=>Ge(()=>import("./Sessions-CVA-ZDdW.js"),[]),meta:{requiresAuth:!0}},{path:"/room-servers",name:"room-servers",component:()=>Ge(()=>import("./RoomServers-CPjLjzvi.js"),__vite__mapDeps([26,7,22,27])),meta:{requiresAuth:!0}},{path:"/companions",name:"companions",component:()=>Ge(()=>import("./Companions-CAMDNPUU.js"),__vite__mapDeps([28,22,27])),meta:{requiresAuth:!0}},{path:"/logs",name:"logs",component:()=>Ge(()=>import("./Logs-trTUZeB2.js"),[]),meta:{requiresAuth:!0}},{path:"/terminal",name:"terminal",component:()=>Ge(()=>import("./Terminal-B4S3bEvn.js"),__vite__mapDeps([29,30])),meta:{requiresAuth:!0}},{path:"/help",name:"help",component:()=>Ge(()=>import("./Help-QuV8zE-L.js"),[]),meta:{requiresAuth:!0}}]});async function fa(){try{const e=await fetch("/api/needs_setup",{headers:{Accept:"application/json"}});if(!e.ok)return console.error("Setup check failed:",e.status),!1;const t=await e.json();return console.log("Setup status check:",t),t.needs_setup===!0}catch(e){return console.error("Error checking setup status:",e),!1}}Vt.beforeEach(async(e,t,n)=>{const r=e.meta.requiresAuth!==!1,s=vc();if(e.path!=="/setup"&&await fa()){n("/setup");return}if(e.path==="/setup"&&!await fa()){n("/login");return}r&&!s?n("/login"):e.path==="/login"&&s?n("/"):n()});const i2="/api",Gr="";let $s=!1,jn=null;async function xc(){return $s&&jn||($s=!0,jn=(async()=>{try{const e=Bt();if(!e)throw new Error("No token to refresh");const t=gc(),n=await $e.post(`${Gr}/auth/refresh`,{client_id:t},{headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}});if(n.data.success&&n.data.token){const r=n.data.token;return n2(r),console.log("Token refreshed successfully"),r}else throw new Error("Token refresh failed")}catch(e){throw console.error("Token refresh error:",e),vn(),Vt.push("/login"),e}finally{$s=!1,jn=null}})()),jn}const ln=$e.create({baseURL:i2,timeout:5e3,headers:{"Content-Type":"application/json"}}),wc=$e.create({baseURL:Gr,timeout:5e3,headers:{"Content-Type":"application/json"}});wc.interceptors.request.use(async e=>{if(e.url?.includes("/auth/login")||e.url?.includes("/auth/refresh"))return e;const t=Bt();if(t){if(bc())try{const n=await xc();return e.headers.Authorization=`Bearer ${n}`,e}catch(n){return Promise.reject(n)}if(yc())return vn(),Vt.push("/login"),Promise.reject(new Error("Token expired"));e.headers.Authorization=`Bearer ${t}`}return e},e=>(console.error("Auth API Request Error:",e),Promise.reject(e)));wc.interceptors.response.use(e=>e,e=>(e.response?.status===401&&(vn(),Vt.currentRoute.value.path!=="/login"&&Vt.push("/login")),console.error("Auth API Response Error:",e.response?.data||e.message),Promise.reject(e)));ln.interceptors.request.use(async e=>{if(e.url?.includes("/auth/login"))return e;const t=Bt();if(t){if(bc())try{const n=await xc();return e.headers.Authorization=`Bearer ${n}`,e}catch(n){return Promise.reject(n)}if(yc())return vn(),Vt.push("/login"),Promise.reject(new Error("Token expired"));e.headers.Authorization=`Bearer ${t}`}return e},e=>(console.error("API Request Error:",e),Promise.reject(e)));ln.interceptors.response.use(e=>e,e=>(e.response?.status===401&&(vn(),Vt.currentRoute.value.path!=="/login"&&Vt.push("/login")),console.error("API Response Error:",e.response?.data||e.message),Promise.reject(e)));class Te{static async get(t,n){try{return(await ln.get(t,{params:n})).data}catch(r){throw this.handleError(r)}}static async post(t,n,r){try{return(await ln.post(t,n,r)).data}catch(s){throw this.handleError(s)}}static async put(t,n,r){try{return(await ln.put(t,n,r)).data}catch(s){throw this.handleError(s)}}static async delete(t,n){try{return(await ln.delete(t,n)).data}catch(r){throw this.handleError(r)}}static async getTransportKeys(){return this.get("transport_keys")}static async sendAdvert(){return this.post("send_advert",{},{headers:{"Content-Type":"application/json"}})}static async createTransportKey(t,n,r,s,o){const i={name:t,flood_policy:n,parent_id:s,last_used:o};return r!==void 0&&(i.transport_key=r),this.post("transport_keys",i)}static async getTransportKey(t){return this.get(`transport_key/${t}`)}static async updateTransportKey(t,n,r,s,o,i){return this.put(`transport_key/${t}`,{name:n,flood_policy:r,transport_key:s,parent_id:o,last_used:i})}static async deleteTransportKey(t){return this.delete(`transport_key/${t}`)}static async updateGlobalFloodPolicy(t){return this.post("global_flood_policy",{global_flood_allow:t})}static async getLogs(){try{return(await ln.get("logs")).data}catch(t){throw this.handleError(t)}}static async deleteAdvert(t){return this.delete(`advert/${t}`)}static async pingNeighbor(t,n=10){return this.post("ping_neighbor",{target_id:t,timeout:n})}static async getIdentities(){return this.get("identities")}static async getIdentity(t){return this.get("identity",{name:t})}static async createIdentity(t){return this.post("create_identity",t)}static async updateIdentity(t){return this.put("update_identity",t)}static async deleteIdentity(t,n="room_server"){const r=new URLSearchParams({name:t});return n==="companion"&&r.set("type","companion"),this.delete(`delete_identity?${r.toString()}`)}static async sendRoomServerAdvert(t){return this.post("send_room_server_advert",{name:t})}static async importRepeaterContacts(t){return this.post("companion/import_repeater_contacts",t)}static async getACLInfo(){return this.get("acl_info")}static async getACLClients(t){return this.get("acl_clients",t)}static async removeACLClient(t){return this.post("acl_remove_client",t)}static async getACLStats(){return this.get("acl_stats")}static async getRoomMessages(t){return this.get("room_messages",t)}static async postRoomMessage(t){return this.post("room_post_message",t)}static async deleteRoomMessage(t){return this.delete(`room_message?room_name=${encodeURIComponent(t.room_name)}&message_id=${t.message_id}`)}static async clearRoomMessages(t){return this.delete(`room_messages?room_name=${encodeURIComponent(t)}`)}static async getRoomStats(t){return this.get("room_stats",t?{room_name:t}:void 0)}static async getRoomClients(t){return this.get("room_clients",{room_name:t})}static async exportConfig(t=!1){const n=t?"config_export?include_secrets=true":"config_export";return this.get(n)}static async importConfig(t){return this.post("config_import",{config:t})}static async exportIdentityKey(){return this.get("identity_export")}static async generateVanityKey(t,n=!1){return this.post("generate_vanity_key",{prefix:t,apply:n})}static async getDbStats(){return this.get("db_stats")}static async purgeTable(t){return this.post("db_purge",{tables:t})}static async vacuumDb(){return this.post("db_vacuum",{})}static handleError(t){if($e.isAxiosError(t)){if(t.response){const n=t.response.data?.error||t.response.data?.message||`HTTP ${t.response.status}`;return new Error(n)}else if(t.request)return new Error("Network error - no response received")}return new Error(t instanceof Error?t.message:"Unknown error occurred")}}const br=Ro("system",()=>{const e=B(null),t=B(!1),n=B(null),r=B(null),s=B("forward"),o=B(!0),i=B(0),a=B(10),l=B(!1),u=ie(()=>e.value?.config?.node_name??"Unknown"),c=ie(()=>{const N=e.value?.public_key;return!N||N==="Unknown"?"Unknown":N.length>=16?`${N.slice(0,8)} ... ${N.slice(-8)}`:`${N}`}),f=ie(()=>e.value!==null),p=ie(()=>e.value?.version??"Unknown"),h=ie(()=>e.value?.core_version??"Unknown"),m=ie(()=>e.value?.noise_floor_dbm??null),y=ie(()=>a.value>0?Math.min(i.value/a.value*100,100):0),b=ie(()=>s.value==="no_tx"?{text:"No TX",title:"No repeat, no local TX; adverts skipped"}:s.value==="monitor"?{text:"Monitor Mode",title:"Monitoring only - not forwarding packets"}:o.value?{text:"Active",title:"Forwarding with duty cycle enforcement"}:{text:"No Limits",title:"Forwarding without duty cycle enforcement"}),T=ie(()=>({mode:s.value})),O=ie(()=>o.value?{active:!0,warning:!1}:{active:!1,warning:!0}),M=N=>{l.value=N};async function $(){try{t.value=!0,n.value=null;const N=await Te.get("/stats");if(N.success&&N.data)return e.value=N.data,r.value=new Date,U(N.data),N.data;if(N&&"version"in N){const J=N;return e.value=J,r.value=new Date,U(J),J}else throw new Error(N.error||"Failed to fetch stats")}catch(N){throw n.value=N instanceof Error?N.message:"Unknown error occurred",console.error("Error fetching stats:",N),N}finally{t.value=!1}}function U(N){if(N.config){const he=N.config.repeater?.mode;he==="forward"||he==="monitor"||he==="no_tx"?s.value=he:he!==void 0&&(s.value="forward");const ce=N.config.duty_cycle;if(ce){o.value=ce.enforcement_enabled!==!1;const se=ce.max_airtime_percent;typeof se=="number"?a.value=se:se&&typeof se=="object"&&"parsedValue"in se&&(a.value=se.parsedValue||10)}}const J=N.utilization_percent;typeof J=="number"?i.value=J:J&&typeof J=="object"&&"parsedValue"in J&&(i.value=J.parsedValue||0)}async function ee(N){try{const J=await Te.post("/set_mode",{mode:N});if(J.success)return s.value=N,!0;throw new Error(J.error||"Failed to set mode")}catch(J){throw n.value=J instanceof Error?J.message:"Unknown error occurred",console.error("Error setting mode:",J),J}}async function G(N){try{const J=await Te.post("/set_duty_cycle",{enabled:N});if(J.success)return o.value=N,!0;throw new Error(J.error||"Failed to set duty cycle")}catch(J){throw n.value=J instanceof Error?J.message:"Unknown error occurred",console.error("Error setting duty cycle:",J),J}}async function Y(){try{const N=await Te.post("/send_advert",{},{timeout:1e4});if(N.success)return console.log("Advertisement sent successfully:",N.data),!0;throw new Error(N.error||"Failed to send advert")}catch(N){throw n.value=N instanceof Error?N.message:"Unknown error occurred",console.error("Error sending advert:",N),N}}async function L(){return await G(!o.value)}function Q(N){e.value?(N.uptime_seconds!==void 0&&(e.value.uptime_seconds=N.uptime_seconds),N.noise_floor_dbm!==void 0&&(e.value.noise_floor_dbm=N.noise_floor_dbm)):e.value=N,r.value=new Date,U(N)}async function ae(N=5e3,J=!1){J||await $();let he=null;return J||(he=setInterval(async()=>{try{await $()}catch(ce){console.error("Auto-refresh error:",ce)}},N)),()=>{he&&clearInterval(he)}}function W(){e.value=null,n.value=null,r.value=null,t.value=!1,s.value="forward",o.value=!0,i.value=0,a.value=10}return{stats:e,isLoading:t,error:n,lastUpdated:r,currentMode:s,dutyCycleEnabled:o,dutyCycleUtilization:i,dutyCycleMax:a,cadCalibrationRunning:l,nodeName:u,pubKey:c,hasStats:f,version:p,coreVersion:h,noiseFloorDbm:m,dutyCyclePercentage:y,statusBadge:b,modeButtonState:T,dutyCycleButtonState:O,fetchStats:$,setMode:ee,setDutyCycle:G,sendAdvert:Y,toggleDutyCycle:L,startAutoRefresh:ae,updateRealtimeStats:Q,reset:W,setCadCalibrationRunning:M}}),Cc=Ro("packets",()=>{const e=B(null),t=B(null),n=B([]),r=B([]),s=B(null),o=B(!1),i=B(null),a=B(null),l=B([]),u=B([]),c=B(null),f=B(0),p=B([]),h=B({rx:0,tx:0,drop:0}),m=B({rx:0,tx:0,drop:0}),y=ie(()=>e.value!==null),b=ie(()=>t.value!==null),T=ie(()=>n.value.length>0),O=ie(()=>r.value.length>0),M=ie(()=>s.value?.avg_noise_floor??0),$=ie(()=>e.value?.total_packets??0),U=ie(()=>e.value?.avg_rssi??0),ee=ie(()=>e.value?.avg_snr??0),G=ie(()=>t.value?.uptime_seconds??0),Y=ie(()=>{if(!e.value?.packet_types)return[];const A=e.value.packet_types,C=A.reduce((Z,xe)=>Z+xe.count,0);return A.map(Z=>({type:Z.type.toString(),count:Z.count,percentage:C>0?Z.count/C*100:0}))}),L=ie(()=>{const A={};return n.value.forEach(C=>{A[C.type]||(A[C.type]=[]),A[C.type].push(C)}),A});async function Q(){try{const A=await Te.get("/stats");if(A.success&&A.data){t.value=A.data;const C=new Date;return u.value.push({timestamp:C,stats:A.data}),u.value.length>50&&(u.value=u.value.slice(-50)),A.data}else if(A&&"version"in A){const C=A;t.value=C;const Z=new Date;return u.value.push({timestamp:Z,stats:C}),u.value.length>50&&(u.value=u.value.slice(-50)),C}else throw new Error(A.error||"Failed to fetch system stats")}catch(A){throw i.value=A instanceof Error?A.message:"Unknown error occurred",console.error("Error fetching system stats:",A),A}}async function ae(A={hours:24}){try{const C=await Te.get("/noise_floor_history",A);if(C.success&&C.data&&C.data.history)return r.value=C.data.history,a.value=new Date,C.data.history;throw new Error(C.error||"Failed to fetch noise floor history")}catch(C){throw i.value=C instanceof Error?C.message:"Unknown error occurred",console.error("Error fetching noise floor history:",C),C}}async function W(A={hours:24}){try{const C=await Te.get("/noise_floor_stats",A);if(C.success&&C.data&&C.data.stats)return s.value=C.data.stats,a.value=new Date,C.data.stats;throw new Error(C.error||"Failed to fetch noise floor stats")}catch(C){throw i.value=C instanceof Error?C.message:"Unknown error occurred",console.error("Error fetching noise floor stats:",C),C}}const N=ie(()=>!r.value||!Array.isArray(r.value)?[]:r.value.slice(-50).map(A=>A.noise_floor_dbm));async function J(A={hours:24}){try{o.value=!0,i.value=null;const C=await Te.get("/packet_stats",A);if(C.success&&C.data){e.value=C.data;const Z=new Date;l.value.push({timestamp:Z,stats:C.data}),l.value.length>50&&(l.value=l.value.slice(-50)),a.value=Z}else throw new Error(C.error||"Failed to fetch packet stats")}catch(C){i.value=C instanceof Error?C.message:"Unknown error occurred",console.error("Error fetching packet stats:",C)}finally{o.value=!1}}async function he(A={limit:100}){try{o.value=!0,i.value=null;const C=await Te.get("/recent_packets",A);if(C.success&&C.data)n.value=C.data,a.value=new Date;else throw new Error(C.error||"Failed to fetch recent packets")}catch(C){i.value=C instanceof Error?C.message:"Unknown error occurred",console.error("Error fetching recent packets:",C)}finally{o.value=!1}}async function ce(A){try{o.value=!0,i.value=null;const C=await Te.get("/filtered_packets",A);if(C.success&&C.data)return n.value=C.data,a.value=new Date,C.data;throw new Error(C.error||"Failed to fetch filtered packets")}catch(C){throw i.value=C instanceof Error?C.message:"Unknown error occurred",console.error("Error fetching filtered packets:",C),C}finally{o.value=!1}}async function se(A){try{o.value=!0,i.value=null;const C=await Te.get("/packet_by_hash",{packet_hash:A});if(C.success&&C.data)return C.data;throw new Error(C.error||"Packet not found")}catch(C){throw i.value=C instanceof Error?C.message:"Unknown error occurred",console.error("Error fetching packet by hash:",C),C}finally{o.value=!1}}const re=ie(()=>{if(!c.value?.series)return{totalPackets:[],transmittedPackets:[],droppedPackets:[],crcErrors:p.value.map(v=>v.count),currentRates:h.value};const A=c.value.series.find(v=>v.type==="rx_count"),C=c.value.series.find(v=>v.type==="tx_count"),Z=A?.data||[],xe=C?.data||[],g=Z.map((v,w)=>{const P=xe[w];return P?Math.max(0,v[1]-P[1]):v[1]});return{totalPackets:Z.map(v=>v[1]),transmittedPackets:xe.map(v=>v[1]),droppedPackets:g,crcErrors:p.value.map(v=>v.count),currentRates:h.value}}),be=ie(()=>{const A=l.value,C=u.value;return{totalPackets:A.map(Z=>Z.stats.total_packets),transmittedPackets:A.map(Z=>Z.stats.transmitted_packets),droppedPackets:A.map(Z=>Z.stats.dropped_packets),avgRssi:A.map(Z=>Z.stats.avg_rssi),uptimeHours:C.map(Z=>Math.floor((Z.stats.uptime_seconds||0)/3600))}});async function pe(A=3e4){await Promise.all([Q(),J(),he(),ae({hours:1}),W({hours:1})]);const C=setInterval(async()=>{try{await Promise.all([Q(),J(),he(),ae({hours:1}),W({hours:1})])}catch(Z){console.error("Auto-refresh error:",Z)}},A);return()=>clearInterval(C)}async function j(A=24){try{const[C,Z]=await Promise.all([Te.get("/crc_error_count",{hours:A}),Te.get("/crc_error_history",{hours:A})]);C?.success&&C.data&&(f.value=C.data.crc_error_count??0),Z?.success&&Z.data&&(p.value=Z.data.history??[])}catch(C){console.error("Failed to fetch CRC error data:",C)}}async function D(){try{const[A]=await Promise.all([Te.get("/metrics_graph_data",{hours:24,resolution:"average",metrics:"rx_count,tx_count"}),j(24)]);A?.success&&A.data&&(c.value=A.data)}catch(A){console.error("Failed to fetch sparkline data:",A)}}async function S(){await D()}function x(){D()}function q(){e.value=null,t.value=null,n.value=[],r.value=[],s.value=null,l.value=[],u.value=[],c.value=null,f.value=0,p.value=[],h.value={rx:0,tx:0,drop:0},m.value={rx:0,tx:0,drop:0},i.value=null,a.value=null,o.value=!1}function H(A){n.value.unshift(A),n.value.length>1e3&&(n.value=n.value.slice(0,1e3))}function k(A){if(A.packet_stats){e.value=A.packet_stats;const C=new Date;l.value.push({timestamp:C,stats:A.packet_stats}),l.value.length>50&&(l.value=l.value.slice(-50))}if(A.system_stats){t.value=A.system_stats;const C=new Date;u.value.push({timestamp:C,stats:A.system_stats}),u.value.length>50&&(u.value=u.value.slice(-50))}a.value=new Date}return{packetStats:e,systemStats:t,recentPackets:n,noiseFloorHistory:r,noiseFloorStats:s,packetStatsHistory:l,systemStatsHistory:u,isLoading:o,error:i,lastUpdated:a,hasPacketStats:y,hasSystemStats:b,hasRecentPackets:T,hasNoiseFloorData:O,currentNoiseFloor:M,totalPackets:$,averageRSSI:U,averageSNR:ee,uptime:G,packetTypeBreakdown:Y,recentPacketsByType:L,sparklineData:re,legacySparklineData:be,noiseFloorSparklineData:N,crcErrorCount:f,interpolatedRates:h,fetchSystemStats:Q,fetchPacketStats:J,fetchCrcErrors:j,fetchRecentPackets:he,fetchFilteredPackets:ce,getPacketByHash:se,fetchNoiseFloorHistory:ae,fetchNoiseFloorStats:W,startAutoRefresh:pe,initializeSparklineHistory:S,interpolateRates:x,reset:q,addRealtimePacket:H,updateRealtimeStats:k}}),_c=Ro("websocket",()=>{const e=B(null),t=B(!1),n=B(0),r=B(null),s=B(Date.now()),o=Cc(),i=br();function a(){if(e.value){if(e.value.readyState===WebSocket.OPEN){console.log("[WebSocket] Already connected, skipping connect()");return}else if(e.value.readyState===WebSocket.CONNECTING){console.log("[WebSocket] Already connecting, skipping connect()");return}}let u;const c=Bt(),f=gc(),p=new URLSearchParams;c&&p.set("token",c),f&&p.set("client_id",f);{const h=window.location.protocol==="https:"?"wss:":"ws:",m=Gr?.trim()?new URL(Gr).host:window.location.host;u=`${h}//${m}/ws/packets?${p.toString()}`}console.log("[WebSocket] Creating new connection..."),e.value=new WebSocket(u),e.value.onopen=()=>{console.log("[WebSocket] Connected"),t.value=!0,n.value=0,s.value=Date.now(),r.value&&clearInterval(r.value),r.value=window.setInterval(()=>{e.value?.readyState===WebSocket.OPEN&&(e.value.send(JSON.stringify({type:"ping"})),Date.now()-s.value>6e4&&(console.warn("[WebSocket] No pong received, reconnecting..."),l(),a()))},3e4)},e.value.onmessage=h=>{try{const m=JSON.parse(h.data);m.type==="packet"?o.addRealtimePacket(m.data):m.type==="stats"?(m.data?.packet_stats&&o.updateRealtimeStats({packet_stats:m.data.packet_stats}),m.data?.system_stats&&i.updateRealtimeStats(m.data.system_stats)):m.type==="packet_stats"?o.updateRealtimeStats(m.data):m.type==="system_stats"?i.updateRealtimeStats(m.data):(m.type==="pong"||m.type==="ping")&&(s.value=Date.now(),m.type==="ping"&&e.value?.readyState===WebSocket.OPEN&&e.value.send(JSON.stringify({type:"pong"})))}catch(m){console.error("[WebSocket] Parse error:",m)}},e.value.onerror=()=>{if(console.log("[WebSocket] Error"),t.value=!1,e.value=null,r.value&&(clearInterval(r.value),r.value=null),n.value<5){const h=Math.min(1e3*Math.pow(2,Math.min(n.value,5)),3e4);console.log(`[WebSocket] Reconnecting in ${h}ms (attempt ${n.value+1})`),n.value++,setTimeout(a,h)}else console.error("[WebSocket] Max reconnection attempts reached - stopping")},e.value.onclose=()=>{console.log("[WebSocket] Disconnected"),t.value=!1,e.value=null,r.value&&(clearInterval(r.value),r.value=null),n.value<5?(n.value=0,setTimeout(a,3e3)):console.log("[WebSocket] Not reconnecting - max attempts reached")}}function l(){console.log("[WebSocket] Disconnecting..."),r.value&&(clearInterval(r.value),r.value=null),e.value&&(e.value.onclose=null,e.value.onerror=null,e.value.close(),e.value=null),t.value=!1,n.value=0}return{isConnected:t,connect:a,disconnect:l}}),Qe=(e,t)=>{const n=e.__vccOpts||e;for(const[r,s]of t)n[r]=s;return n},a2={},l2={width:"23",height:"25",viewBox:"0 0 23 25",fill:"none",xmlns:"http://www.w3.org/2000/svg"};function c2(e,t){return _(),E("svg",l2,t[0]||(t[0]=[d("path",{d:"M2.84279 2.25795C2.90709 1.12053 3.17879 0.625914 3.95795 0.228723C4.79631 -0.198778 6.11858 0.000168182 7.67449 0.788054C8.34465 1.12757 8.41289 1.13448 9.58736 0.983905C11.1485 0.783681 13.1582 0.784388 14.5991 0.985738C15.6887 1.13801 15.7603 1.1304 16.4321 0.790174C18.6406 -0.328212 20.3842 -0.255036 21.0156 0.982491C21.3308 1.6002 21.3893 3.20304 21.1449 4.52503C21.0094 5.25793 21.0238 5.34943 21.3502 5.83037C23.6466 9.21443 21.9919 14.6998 18.0569 16.7469C17.7558 16.9036 17.502 17.0005 17.2952 17.0795C16.6602 17.3219 16.4674 17.3956 16.7008 18.5117C16.8132 19.0486 16.9486 20.3833 17.0018 21.478C17.098 23.4567 17.0966 23.4705 16.7495 23.8742C16.2772 24.4233 15.5963 24.4326 15.135 23.8962C14.8341 23.5464 14.8047 23.3812 14.8047 22.0315C14.8047 20.037 14.5861 18.7113 14.0695 17.5753C13.4553 16.2235 13.9106 15.7194 15.3154 15.4173C17.268 14.9973 18.793 13.7923 19.643 11.9978C20.4511 10.2921 20.5729 7.93485 19.1119 6.50124C18.6964 6.00746 18.6674 5.56022 18.9641 4.21159C19.075 3.70754 19.168 3.05725 19.1707 2.76637C19.1749 2.30701 19.1331 2.23764 18.8509 2.23764C18.6724 2.23764 17.9902 2.49736 17.3352 2.81474L16.2897 3.32145C16.1947 3.36751 16.0883 3.38522 15.9834 3.37318C13.3251 3.06805 10.7991 3.06334 8.12774 3.37438C8.02244 3.38663 7.91563 3.36892 7.82025 3.32263L6.77535 2.81559C6.12027 2.49764 5.43813 2.23764 5.25963 2.23764C4.84693 2.23764 4.84072 2.54233 5.2169 4.35258C5.44669 5.45816 5.60133 5.70451 4.93703 6.58851C3.94131 7.91359 3.69258 9.55902 4.22654 11.2878C4.89952 13.4664 6.54749 14.9382 8.86436 15.4292C10.261 15.7253 10.6261 16.1115 10.0928 17.713C9.67293 18.9734 9.40748 19.2982 8.79738 19.2982C7.97649 19.2982 7.46228 18.5871 7.74527 17.843C7.86991 17.5151 7.83283 17.4801 7.06383 17.1996C4.71637 16.3437 2.9209 14.4254 2.10002 11.8959C1.46553 9.94098 1.74471 7.39642 2.76257 5.85843C3.10914 5.33477 3.1145 5.29036 2.95277 4.28787C2.86126 3.72037 2.81177 2.80699 2.84279 2.25795Z",fill:"currentColor"},null,-1),d("path",{d:"M2.02306 16.5589C1.68479 16.0516 0.999227 15.9144 0.491814 16.2527C-0.0155884 16.591 -0.152708 17.2765 0.185564 17.7839C0.435301 18.1586 0.734065 18.4663 0.987777 18.72C1.03455 18.7668 1.08 18.8119 1.12438 18.856C1.3369 19.0671 1.52455 19.2535 1.71302 19.4748C2.12986 19.964 2.54572 20.623 2.78206 21.8047C2.88733 22.3311 3.26569 22.6147 3.47533 22.7386C3.70269 22.8728 3.9511 22.952 4.15552 23.0036C4.57369 23.109 5.08133 23.1638 5.56309 23.1957C6.09196 23.2308 6.665 23.2422 7.17743 23.2453C7.1778 23.8547 7.67202 24.3487 8.28162 24.3487C8.89146 24.3487 9.38582 23.8543 9.38582 23.2445V22.1403C9.38582 21.5305 8.89146 21.0361 8.28162 21.0361C8.17753 21.0361 8.06491 21.0364 7.94562 21.0369C7.29761 21.0389 6.45295 21.0414 5.70905 20.9922C5.35033 20.9684 5.05544 20.9347 4.8392 20.8936C4.50619 19.5863 3.96821 18.7165 3.39415 18.0426C3.14038 17.7448 2.87761 17.4842 2.66387 17.2722C2.62385 17.2326 2.58556 17.1946 2.54935 17.1584C2.30273 16.9118 2.1414 16.7365 2.02306 16.5589Z",fill:"currentColor"},null,-1)]))}const u2=Qe(a2,[["render",c2]]),d2={},f2={width:"17",height:"24",viewBox:"0 0 17 24",fill:"none",xmlns:"http://www.w3.org/2000/svg"};function p2(e,t){return _(),E("svg",f2,t[0]||(t[0]=[At('
In Progress
setTimeout(H,2e3));try{const H=await Te.get("/update/status");if(!H?.success)continue;ee.value="verifying",await new Promise(A=>setTimeout(A,1200));const k=H.current_version??"";U.value=k,s.value=k||s.value,r("version-updated",{currentVersion:s.value,latestVersion:o.value,hasUpdate:!!H.has_update}),k&&D&&k===D?(b.value="verified",i.value=!1,ee.value=null,r("installed")):(b.value="verify-failed",ee.value=null);return}catch{}}b.value="verify-failed",ee.value=null,T.value="Service did not respond after restart — check logs"}nt(()=>n.show,D=>{D?(b.value="idle",T.value=null,O.value=[],$.value=!1,U.value=null,ee.value=null,Y.value=!1,L&&(clearTimeout(L),L=null),u.value="",c.value="",s.value=n.currentVersion,o.value=n.latestVersion,i.value=n.hasUpdate,ce(),he()):J()}),Pn(()=>{J(),L&&(clearTimeout(L),L=null)});function pe(D){D.target===D.currentTarget&&b.value!=="installing"&&b.value!=="restarting"&&r("close")}function j(){window.location.reload()}return(D,S)=>(_(),Ye(bo,{to:"body"},[n.show?(_(),E("div",{key:0,class:"fixed inset-0 bg-black/50 backdrop-blur-sm z-[99999] flex items-center justify-center p-4",onClick:pe},[d("div",{class:"bg-white dark:bg-surface-elevated rounded-[20px] w-full max-w-lg border border-stroke-subtle dark:border-white/10 shadow-2xl flex flex-col max-h-[90vh]",onClick:S[5]||(S[5]=Qn(()=>{},["stop"]))},[d("div",Ch,[S[7]||(S[7]=d("div",{class:"flex items-center gap-3"},[d("div",{class:"w-10 h-10 rounded-xl bg-primary/10 flex items-center justify-center"},[d("svg",{class:"w-5 h-5 text-primary",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"})])]),d("div",null,[d("h3",{class:"text-lg font-semibold text-content-primary dark:text-content-primary"},"OTA Update"),d("p",{class:"text-xs text-content-muted dark:text-content-muted"},"Update over the air from GitHub")])],-1)),b.value!=="installing"&&b.value!=="restarting"?(_(),E("button",{key:0,onClick:S[0]||(S[0]=x=>r("close")),class:"text-content-secondary hover:text-content-primary transition-colors"},S[6]||(S[6]=[d("svg",{class:"w-6 h-6",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M6 18L18 6M6 6l12 12"})],-1)]))):oe("",!0)]),d("div",_h,[d("div",kh,[d("div",Sh,[S[8]||(S[8]=d("p",{class:"text-xs text-content-muted mb-1"},"Installed",-1)),d("p",Eh,F(s.value||"—"),1)]),d("div",{class:fe(["bg-background-mute dark:bg-background-mute rounded-xl p-3 border border-stroke-subtle dark:border-stroke/10",i.value?"border-l-2 border-l-accent-red":"border-l-2 border-l-accent-green"])},[S[10]||(S[10]=d("p",{class:"text-xs text-content-muted mb-1"},"On GitHub",-1)),p.value?(_(),E("div",Rh,S[9]||(S[9]=[d("span",{class:"w-3 h-3 border-2 border-primary border-t-transparent rounded-full animate-spin inline-block"},null,-1),d("span",{class:"text-xs text-content-muted"},"Checking…",-1)]))):(_(),E("p",{key:1,class:fe(["text-sm font-mono font-medium",i.value?"text-accent-red":"text-accent-green"])},F(o.value||"—"),3))],2)]),n.rateLimitUntil?(_(),E("div",Ah,[S[14]||(S[14]=d("svg",{class:"w-4 h-4 shrink-0 mt-0.5 text-amber-600 dark:text-amber-400",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"})],-1)),d("div",Th,[S[13]||(S[13]=d("p",{class:"font-semibold mb-0.5"},"GitHub API rate limit reached",-1)),d("p",null,[S[11]||(S[11]=we("Version checks are paused until ",-1)),d("span",Mh,F(new Date(n.rateLimitUntil).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})),1),S[12]||(S[12]=we(". This is a GitHub limit, not a software issue. You can still install or switch channels manually.",-1))])])])):oe("",!0),!i.value&&s.value&&!p.value?(_(),E("div",Oh,S[15]||(S[15]=[d("svg",{class:"w-4 h-4 shrink-0",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M5 13l4 4L19 7"})],-1),we(" You are up to date. Use ",-1),d("em",{class:"mx-1"},"Force Reinstall",-1),we(" to reinstall anyway. ",-1)]))):oe("",!0),h.value.length>0||m.value?(_(),E("div",Lh,[d("button",{onClick:S[1]||(S[1]=x=>y.value=!y.value),class:"flex items-center justify-between w-full text-xs font-medium text-content-secondary dark:text-content-secondary uppercase tracking-wide py-1 hover:text-content-primary transition-colors"},[S[17]||(S[17]=d("span",null,"What's New",-1)),d("span",Ph,[m.value?(_(),E("span",$h)):(_(),E("span",Nh,F(h.value.length)+" commit"+F(h.value.length!==1?"s":""),1)),(_(),E("svg",{class:fe(["w-3.5 h-3.5 text-content-muted transition-transform",y.value?"rotate-180":""]),viewBox:"0 0 20 20",fill:"currentColor"},S[16]||(S[16]=[d("path",{"fill-rule":"evenodd",d:"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z","clip-rule":"evenodd"},null,-1)]),2))])]),y.value?(_(),E("div",Ih,[d("div",Dh,[(_(!0),E(Re,null,He(h.value,x=>(_(),E("a",{key:x.sha,href:x.url,target:"_blank",class:"flex gap-3 px-3 py-2.5 hover:bg-background-soft dark:hover:bg-surface/50 transition-colors group"},[d("span",Fh,F(x.short_sha),1),d("div",Bh,[d("p",Hh,F(x.title),1),d("p",jh,F(x.author)+" · "+F(x.date?new Date(x.date).toLocaleDateString():""),1)]),S[18]||(S[18]=d("svg",{class:"w-3 h-3 text-content-muted shrink-0 mt-1 opacity-0 group-hover:opacity-100 transition-opacity",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"})],-1))],8,Vh))),128))])])):oe("",!0)])):oe("",!0),d("div",Uh,[S[19]||(S[19]=d("label",{class:"text-xs font-medium text-content-secondary dark:text-content-secondary uppercase tracking-wide"}," Release Channel ",-1)),d("div",qh,[Au(d("select",{"onUpdate:modelValue":S[2]||(S[2]=x=>l.value=x),disabled:f.value||b.value==="installing"||p.value,class:"flex-1 bg-background-mute dark:bg-surface border border-stroke-subtle dark:border-stroke/20 rounded-xl px-3 py-2 text-sm text-content-primary dark:text-content-primary disabled:opacity-50 focus:outline-none focus:ring-1 focus:ring-primary"},[(_(!0),E(Re,null,He(a.value,x=>(_(),E("option",{key:x,value:x},F(x),9,Wh))),128))],8,Kh),[[sd,l.value]]),d("button",{onClick:se,disabled:f.value||b.value==="installing"||p.value,class:"px-4 py-2 bg-primary/10 hover:bg-primary/20 text-primary rounded-xl text-sm font-medium disabled:opacity-50 transition-colors"},F(f.value||p.value?"…":"Apply"),9,Gh)]),u.value?(_(),E("p",Zh,F(u.value),1)):oe("",!0),c.value?(_(),E("p",zh,F(c.value),1)):oe("",!0),S[20]||(S[20]=d("p",{class:"text-xs text-content-muted"},[d("em",null,"main"),we(" = stable releases | "),d("em",null,"dev"),we(" = latest commits (may be unstable) ")],-1))]),b.value==="installing"||b.value==="restarting"||O.value.length>0&&($.value||b.value==="error")?(_(),E("div",Jh,[d("div",Xh,[S[24]||(S[24]=d("label",{class:"text-xs font-medium text-content-secondary uppercase tracking-wide"},"Install Log",-1)),b.value==="installing"?(_(),E("span",Yh,S[21]||(S[21]=[d("span",{class:"inline-block w-2 h-2 rounded-full bg-primary animate-pulse"},null,-1),we(" Running… ",-1)]))):b.value==="restarting"&&ee.value==="verifying"?(_(),E("span",Qh,S[22]||(S[22]=[d("span",{class:"inline-block w-2 h-2 rounded-full bg-primary animate-pulse"},null,-1),we(" Checking version… ",-1)]))):b.value==="restarting"?(_(),E("span",e5,[S[23]||(S[23]=d("span",{class:"inline-block w-2 h-2 rounded-full bg-yellow-500 animate-pulse"},null,-1)),we(" "+F(ee.value==="going-down"?"Stopping service…":"Waiting for service…"),1)])):b.value==="verified"?(_(),E("span",t5,"Complete ✓")):b.value==="verify-failed"||b.value==="error"?(_(),E("span",n5,"Failed ✗")):oe("",!0)]),d("div",{ref_key:"logContainer",ref:M,class:"bg-zinc-900 dark:bg-black/60 rounded-xl p-3 h-52 overflow-y-auto font-mono text-xs text-green-400 leading-relaxed border border-stroke/20"},[(_(!0),E(Re,null,He(O.value,(x,q)=>(_(),E("div",{key:q,class:fe(["whitespace-pre-wrap break-all",{"text-accent-red":x.includes("✗")||x.includes("error")||x.includes("ERROR")||x.includes("Failed"),"text-yellow-400":x.includes("WARNING")||x.includes("⚠"),"text-accent-green":x.includes("✓")||x.includes("Successfully"),"text-content-muted/60":x.includes("keepalive")}])},F(x),3))),128)),b.value==="installing"?(_(),E("div",r5)):oe("",!0),b.value==="restarting"&&ee.value==="verifying"?(_(),E("div",s5,S[25]||(S[25]=[d("span",{class:"w-3 h-3 border-2 border-primary border-t-transparent rounded-full animate-spin inline-block"},null,-1),we(" Service is back — verifying version… ",-1)]))):b.value==="restarting"?(_(),E("div",o5,[S[26]||(S[26]=d("span",{class:"w-3 h-3 border-2 border-yellow-400 border-t-transparent rounded-full animate-spin inline-block"},null,-1)),we(" "+F(ee.value==="going-down"?"Waiting for service to stop…":"Waiting for service to come back up…"),1)])):oe("",!0),O.value.length===0&&b.value==="installing"?(_(),E("div",i5,"Waiting for output…")):oe("",!0)],512),T.value?(_(),E("p",a5,F(T.value),1)):oe("",!0)])):oe("",!0),b.value==="restarting"&&ee.value==="verifying"?(_(),E("div",l5,S[27]||(S[27]=[d("span",{class:"w-4 h-4 border-2 border-primary border-t-transparent rounded-full animate-spin shrink-0"},null,-1),d("div",null,[d("p",{class:"font-medium"},"Checking version…"),d("p",{class:"text-xs opacity-70 mt-0.5"},"Confirming the installed version matches the target")],-1)]))):b.value==="restarting"&&O.value.length===0?(_(),E("div",c5,[d("div",u5,[S[28]||(S[28]=d("span",{class:"w-4 h-4 border-2 border-yellow-500 border-t-transparent rounded-full animate-spin shrink-0"},null,-1)),d("div",null,[d("p",d5,F(ee.value==="going-down"?"Stopping service…":"Starting service…"),1),d("p",f5,F(ee.value==="going-down"?"Waiting for the old process to exit":"Waiting for the service to become healthy"),1)])])])):oe("",!0),b.value==="verified"?(_(),E("div",p5,[d("div",h5,[S[31]||(S[31]=d("div",{class:"w-9 h-9 rounded-full bg-accent-green flex items-center justify-center shrink-0"},[d("svg",{class:"w-5 h-5 text-white",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2.5",d:"M5 13l4 4L19 7"})])],-1)),d("div",null,[S[30]||(S[30]=d("p",{class:"font-semibold text-gray-900 dark:text-content-primary"},"Installed successfully!",-1)),d("p",m5,[S[29]||(S[29]=we("Running version ",-1)),d("span",g5,F(U.value),1)])])]),d("button",{onClick:j,class:"mt-3 w-full py-2 px-4 rounded-xl text-sm font-semibold text-white bg-primary hover:bg-primary/90 transition-colors"}," Refresh Page to Load New Version ")])):oe("",!0),b.value==="verify-failed"?(_(),E("div",v5,[d("div",y5,[S[33]||(S[33]=d("div",{class:"w-9 h-9 rounded-full bg-accent-red/15 flex items-center justify-center shrink-0"},[d("svg",{class:"w-5 h-5 text-accent-red",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2.5",d:"M6 18L18 6M6 6l12 12"})])],-1)),d("div",b5,[S[32]||(S[32]=d("p",{class:"font-semibold text-accent-red"},"Installation may have failed",-1)),d("p",x5,F(T.value||"Version mismatch after restart"),1)])]),U.value||o.value?(_(),E("div",w5,[d("div",C5,[S[34]||(S[34]=d("p",{class:"text-content-muted mb-0.5"},"Expected",-1)),d("p",_5,F(o.value||"—"),1)]),d("div",k5,[S[35]||(S[35]=d("p",{class:"text-content-muted mb-0.5"},"Reported",-1)),d("p",S5,F(U.value||"unknown"),1)])])):oe("",!0),O.value.length>0?(_(),E("button",{key:1,onClick:S[3]||(S[3]=x=>$.value=!$.value),class:"w-full text-xs text-accent-red/70 hover:text-accent-red underline underline-offset-2 hover:no-underline transition-all"},F($.value?"Hide install log":"View install log"),1)):oe("",!0)])):oe("",!0)]),d("div",E5,[d("button",{onClick:re,disabled:!Q.value,class:fe(["flex-1 py-3 rounded-xl font-semibold text-sm transition-colors disabled:opacity-50 disabled:cursor-not-allowed",b.value==="verified"||b.value==="complete"?"bg-accent-green/20 text-accent-green cursor-default":b.value==="error"||b.value==="verify-failed"?"bg-accent-red hover:bg-accent-red/80 text-white":b.value==="restarting"?"bg-yellow-500/20 text-yellow-600 cursor-default":"bg-primary hover:bg-primary/80 text-white"])},[b.value==="installing"?(_(),E("span",A5,S[36]||(S[36]=[d("span",{class:"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"},null,-1),we(" Installing… ",-1)]))):b.value==="restarting"?(_(),E("span",T5,S[37]||(S[37]=[d("span",{class:"w-4 h-4 border-2 border-yellow-600 border-t-transparent rounded-full animate-spin"},null,-1),we(" Restarting service… ",-1)]))):(_(),E("span",M5,F(ae.value),1))],10,R5),b.value!=="installing"&&b.value!=="restarting"?(_(),E("button",{key:0,onClick:S[4]||(S[4]=x=>r("close")),class:"px-6 py-3 rounded-xl border border-stroke-subtle dark:border-stroke/20 text-content-secondary hover:text-content-primary hover:bg-background-mute transition-colors text-sm"}," Close ")):oe("",!0)])])])):oe("",!0)]))}}),L5={class:"glass-card p-3 sm:p-6 mb-5 rounded-[20px] relative z-10"},P5={class:"flex justify-between items-center"},$5={class:"flex items-center gap-3"},N5={class:"hidden sm:block"},I5={class:"text-content-primary dark:text-content-primary text-2xl lg:text-[35px] font-bold mb-1 sm:mb-2"},D5={class:"flex items-center gap-3 sm:gap-4"},V5={class:"text-right",style:{"min-width":"180px"}},F5={key:0,class:"flex items-center gap-2 justify-end"},B5={key:1,class:"space-y-1"},H5={class:"text-content-secondary dark:text-content-muted text-xs sm:text-sm"},j5={class:"text-primary font-medium"},U5={key:0,class:"text-xs text-content-muted dark:text-content-muted/80",style:{"min-height":"16px"}},q5={key:0},K5={key:2},W5={key:0,class:"text-xs text-content-muted dark:text-content-muted/60 hidden sm:block",style:{"min-height":"16px"}},G5={key:0,class:"absolute right-0 top-10 z-[100] w-48 bg-surface dark:bg-surface-elevated border border-stroke-subtle dark:border-stroke/20 rounded-xl shadow-2xl overflow-hidden"},Z5=["disabled"],z5={key:0,class:"w-4 h-4 text-content-secondary",viewBox:"0 0 20 20",fill:"none",stroke:"currentColor","stroke-width":"1.5",xmlns:"http://www.w3.org/2000/svg"},J5={key:1,class:"animate-spin rounded-full h-4 w-4 border-b-2 border-primary"},X5={class:"flex items-center justify-between mb-3"},Y5={class:"flex items-center gap-2"},Q5=["disabled"],e4=["disabled"],t4={class:"space-y-3 text-sm"},n4={key:0,class:"bg-red-50 dark:bg-background-mute p-3 rounded-lg border border-accent-red/30 border-l-2 border-l-accent-red"},r4={class:"flex items-center justify-between"},s4={class:"text-accent-red font-bold"},o4={class:"text-xs text-content-muted dark:text-content-muted mt-1"},i4={class:"mt-2 flex items-center gap-2"},a4=["disabled"],l4={key:1,class:"flex items-start gap-2 bg-amber-50 dark:bg-amber-500/10 border border-amber-200 dark:border-amber-500/30 border-l-2 border-l-amber-500 rounded-lg p-3 text-xs text-amber-800 dark:text-amber-300"},c4={key:2,class:"bg-green-50 dark:bg-background-mute p-3 rounded-lg border border-stroke-subtle dark:border-stroke/10 border-l-2 border-l-accent-green"},u4={class:"flex items-center justify-between"},d4={class:"text-accent-green font-bold"},f4={key:0,class:"text-xs text-content-muted dark:text-content-muted mt-1"},p4={class:"mt-2 flex items-center gap-2"},h4=["disabled"],m4={key:3,class:"bg-background-mute dark:bg-background-mute p-3 rounded-lg border border-stroke-subtle dark:border-stroke/10"},g4={key:4,class:"bg-red-50 dark:bg-background-mute p-3 rounded-lg border border-accent-red/30 border-l-2 border-l-accent-red"},v4={class:"text-xs text-content-secondary dark:text-content-muted"},y4={class:"bg-background-mute dark:bg-background-mute p-3 rounded-lg border border-stroke-subtle dark:border-stroke/10 border-l-2 border-l-primary"},b4={class:"flex items-center justify-between"},x4={class:"text-primary font-bold"},w4={key:0,class:"text-xs text-content-muted dark:text-content-muted mt-1"},C4={class:"flex items-center justify-between"},_4={class:"text-content-primary dark:text-content-primary font-medium"},k4={key:0,class:"mt-2"},S4={class:"text-xs text-content-muted dark:text-content-muted"},E4={class:"text-content-secondary dark:text-content-secondary"},R4={key:5,class:"bg-background-mute dark:bg-background-mute p-4 rounded-lg border border-stroke-subtle dark:border-stroke/10 text-center"},A4={key:6,class:"bg-background-mute dark:bg-background-mute p-3 rounded-lg border border-stroke-subtle dark:border-stroke/10 text-center"},T4={key:0,class:"fixed inset-0 z-[9999] bg-black/60 backdrop-blur-sm flex items-center justify-center"},M4={class:"bg-surface dark:bg-surface-elevated rounded-2xl p-8 shadow-2xl max-w-sm w-full mx-4 text-center border border-stroke-subtle dark:border-stroke/20"},O4={key:0,class:"mb-4"},L4={key:1,class:"mb-4"},P4={class:"text-sm text-content-secondary dark:text-content-muted"},$4={key:2,class:"mt-4 flex items-center justify-center gap-3"},N4=pt({name:"TopBar",__name:"TopBar",emits:["toggleMobileSidebar"],setup(e,{emit:t}){const n=t,r=Mo(),s=br(),o=B(!1),i=B(null),a=B(!1),l=B(!1),u=B(null),c=B(!1),f=B(""),p=B(!1),h=B({hasUpdate:!1,currentVersion:"",latestVersion:"",isChecking:!1,lastChecked:null,error:null,rateLimitUntil:null}),m=B({}),y=B(!0),b=B(null),T=B(r2()||"User"),O=["Chat Node","Repeater","Room Server"];function M(S){const x=S.target;i.value&&!i.value.contains(x)&&(o.value=!1),u.value&&!u.value.contains(x)&&(l.value=!1)}const $=async()=>{try{y.value=!0;const S={};for(const x of O)try{const q=await Te.get(`/adverts_by_contact_type?contact_type=${encodeURIComponent(x)}&hours=168`);q.success&&Array.isArray(q.data)?S[x]=q.data:S[x]=[]}catch(q){console.error(`Error fetching ${x} nodes:`,q),S[x]=[]}m.value=S,b.value=new Date}catch(S){console.error("Error updating tracked nodes:",S)}finally{y.value=!1}},U=async(S=!1)=>{if(!h.value.isChecking)try{h.value.isChecking=!0,h.value.error=null,await Te.post("/update/check",S?{force:!0}:{});for(let x=0;x<20;x++){const q=await Te.get("/update/status");if(q.success&&q.state!=="checking"){h.value.currentVersion=q.current_version??"",h.value.latestVersion=q.latest_version??"",h.value.hasUpdate=!!q.has_update,h.value.lastChecked=new Date,h.value.error=q.error??null,h.value.rateLimitUntil=q.rate_limit_until??null;return}await new Promise(H=>setTimeout(H,500))}h.value.error="Version check timed out"}catch(x){console.error("Error checking for updates:",x),h.value.error=x instanceof Error?x.message:"Failed to check for updates"}finally{h.value.isChecking=!1}},ee=()=>{o.value=!1,U(),s.fetchStats()},G=S=>{h.value.currentVersion=S.currentVersion,h.value.latestVersion=S.latestVersion,h.value.hasUpdate=S.hasUpdate,h.value.lastChecked=new Date},Y=()=>{vn(),r.push("/login")},L=async(S=20,x=2e3)=>{for(let q=0;qsetTimeout(H,x))}return!1},Q=async()=>{if(!c.value){c.value=!0,p.value=!1,f.value="Sending restart request...",l.value=!1;try{const S=await Te.post("/restart_service",{});S.success?(f.value="Service restarting, waiting for it to come back...",await L()?(f.value="Service is back! Reloading...",setTimeout(()=>{window.location.reload()},500)):(f.value="Service did not respond in time. Try reloading manually.",p.value=!0)):(f.value=S.error||"Restart request failed",p.value=!0)}catch(S){S.code==="ERR_NETWORK"||S.message?.includes("Network error")||S.response?.status===500||S.message?.includes("500")?(f.value="Service restarting, waiting for it to come back...",await L()?(f.value="Service is back! Reloading...",setTimeout(()=>{window.location.reload()},500)):(f.value="Service did not respond in time. Try reloading manually.",p.value=!0)):(f.value=S.message||"Restart request failed",p.value=!0)}}},ae=()=>{c.value=!1,f.value="",p.value=!1},W=()=>{window.location.reload()},N=ie(()=>Object.values(m.value).reduce((x,q)=>x+q.length,0)),J=ie(()=>O.map(x=>({type:x,count:m.value[x]?.length||0})).filter(x=>x.count>0)),he=ie(()=>!0),ce=S=>({"Chat Node":"text-blue-600 dark:text-blue-400",Repeater:"text-accent-green","Room Server":"text-accent-purple"})[S]||"text-gray-400",se=S=>{const x=m.value[S]||[];return x.length===0?"None":x.reduce((H,k)=>k.last_seen>H.last_seen?k:H,x[0]).node_name||"Unknown Node"};let re=null,be=null;const pe=()=>{re&&clearInterval(re),re=setInterval(()=>{$()},3e4),be&&clearInterval(be),be=setInterval(()=>{U()},6e5)},j=()=>{re&&(clearInterval(re),re=null),be&&(clearInterval(be),be=null)};gn(()=>{document.addEventListener("click",M),$(),U(),pe()}),ns(()=>{document.removeEventListener("click",M),j()});const D=()=>{n("toggleMobileSidebar")};return(S,x)=>(_(),E(Re,null,[d("div",L5,[d("div",P5,[d("div",$5,[d("button",{onClick:D,class:"lg:hidden w-10 h-10 rounded bg-background-mute dark:bg-surface-elevated flex items-center justify-center hover:bg-stroke-subtle dark:hover:bg-stroke/30 transition-colors"},x[10]||(x[10]=[d("svg",{class:"w-5 h-5 text-content-secondary dark:text-content-primary",viewBox:"0 0 20 20",fill:"none",xmlns:"http://www.w3.org/2000/svg"},[d("path",{d:"M3 6h14M3 10h14M3 14h14",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round","stroke-linejoin":"round"})],-1)])),d("div",N5,[d("h1",I5,"Hi "+F(T.value)+"👋",1)])]),d("div",D5,[d("div",V5,[y.value?(_(),E("div",F5,x[11]||(x[11]=[d("div",{class:"animate-spin rounded-full h-3 w-3 border-b-2 border-primary"},null,-1),d("p",{class:"text-content-secondary dark:text-content-muted text-xs sm:text-sm"},"Loading...",-1)]))):N.value>0?(_(),E("div",B5,[d("p",H5,[x[12]||(x[12]=we(" Tracking: ",-1)),d("span",j5,F(N.value)+" node"+F(N.value===1?"":"s"),1)]),J.value.length>0?(_(),E("div",U5,[(_(!0),E(Re,null,He(J.value,(q,H)=>(_(),E("span",{key:q.type,class:"inline"},[we(F(q.count)+" "+F(q.type)+F(q.count===1?"":"s"),1),H
{if(!r._listeners)return;let o=r._listeners.length;for(;o-- >0;)r._listeners[o](s);r._listeners=null}),this.promise.then=s=>{let o;const i=new Promise(a=>{r.subscribe(a),o=a}).then(s);return i.cancel=function(){r.unsubscribe(o)},i},t(function(o,i,a){r.reason||(r.reason=new Nn(o,i,a),n(r.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(t){if(this.reason){t(this.reason);return}this._listeners?this._listeners.push(t):this._listeners=[t]}unsubscribe(t){if(!this._listeners)return;const n=this._listeners.indexOf(t);n!==-1&&this._listeners.splice(n,1)}toAbortSignal(){const t=new AbortController,n=r=>{t.abort(r)};return this.subscribe(n),t.signal.unsubscribe=()=>this.unsubscribe(n),t.signal}static source(){let t;return{token:new hc(function(s){t=s}),cancel:t}}};function e2(e){return function(n){return e.apply(null,n)}}function t2(e){return R.isObject(e)&&e.isAxiosError===!0}const ro={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(ro).forEach(([e,t])=>{ro[t]=e});function mc(e){const t=new pn(e),n=Wl(pn.prototype.request,t);return R.extend(n,pn.prototype,t,{allOwnKeys:!0}),R.extend(n,t,null,{allOwnKeys:!0}),n.create=function(s){return mc(mn(e,s))},n}const $e=mc(yr);$e.Axios=pn;$e.CanceledError=Nn;$e.CancelToken=Q0;$e.isCancel=ac;$e.VERSION=pc;$e.toFormData=fs;$e.AxiosError=ve;$e.Cancel=$e.CanceledError;$e.all=function(t){return Promise.all(t)};$e.spread=e2;$e.isAxiosError=t2;$e.mergeConfig=mn;$e.AxiosHeaders=st;$e.formToJSON=e=>ic(R.isHTMLForm(e)?new FormData(e):e);$e.getAdapter=fc.getAdapter;$e.HttpStatusCode=ro;$e.default=$e;const{Axios:J4,AxiosError:X4,CanceledError:Y4,isCancel:Q4,CancelToken:e6,VERSION:t6,all:n6,Cancel:r6,isAxiosError:s6,spread:o6,toFormData:i6,AxiosHeaders:a6,HttpStatusCode:l6,formToJSON:c6,getAdapter:u6,mergeConfig:d6}=$e,Io="pymc_jwt_token",ua="pymc_client_id";function gc(){let e=localStorage.getItem(ua);return e||(e=`${Date.now()}-${Math.random().toString(36).substring(2,15)}`,localStorage.setItem(ua,e)),e}function Bt(){return localStorage.getItem(Io)}function n2(e){localStorage.setItem(Io,e)}function vn(){localStorage.removeItem(Io)}function vc(){return Bt()!==null}function Do(e){try{const n=e.split(".")[1].replace(/-/g,"+").replace(/_/g,"/"),r=decodeURIComponent(atob(n).split("").map(s=>"%"+("00"+s.charCodeAt(0).toString(16)).slice(-2)).join(""));return JSON.parse(r)}catch{return null}}function yc(){const e=Bt();if(!e)return!0;const t=Do(e);return!t||!t.exp?!0:Date.now()>=t.exp*1e3-3e4}function bc(){const e=Bt();if(!e)return!1;const t=Do(e);if(!t||!t.exp)return!1;const n=t.exp*1e3-Date.now();return n>0&&n<3e5}function r2(){const e=Bt();if(!e)return null;const t=Do(e);return!t||!t.sub?null:t.sub}const s2="modulepreload",o2=function(e){return"/"+e},da={},Ge=function(t,n,r){let s=Promise.resolve();if(n&&n.length>0){let l=function(u){return Promise.all(u.map(c=>Promise.resolve(c).then(f=>({status:"fulfilled",value:f}),f=>({status:"rejected",reason:f}))))};document.getElementsByTagName("link");const i=document.querySelector("meta[property=csp-nonce]"),a=i?.nonce||i?.getAttribute("nonce");s=l(n.map(u=>{if(u=o2(u),u in da)return;da[u]=!0;const c=u.endsWith(".css"),f=c?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${u}"]${f}`))return;const p=document.createElement("link");if(p.rel=c?"stylesheet":s2,c||(p.as="script"),p.crossOrigin="",p.href=u,a&&p.setAttribute("nonce",a),document.head.appendChild(p),c)return new Promise((h,m)=>{p.addEventListener("load",h),p.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${u}`)))})}))}function o(i){const a=new Event("vite:preloadError",{cancelable:!0});if(a.payload=i,window.dispatchEvent(a),!a.defaultPrevented)throw i}return s.then(i=>{for(const a of i||[])a.status==="rejected"&&o(a.reason);return t().catch(o)})},Vt=Sf({history:nf("/"),routes:[{path:"/setup",name:"setup",component:()=>Ge(()=>import("./Setup-Dq5DYqa_.js"),__vite__mapDeps([0,1])),meta:{requiresAuth:!1,requiresSetup:!1}},{path:"/login",name:"login",component:()=>Ge(()=>import("./Login-D0PhxOgj.js"),__vite__mapDeps([2,3])),meta:{requiresAuth:!1}},{path:"/",name:"dashboard",component:()=>Ge(()=>import("./Dashboard-Cv42kxN_.js"),__vite__mapDeps([4,5,6,7,8])),meta:{requiresAuth:!0}},{path:"/neighbors",name:"neighbors",component:()=>Ge(()=>import("./Neighbors-Iq3xu5XJ.js"),__vite__mapDeps([9,6,10,11,7,12,13])),meta:{requiresAuth:!0}},{path:"/statistics",name:"statistics",component:()=>Ge(()=>import("./Statistics-Sn0kb5mJ.js"),__vite__mapDeps([14,15,5,16,7,17,11,18])),meta:{requiresAuth:!0}},{path:"/system-stats",name:"system-stats",component:()=>Ge(()=>import("./SystemStats-D99udK9A.js"),__vite__mapDeps([19,15,5,16,20])),meta:{requiresAuth:!0}},{path:"/configuration",name:"configuration",component:()=>Ge(()=>import("./Configuration-COSqDNV7.js"),__vite__mapDeps([21,22,7,23,13])),meta:{requiresAuth:!0}},{path:"/cad-calibration",name:"cad-calibration",component:()=>Ge(()=>import("./CADCalibration-CCeYRLvI.js"),__vite__mapDeps([24,17,11,25])),meta:{requiresAuth:!0}},{path:"/sessions",name:"sessions",component:()=>Ge(()=>import("./Sessions-rHkTsOlY.js"),[]),meta:{requiresAuth:!0}},{path:"/room-servers",name:"room-servers",component:()=>Ge(()=>import("./RoomServers-CGLfVLxc.js"),__vite__mapDeps([26,7,22,27])),meta:{requiresAuth:!0}},{path:"/companions",name:"companions",component:()=>Ge(()=>import("./Companions-dkXrpFyo.js"),__vite__mapDeps([28,22,27])),meta:{requiresAuth:!0}},{path:"/logs",name:"logs",component:()=>Ge(()=>import("./Logs-FrDrsrTw.js"),[]),meta:{requiresAuth:!0}},{path:"/terminal",name:"terminal",component:()=>Ge(()=>import("./Terminal-CO_C7fq3.js"),__vite__mapDeps([29,30])),meta:{requiresAuth:!0}},{path:"/help",name:"help",component:()=>Ge(()=>import("./Help-xigBHw94.js"),[]),meta:{requiresAuth:!0}}]});async function fa(){try{const e=await fetch("/api/needs_setup",{headers:{Accept:"application/json"}});if(!e.ok)return console.error("Setup check failed:",e.status),!1;const t=await e.json();return console.log("Setup status check:",t),t.needs_setup===!0}catch(e){return console.error("Error checking setup status:",e),!1}}Vt.beforeEach(async(e,t,n)=>{const r=e.meta.requiresAuth!==!1,s=vc();if(e.path!=="/setup"&&await fa()){n("/setup");return}if(e.path==="/setup"&&!await fa()){n("/login");return}r&&!s?n("/login"):e.path==="/login"&&s?n("/"):n()});const i2="/api",Gr="";let $s=!1,jn=null;async function xc(){return $s&&jn||($s=!0,jn=(async()=>{try{const e=Bt();if(!e)throw new Error("No token to refresh");const t=gc(),n=await $e.post(`${Gr}/auth/refresh`,{client_id:t},{headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}});if(n.data.success&&n.data.token){const r=n.data.token;return n2(r),console.log("Token refreshed successfully"),r}else throw new Error("Token refresh failed")}catch(e){throw console.error("Token refresh error:",e),vn(),Vt.push("/login"),e}finally{$s=!1,jn=null}})()),jn}const ln=$e.create({baseURL:i2,timeout:5e3,headers:{"Content-Type":"application/json"}}),wc=$e.create({baseURL:Gr,timeout:5e3,headers:{"Content-Type":"application/json"}});wc.interceptors.request.use(async e=>{if(e.url?.includes("/auth/login")||e.url?.includes("/auth/refresh"))return e;const t=Bt();if(t){if(bc())try{const n=await xc();return e.headers.Authorization=`Bearer ${n}`,e}catch(n){return Promise.reject(n)}if(yc())return vn(),Vt.push("/login"),Promise.reject(new Error("Token expired"));e.headers.Authorization=`Bearer ${t}`}return e},e=>(console.error("Auth API Request Error:",e),Promise.reject(e)));wc.interceptors.response.use(e=>e,e=>(e.response?.status===401&&(vn(),Vt.currentRoute.value.path!=="/login"&&Vt.push("/login")),console.error("Auth API Response Error:",e.response?.data||e.message),Promise.reject(e)));ln.interceptors.request.use(async e=>{if(e.url?.includes("/auth/login"))return e;const t=Bt();if(t){if(bc())try{const n=await xc();return e.headers.Authorization=`Bearer ${n}`,e}catch(n){return Promise.reject(n)}if(yc())return vn(),Vt.push("/login"),Promise.reject(new Error("Token expired"));e.headers.Authorization=`Bearer ${t}`}return e},e=>(console.error("API Request Error:",e),Promise.reject(e)));ln.interceptors.response.use(e=>e,e=>(e.response?.status===401&&(vn(),Vt.currentRoute.value.path!=="/login"&&Vt.push("/login")),console.error("API Response Error:",e.response?.data||e.message),Promise.reject(e)));class Te{static async get(t,n){try{return(await ln.get(t,{params:n})).data}catch(r){throw this.handleError(r)}}static async post(t,n,r){try{return(await ln.post(t,n,r)).data}catch(s){throw this.handleError(s)}}static async put(t,n,r){try{return(await ln.put(t,n,r)).data}catch(s){throw this.handleError(s)}}static async delete(t,n){try{return(await ln.delete(t,n)).data}catch(r){throw this.handleError(r)}}static async getTransportKeys(){return this.get("transport_keys")}static async sendAdvert(){return this.post("send_advert",{},{headers:{"Content-Type":"application/json"}})}static async createTransportKey(t,n,r,s,o){const i={name:t,flood_policy:n,parent_id:s,last_used:o};return r!==void 0&&(i.transport_key=r),this.post("transport_keys",i)}static async getTransportKey(t){return this.get(`transport_key/${t}`)}static async updateTransportKey(t,n,r,s,o,i){return this.put(`transport_key/${t}`,{name:n,flood_policy:r,transport_key:s,parent_id:o,last_used:i})}static async deleteTransportKey(t){return this.delete(`transport_key/${t}`)}static async updateGlobalFloodPolicy(t){return this.post("global_flood_policy",{global_flood_allow:t})}static async getLogs(){try{return(await ln.get("logs")).data}catch(t){throw this.handleError(t)}}static async deleteAdvert(t){return this.delete(`advert/${t}`)}static async pingNeighbor(t,n=10){return this.post("ping_neighbor",{target_id:t,timeout:n})}static async getIdentities(){return this.get("identities")}static async getIdentity(t){return this.get("identity",{name:t})}static async createIdentity(t){return this.post("create_identity",t)}static async updateIdentity(t){return this.put("update_identity",t)}static async deleteIdentity(t,n="room_server"){const r=new URLSearchParams({name:t});return n==="companion"&&r.set("type","companion"),this.delete(`delete_identity?${r.toString()}`)}static async sendRoomServerAdvert(t){return this.post("send_room_server_advert",{name:t})}static async importRepeaterContacts(t){return this.post("companion/import_repeater_contacts",t)}static async getACLInfo(){return this.get("acl_info")}static async getACLClients(t){return this.get("acl_clients",t)}static async removeACLClient(t){return this.post("acl_remove_client",t)}static async getACLStats(){return this.get("acl_stats")}static async getRoomMessages(t){return this.get("room_messages",t)}static async postRoomMessage(t){return this.post("room_post_message",t)}static async deleteRoomMessage(t){return this.delete(`room_message?room_name=${encodeURIComponent(t.room_name)}&message_id=${t.message_id}`)}static async clearRoomMessages(t){return this.delete(`room_messages?room_name=${encodeURIComponent(t)}`)}static async getRoomStats(t){return this.get("room_stats",t?{room_name:t}:void 0)}static async getRoomClients(t){return this.get("room_clients",{room_name:t})}static async exportConfig(t=!1){const n=t?"config_export?include_secrets=true":"config_export";return this.get(n)}static async importConfig(t){return this.post("config_import",{config:t})}static async exportIdentityKey(){return this.get("identity_export")}static async generateVanityKey(t,n=!1){return this.post("generate_vanity_key",{prefix:t,apply:n})}static async getDbStats(){return this.get("db_stats")}static async purgeTable(t){return this.post("db_purge",{tables:t})}static async vacuumDb(){return this.post("db_vacuum",{})}static handleError(t){if($e.isAxiosError(t)){if(t.response){const n=t.response.data?.error||t.response.data?.message||`HTTP ${t.response.status}`;return new Error(n)}else if(t.request)return new Error("Network error - no response received")}return new Error(t instanceof Error?t.message:"Unknown error occurred")}}const br=Ro("system",()=>{const e=B(null),t=B(!1),n=B(null),r=B(null),s=B("forward"),o=B(!0),i=B(0),a=B(10),l=B(!1),u=ie(()=>e.value?.config?.node_name??"Unknown"),c=ie(()=>{const N=e.value?.public_key;return!N||N==="Unknown"?"Unknown":N.length>=16?`${N.slice(0,8)} ... ${N.slice(-8)}`:`${N}`}),f=ie(()=>e.value!==null),p=ie(()=>e.value?.version??"Unknown"),h=ie(()=>e.value?.core_version??"Unknown"),m=ie(()=>e.value?.noise_floor_dbm??null),y=ie(()=>a.value>0?Math.min(i.value/a.value*100,100):0),b=ie(()=>s.value==="no_tx"?{text:"No TX",title:"No repeat, no local TX; adverts skipped"}:s.value==="monitor"?{text:"Monitor Mode",title:"Monitoring only - not forwarding packets"}:o.value?{text:"Active",title:"Forwarding with duty cycle enforcement"}:{text:"No Limits",title:"Forwarding without duty cycle enforcement"}),T=ie(()=>({mode:s.value})),O=ie(()=>o.value?{active:!0,warning:!1}:{active:!1,warning:!0}),M=N=>{l.value=N};async function $(){try{t.value=!0,n.value=null;const N=await Te.get("/stats");if(N.success&&N.data)return e.value=N.data,r.value=new Date,U(N.data),N.data;if(N&&"version"in N){const J=N;return e.value=J,r.value=new Date,U(J),J}else throw new Error(N.error||"Failed to fetch stats")}catch(N){throw n.value=N instanceof Error?N.message:"Unknown error occurred",console.error("Error fetching stats:",N),N}finally{t.value=!1}}function U(N){if(N.config){const he=N.config.repeater?.mode;he==="forward"||he==="monitor"||he==="no_tx"?s.value=he:he!==void 0&&(s.value="forward");const ce=N.config.duty_cycle;if(ce){o.value=ce.enforcement_enabled!==!1;const se=ce.max_airtime_percent;typeof se=="number"?a.value=se:se&&typeof se=="object"&&"parsedValue"in se&&(a.value=se.parsedValue||10)}}const J=N.utilization_percent;typeof J=="number"?i.value=J:J&&typeof J=="object"&&"parsedValue"in J&&(i.value=J.parsedValue||0)}async function ee(N){try{const J=await Te.post("/set_mode",{mode:N});if(J.success)return s.value=N,!0;throw new Error(J.error||"Failed to set mode")}catch(J){throw n.value=J instanceof Error?J.message:"Unknown error occurred",console.error("Error setting mode:",J),J}}async function G(N){try{const J=await Te.post("/set_duty_cycle",{enabled:N});if(J.success)return o.value=N,!0;throw new Error(J.error||"Failed to set duty cycle")}catch(J){throw n.value=J instanceof Error?J.message:"Unknown error occurred",console.error("Error setting duty cycle:",J),J}}async function Y(){try{const N=await Te.post("/send_advert",{},{timeout:1e4});if(N.success)return console.log("Advertisement sent successfully:",N.data),!0;throw new Error(N.error||"Failed to send advert")}catch(N){throw n.value=N instanceof Error?N.message:"Unknown error occurred",console.error("Error sending advert:",N),N}}async function L(){return await G(!o.value)}function Q(N){e.value?(N.uptime_seconds!==void 0&&(e.value.uptime_seconds=N.uptime_seconds),N.noise_floor_dbm!==void 0&&(e.value.noise_floor_dbm=N.noise_floor_dbm)):e.value=N,r.value=new Date,U(N)}async function ae(N=5e3,J=!1){J||await $();let he=null;return J||(he=setInterval(async()=>{try{await $()}catch(ce){console.error("Auto-refresh error:",ce)}},N)),()=>{he&&clearInterval(he)}}function W(){e.value=null,n.value=null,r.value=null,t.value=!1,s.value="forward",o.value=!0,i.value=0,a.value=10}return{stats:e,isLoading:t,error:n,lastUpdated:r,currentMode:s,dutyCycleEnabled:o,dutyCycleUtilization:i,dutyCycleMax:a,cadCalibrationRunning:l,nodeName:u,pubKey:c,hasStats:f,version:p,coreVersion:h,noiseFloorDbm:m,dutyCyclePercentage:y,statusBadge:b,modeButtonState:T,dutyCycleButtonState:O,fetchStats:$,setMode:ee,setDutyCycle:G,sendAdvert:Y,toggleDutyCycle:L,startAutoRefresh:ae,updateRealtimeStats:Q,reset:W,setCadCalibrationRunning:M}}),Cc=Ro("packets",()=>{const e=B(null),t=B(null),n=B([]),r=B([]),s=B(null),o=B(!1),i=B(null),a=B(null),l=B([]),u=B([]),c=B(null),f=B(0),p=B([]),h=B({rx:0,tx:0,drop:0}),m=B({rx:0,tx:0,drop:0}),y=ie(()=>e.value!==null),b=ie(()=>t.value!==null),T=ie(()=>n.value.length>0),O=ie(()=>r.value.length>0),M=ie(()=>s.value?.avg_noise_floor??0),$=ie(()=>e.value?.total_packets??0),U=ie(()=>e.value?.avg_rssi??0),ee=ie(()=>e.value?.avg_snr??0),G=ie(()=>t.value?.uptime_seconds??0),Y=ie(()=>{if(!e.value?.packet_types)return[];const A=e.value.packet_types,C=A.reduce((Z,xe)=>Z+xe.count,0);return A.map(Z=>({type:Z.type.toString(),count:Z.count,percentage:C>0?Z.count/C*100:0}))}),L=ie(()=>{const A={};return n.value.forEach(C=>{A[C.type]||(A[C.type]=[]),A[C.type].push(C)}),A});async function Q(){try{const A=await Te.get("/stats");if(A.success&&A.data){t.value=A.data;const C=new Date;return u.value.push({timestamp:C,stats:A.data}),u.value.length>50&&(u.value=u.value.slice(-50)),A.data}else if(A&&"version"in A){const C=A;t.value=C;const Z=new Date;return u.value.push({timestamp:Z,stats:C}),u.value.length>50&&(u.value=u.value.slice(-50)),C}else throw new Error(A.error||"Failed to fetch system stats")}catch(A){throw i.value=A instanceof Error?A.message:"Unknown error occurred",console.error("Error fetching system stats:",A),A}}async function ae(A={hours:24}){try{const C=await Te.get("/noise_floor_history",A);if(C.success&&C.data&&C.data.history)return r.value=C.data.history,a.value=new Date,C.data.history;throw new Error(C.error||"Failed to fetch noise floor history")}catch(C){throw i.value=C instanceof Error?C.message:"Unknown error occurred",console.error("Error fetching noise floor history:",C),C}}async function W(A={hours:24}){try{const C=await Te.get("/noise_floor_stats",A);if(C.success&&C.data&&C.data.stats)return s.value=C.data.stats,a.value=new Date,C.data.stats;throw new Error(C.error||"Failed to fetch noise floor stats")}catch(C){throw i.value=C instanceof Error?C.message:"Unknown error occurred",console.error("Error fetching noise floor stats:",C),C}}const N=ie(()=>!r.value||!Array.isArray(r.value)?[]:r.value.slice(-50).map(A=>A.noise_floor_dbm));async function J(A={hours:24}){try{o.value=!0,i.value=null;const C=await Te.get("/packet_stats",A);if(C.success&&C.data){e.value=C.data;const Z=new Date;l.value.push({timestamp:Z,stats:C.data}),l.value.length>50&&(l.value=l.value.slice(-50)),a.value=Z}else throw new Error(C.error||"Failed to fetch packet stats")}catch(C){i.value=C instanceof Error?C.message:"Unknown error occurred",console.error("Error fetching packet stats:",C)}finally{o.value=!1}}async function he(A={limit:100}){try{o.value=!0,i.value=null;const C=await Te.get("/recent_packets",A);if(C.success&&C.data)n.value=C.data,a.value=new Date;else throw new Error(C.error||"Failed to fetch recent packets")}catch(C){i.value=C instanceof Error?C.message:"Unknown error occurred",console.error("Error fetching recent packets:",C)}finally{o.value=!1}}async function ce(A){try{o.value=!0,i.value=null;const C=await Te.get("/filtered_packets",A);if(C.success&&C.data)return n.value=C.data,a.value=new Date,C.data;throw new Error(C.error||"Failed to fetch filtered packets")}catch(C){throw i.value=C instanceof Error?C.message:"Unknown error occurred",console.error("Error fetching filtered packets:",C),C}finally{o.value=!1}}async function se(A){try{o.value=!0,i.value=null;const C=await Te.get("/packet_by_hash",{packet_hash:A});if(C.success&&C.data)return C.data;throw new Error(C.error||"Packet not found")}catch(C){throw i.value=C instanceof Error?C.message:"Unknown error occurred",console.error("Error fetching packet by hash:",C),C}finally{o.value=!1}}const re=ie(()=>{if(!c.value?.series)return{totalPackets:[],transmittedPackets:[],droppedPackets:[],crcErrors:p.value.map(v=>v.count),currentRates:h.value};const A=c.value.series.find(v=>v.type==="rx_count"),C=c.value.series.find(v=>v.type==="tx_count"),Z=A?.data||[],xe=C?.data||[],g=Z.map((v,w)=>{const P=xe[w];return P?Math.max(0,v[1]-P[1]):v[1]});return{totalPackets:Z.map(v=>v[1]),transmittedPackets:xe.map(v=>v[1]),droppedPackets:g,crcErrors:p.value.map(v=>v.count),currentRates:h.value}}),be=ie(()=>{const A=l.value,C=u.value;return{totalPackets:A.map(Z=>Z.stats.total_packets),transmittedPackets:A.map(Z=>Z.stats.transmitted_packets),droppedPackets:A.map(Z=>Z.stats.dropped_packets),avgRssi:A.map(Z=>Z.stats.avg_rssi),uptimeHours:C.map(Z=>Math.floor((Z.stats.uptime_seconds||0)/3600))}});async function pe(A=3e4){await Promise.all([Q(),J(),he(),ae({hours:1}),W({hours:1})]);const C=setInterval(async()=>{try{await Promise.all([Q(),J(),he(),ae({hours:1}),W({hours:1})])}catch(Z){console.error("Auto-refresh error:",Z)}},A);return()=>clearInterval(C)}async function j(A=24){try{const[C,Z]=await Promise.all([Te.get("/crc_error_count",{hours:A}),Te.get("/crc_error_history",{hours:A})]);C?.success&&C.data&&(f.value=C.data.crc_error_count??0),Z?.success&&Z.data&&(p.value=Z.data.history??[])}catch(C){console.error("Failed to fetch CRC error data:",C)}}async function D(){try{const[A]=await Promise.all([Te.get("/metrics_graph_data",{hours:24,resolution:"average",metrics:"rx_count,tx_count"}),j(24)]);A?.success&&A.data&&(c.value=A.data)}catch(A){console.error("Failed to fetch sparkline data:",A)}}async function S(){await D()}function x(){D()}function q(){e.value=null,t.value=null,n.value=[],r.value=[],s.value=null,l.value=[],u.value=[],c.value=null,f.value=0,p.value=[],h.value={rx:0,tx:0,drop:0},m.value={rx:0,tx:0,drop:0},i.value=null,a.value=null,o.value=!1}function H(A){n.value.unshift(A),n.value.length>1e3&&(n.value=n.value.slice(0,1e3))}function k(A){if(A.packet_stats){e.value=A.packet_stats;const C=new Date;l.value.push({timestamp:C,stats:A.packet_stats}),l.value.length>50&&(l.value=l.value.slice(-50))}if(A.system_stats){t.value=A.system_stats;const C=new Date;u.value.push({timestamp:C,stats:A.system_stats}),u.value.length>50&&(u.value=u.value.slice(-50))}a.value=new Date}return{packetStats:e,systemStats:t,recentPackets:n,noiseFloorHistory:r,noiseFloorStats:s,packetStatsHistory:l,systemStatsHistory:u,isLoading:o,error:i,lastUpdated:a,hasPacketStats:y,hasSystemStats:b,hasRecentPackets:T,hasNoiseFloorData:O,currentNoiseFloor:M,totalPackets:$,averageRSSI:U,averageSNR:ee,uptime:G,packetTypeBreakdown:Y,recentPacketsByType:L,sparklineData:re,legacySparklineData:be,noiseFloorSparklineData:N,crcErrorCount:f,interpolatedRates:h,fetchSystemStats:Q,fetchPacketStats:J,fetchCrcErrors:j,fetchRecentPackets:he,fetchFilteredPackets:ce,getPacketByHash:se,fetchNoiseFloorHistory:ae,fetchNoiseFloorStats:W,startAutoRefresh:pe,initializeSparklineHistory:S,interpolateRates:x,reset:q,addRealtimePacket:H,updateRealtimeStats:k}}),_c=Ro("websocket",()=>{const e=B(null),t=B(!1),n=B(0),r=B(null),s=B(Date.now()),o=Cc(),i=br();function a(){if(e.value){if(e.value.readyState===WebSocket.OPEN){console.log("[WebSocket] Already connected, skipping connect()");return}else if(e.value.readyState===WebSocket.CONNECTING){console.log("[WebSocket] Already connecting, skipping connect()");return}}let u;const c=Bt(),f=gc(),p=new URLSearchParams;c&&p.set("token",c),f&&p.set("client_id",f);{const h=window.location.protocol==="https:"?"wss:":"ws:",m=Gr?.trim()?new URL(Gr).host:window.location.host;u=`${h}//${m}/ws/packets?${p.toString()}`}console.log("[WebSocket] Creating new connection..."),e.value=new WebSocket(u),e.value.onopen=()=>{console.log("[WebSocket] Connected"),t.value=!0,n.value=0,s.value=Date.now(),r.value&&clearInterval(r.value),r.value=window.setInterval(()=>{e.value?.readyState===WebSocket.OPEN&&(e.value.send(JSON.stringify({type:"ping"})),Date.now()-s.value>6e4&&(console.warn("[WebSocket] No pong received, reconnecting..."),l(),a()))},3e4)},e.value.onmessage=h=>{try{const m=JSON.parse(h.data);m.type==="packet"?o.addRealtimePacket(m.data):m.type==="stats"?(m.data?.packet_stats&&o.updateRealtimeStats({packet_stats:m.data.packet_stats}),m.data?.system_stats&&i.updateRealtimeStats(m.data.system_stats)):m.type==="packet_stats"?o.updateRealtimeStats(m.data):m.type==="system_stats"?i.updateRealtimeStats(m.data):(m.type==="pong"||m.type==="ping")&&(s.value=Date.now(),m.type==="ping"&&e.value?.readyState===WebSocket.OPEN&&e.value.send(JSON.stringify({type:"pong"})))}catch(m){console.error("[WebSocket] Parse error:",m)}},e.value.onerror=()=>{if(console.log("[WebSocket] Error"),t.value=!1,e.value=null,r.value&&(clearInterval(r.value),r.value=null),n.value<5){const h=Math.min(1e3*Math.pow(2,Math.min(n.value,5)),3e4);console.log(`[WebSocket] Reconnecting in ${h}ms (attempt ${n.value+1})`),n.value++,setTimeout(a,h)}else console.error("[WebSocket] Max reconnection attempts reached - stopping")},e.value.onclose=()=>{console.log("[WebSocket] Disconnected"),t.value=!1,e.value=null,r.value&&(clearInterval(r.value),r.value=null),n.value<5?(n.value=0,setTimeout(a,3e3)):console.log("[WebSocket] Not reconnecting - max attempts reached")}}function l(){console.log("[WebSocket] Disconnecting..."),r.value&&(clearInterval(r.value),r.value=null),e.value&&(e.value.onclose=null,e.value.onerror=null,e.value.close(),e.value=null),t.value=!1,n.value=0}return{isConnected:t,connect:a,disconnect:l}}),Qe=(e,t)=>{const n=e.__vccOpts||e;for(const[r,s]of t)n[r]=s;return n},a2={},l2={width:"23",height:"25",viewBox:"0 0 23 25",fill:"none",xmlns:"http://www.w3.org/2000/svg"};function c2(e,t){return _(),E("svg",l2,t[0]||(t[0]=[d("path",{d:"M2.84279 2.25795C2.90709 1.12053 3.17879 0.625914 3.95795 0.228723C4.79631 -0.198778 6.11858 0.000168182 7.67449 0.788054C8.34465 1.12757 8.41289 1.13448 9.58736 0.983905C11.1485 0.783681 13.1582 0.784388 14.5991 0.985738C15.6887 1.13801 15.7603 1.1304 16.4321 0.790174C18.6406 -0.328212 20.3842 -0.255036 21.0156 0.982491C21.3308 1.6002 21.3893 3.20304 21.1449 4.52503C21.0094 5.25793 21.0238 5.34943 21.3502 5.83037C23.6466 9.21443 21.9919 14.6998 18.0569 16.7469C17.7558 16.9036 17.502 17.0005 17.2952 17.0795C16.6602 17.3219 16.4674 17.3956 16.7008 18.5117C16.8132 19.0486 16.9486 20.3833 17.0018 21.478C17.098 23.4567 17.0966 23.4705 16.7495 23.8742C16.2772 24.4233 15.5963 24.4326 15.135 23.8962C14.8341 23.5464 14.8047 23.3812 14.8047 22.0315C14.8047 20.037 14.5861 18.7113 14.0695 17.5753C13.4553 16.2235 13.9106 15.7194 15.3154 15.4173C17.268 14.9973 18.793 13.7923 19.643 11.9978C20.4511 10.2921 20.5729 7.93485 19.1119 6.50124C18.6964 6.00746 18.6674 5.56022 18.9641 4.21159C19.075 3.70754 19.168 3.05725 19.1707 2.76637C19.1749 2.30701 19.1331 2.23764 18.8509 2.23764C18.6724 2.23764 17.9902 2.49736 17.3352 2.81474L16.2897 3.32145C16.1947 3.36751 16.0883 3.38522 15.9834 3.37318C13.3251 3.06805 10.7991 3.06334 8.12774 3.37438C8.02244 3.38663 7.91563 3.36892 7.82025 3.32263L6.77535 2.81559C6.12027 2.49764 5.43813 2.23764 5.25963 2.23764C4.84693 2.23764 4.84072 2.54233 5.2169 4.35258C5.44669 5.45816 5.60133 5.70451 4.93703 6.58851C3.94131 7.91359 3.69258 9.55902 4.22654 11.2878C4.89952 13.4664 6.54749 14.9382 8.86436 15.4292C10.261 15.7253 10.6261 16.1115 10.0928 17.713C9.67293 18.9734 9.40748 19.2982 8.79738 19.2982C7.97649 19.2982 7.46228 18.5871 7.74527 17.843C7.86991 17.5151 7.83283 17.4801 7.06383 17.1996C4.71637 16.3437 2.9209 14.4254 2.10002 11.8959C1.46553 9.94098 1.74471 7.39642 2.76257 5.85843C3.10914 5.33477 3.1145 5.29036 2.95277 4.28787C2.86126 3.72037 2.81177 2.80699 2.84279 2.25795Z",fill:"currentColor"},null,-1),d("path",{d:"M2.02306 16.5589C1.68479 16.0516 0.999227 15.9144 0.491814 16.2527C-0.0155884 16.591 -0.152708 17.2765 0.185564 17.7839C0.435301 18.1586 0.734065 18.4663 0.987777 18.72C1.03455 18.7668 1.08 18.8119 1.12438 18.856C1.3369 19.0671 1.52455 19.2535 1.71302 19.4748C2.12986 19.964 2.54572 20.623 2.78206 21.8047C2.88733 22.3311 3.26569 22.6147 3.47533 22.7386C3.70269 22.8728 3.9511 22.952 4.15552 23.0036C4.57369 23.109 5.08133 23.1638 5.56309 23.1957C6.09196 23.2308 6.665 23.2422 7.17743 23.2453C7.1778 23.8547 7.67202 24.3487 8.28162 24.3487C8.89146 24.3487 9.38582 23.8543 9.38582 23.2445V22.1403C9.38582 21.5305 8.89146 21.0361 8.28162 21.0361C8.17753 21.0361 8.06491 21.0364 7.94562 21.0369C7.29761 21.0389 6.45295 21.0414 5.70905 20.9922C5.35033 20.9684 5.05544 20.9347 4.8392 20.8936C4.50619 19.5863 3.96821 18.7165 3.39415 18.0426C3.14038 17.7448 2.87761 17.4842 2.66387 17.2722C2.62385 17.2326 2.58556 17.1946 2.54935 17.1584C2.30273 16.9118 2.1414 16.7365 2.02306 16.5589Z",fill:"currentColor"},null,-1)]))}const u2=Qe(a2,[["render",c2]]),d2={},f2={width:"17",height:"24",viewBox:"0 0 17 24",fill:"none",xmlns:"http://www.w3.org/2000/svg"};function p2(e,t){return _(),E("svg",f2,t[0]||(t[0]=[At('
In Progress
setTimeout(H,2e3));try{const H=await Te.get("/update/status");if(!H?.success)continue;ee.value="verifying",await new Promise(A=>setTimeout(A,1200));const k=H.current_version??"";U.value=k,s.value=k||s.value,r("version-updated",{currentVersion:s.value,latestVersion:o.value,hasUpdate:!!H.has_update}),k&&D&&k===D?(b.value="verified",i.value=!1,ee.value=null,r("installed")):(b.value="verify-failed",ee.value=null);return}catch{}}b.value="verify-failed",ee.value=null,T.value="Service did not respond after restart — check logs"}nt(()=>n.show,D=>{D?(b.value="idle",T.value=null,O.value=[],$.value=!1,U.value=null,ee.value=null,Y.value=!1,L&&(clearTimeout(L),L=null),u.value="",c.value="",s.value=n.currentVersion,o.value=n.latestVersion,i.value=n.hasUpdate,ce(),he()):J()}),Pn(()=>{J(),L&&(clearTimeout(L),L=null)});function pe(D){D.target===D.currentTarget&&b.value!=="installing"&&b.value!=="restarting"&&r("close")}function j(){window.location.reload()}return(D,S)=>(_(),Ye(bo,{to:"body"},[n.show?(_(),E("div",{key:0,class:"fixed inset-0 bg-black/50 backdrop-blur-sm z-[99999] flex items-center justify-center p-4",onClick:pe},[d("div",{class:"bg-white dark:bg-surface-elevated rounded-[20px] w-full max-w-lg border border-stroke-subtle dark:border-white/10 shadow-2xl flex flex-col max-h-[90vh]",onClick:S[5]||(S[5]=Qn(()=>{},["stop"]))},[d("div",Ch,[S[7]||(S[7]=d("div",{class:"flex items-center gap-3"},[d("div",{class:"w-10 h-10 rounded-xl bg-primary/10 flex items-center justify-center"},[d("svg",{class:"w-5 h-5 text-primary",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"})])]),d("div",null,[d("h3",{class:"text-lg font-semibold text-content-primary dark:text-content-primary"},"OTA Update"),d("p",{class:"text-xs text-content-muted dark:text-content-muted"},"Update over the air from GitHub")])],-1)),b.value!=="installing"&&b.value!=="restarting"?(_(),E("button",{key:0,onClick:S[0]||(S[0]=x=>r("close")),class:"text-content-secondary hover:text-content-primary transition-colors"},S[6]||(S[6]=[d("svg",{class:"w-6 h-6",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M6 18L18 6M6 6l12 12"})],-1)]))):oe("",!0)]),d("div",_h,[d("div",kh,[d("div",Sh,[S[8]||(S[8]=d("p",{class:"text-xs text-content-muted mb-1"},"Installed",-1)),d("p",Eh,F(s.value||"—"),1)]),d("div",{class:fe(["bg-background-mute dark:bg-background-mute rounded-xl p-3 border border-stroke-subtle dark:border-stroke/10",i.value?"border-l-2 border-l-accent-red":"border-l-2 border-l-accent-green"])},[S[10]||(S[10]=d("p",{class:"text-xs text-content-muted mb-1"},"On GitHub",-1)),p.value?(_(),E("div",Rh,S[9]||(S[9]=[d("span",{class:"w-3 h-3 border-2 border-primary border-t-transparent rounded-full animate-spin inline-block"},null,-1),d("span",{class:"text-xs text-content-muted"},"Checking…",-1)]))):(_(),E("p",{key:1,class:fe(["text-sm font-mono font-medium",i.value?"text-accent-red":"text-accent-green"])},F(o.value||"—"),3))],2)]),n.rateLimitUntil?(_(),E("div",Ah,[S[14]||(S[14]=d("svg",{class:"w-4 h-4 shrink-0 mt-0.5 text-amber-600 dark:text-amber-400",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"})],-1)),d("div",Th,[S[13]||(S[13]=d("p",{class:"font-semibold mb-0.5"},"GitHub API rate limit reached",-1)),d("p",null,[S[11]||(S[11]=we("Version checks are paused until ",-1)),d("span",Mh,F(new Date(n.rateLimitUntil).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})),1),S[12]||(S[12]=we(". This is a GitHub limit, not a software issue. You can still install or switch channels manually.",-1))])])])):oe("",!0),!i.value&&s.value&&!p.value?(_(),E("div",Oh,S[15]||(S[15]=[d("svg",{class:"w-4 h-4 shrink-0",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M5 13l4 4L19 7"})],-1),we(" You are up to date. Use ",-1),d("em",{class:"mx-1"},"Force Reinstall",-1),we(" to reinstall anyway. ",-1)]))):oe("",!0),h.value.length>0||m.value?(_(),E("div",Lh,[d("button",{onClick:S[1]||(S[1]=x=>y.value=!y.value),class:"flex items-center justify-between w-full text-xs font-medium text-content-secondary dark:text-content-secondary uppercase tracking-wide py-1 hover:text-content-primary transition-colors"},[S[17]||(S[17]=d("span",null,"What's New",-1)),d("span",Ph,[m.value?(_(),E("span",$h)):(_(),E("span",Nh,F(h.value.length)+" commit"+F(h.value.length!==1?"s":""),1)),(_(),E("svg",{class:fe(["w-3.5 h-3.5 text-content-muted transition-transform",y.value?"rotate-180":""]),viewBox:"0 0 20 20",fill:"currentColor"},S[16]||(S[16]=[d("path",{"fill-rule":"evenodd",d:"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z","clip-rule":"evenodd"},null,-1)]),2))])]),y.value?(_(),E("div",Ih,[d("div",Dh,[(_(!0),E(Re,null,He(h.value,x=>(_(),E("a",{key:x.sha,href:x.url,target:"_blank",class:"flex gap-3 px-3 py-2.5 hover:bg-background-soft dark:hover:bg-surface/50 transition-colors group"},[d("span",Fh,F(x.short_sha),1),d("div",Bh,[d("p",Hh,F(x.title),1),d("p",jh,F(x.author)+" · "+F(x.date?new Date(x.date).toLocaleDateString():""),1)]),S[18]||(S[18]=d("svg",{class:"w-3 h-3 text-content-muted shrink-0 mt-1 opacity-0 group-hover:opacity-100 transition-opacity",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"})],-1))],8,Vh))),128))])])):oe("",!0)])):oe("",!0),d("div",Uh,[S[19]||(S[19]=d("label",{class:"text-xs font-medium text-content-secondary dark:text-content-secondary uppercase tracking-wide"}," Release Channel ",-1)),d("div",qh,[Au(d("select",{"onUpdate:modelValue":S[2]||(S[2]=x=>l.value=x),disabled:f.value||b.value==="installing"||p.value,class:"flex-1 bg-background-mute dark:bg-surface border border-stroke-subtle dark:border-stroke/20 rounded-xl px-3 py-2 text-sm text-content-primary dark:text-content-primary disabled:opacity-50 focus:outline-none focus:ring-1 focus:ring-primary"},[(_(!0),E(Re,null,He(a.value,x=>(_(),E("option",{key:x,value:x},F(x),9,Wh))),128))],8,Kh),[[sd,l.value]]),d("button",{onClick:se,disabled:f.value||b.value==="installing"||p.value,class:"px-4 py-2 bg-primary/10 hover:bg-primary/20 text-primary rounded-xl text-sm font-medium disabled:opacity-50 transition-colors"},F(f.value||p.value?"…":"Apply"),9,Gh)]),u.value?(_(),E("p",Zh,F(u.value),1)):oe("",!0),c.value?(_(),E("p",zh,F(c.value),1)):oe("",!0),S[20]||(S[20]=d("p",{class:"text-xs text-content-muted"},[d("em",null,"main"),we(" = stable releases | "),d("em",null,"dev"),we(" = latest commits (may be unstable) ")],-1))]),b.value==="installing"||b.value==="restarting"||O.value.length>0&&($.value||b.value==="error")?(_(),E("div",Jh,[d("div",Xh,[S[24]||(S[24]=d("label",{class:"text-xs font-medium text-content-secondary uppercase tracking-wide"},"Install Log",-1)),b.value==="installing"?(_(),E("span",Yh,S[21]||(S[21]=[d("span",{class:"inline-block w-2 h-2 rounded-full bg-primary animate-pulse"},null,-1),we(" Running… ",-1)]))):b.value==="restarting"&&ee.value==="verifying"?(_(),E("span",Qh,S[22]||(S[22]=[d("span",{class:"inline-block w-2 h-2 rounded-full bg-primary animate-pulse"},null,-1),we(" Checking version… ",-1)]))):b.value==="restarting"?(_(),E("span",e5,[S[23]||(S[23]=d("span",{class:"inline-block w-2 h-2 rounded-full bg-yellow-500 animate-pulse"},null,-1)),we(" "+F(ee.value==="going-down"?"Stopping service…":"Waiting for service…"),1)])):b.value==="verified"?(_(),E("span",t5,"Complete ✓")):b.value==="verify-failed"||b.value==="error"?(_(),E("span",n5,"Failed ✗")):oe("",!0)]),d("div",{ref_key:"logContainer",ref:M,class:"bg-zinc-900 dark:bg-black/60 rounded-xl p-3 h-52 overflow-y-auto font-mono text-xs text-green-400 leading-relaxed border border-stroke/20"},[(_(!0),E(Re,null,He(O.value,(x,q)=>(_(),E("div",{key:q,class:fe(["whitespace-pre-wrap break-all",{"text-accent-red":x.includes("✗")||x.includes("error")||x.includes("ERROR")||x.includes("Failed"),"text-yellow-400":x.includes("WARNING")||x.includes("⚠"),"text-accent-green":x.includes("✓")||x.includes("Successfully"),"text-content-muted/60":x.includes("keepalive")}])},F(x),3))),128)),b.value==="installing"?(_(),E("div",r5)):oe("",!0),b.value==="restarting"&&ee.value==="verifying"?(_(),E("div",s5,S[25]||(S[25]=[d("span",{class:"w-3 h-3 border-2 border-primary border-t-transparent rounded-full animate-spin inline-block"},null,-1),we(" Service is back — verifying version… ",-1)]))):b.value==="restarting"?(_(),E("div",o5,[S[26]||(S[26]=d("span",{class:"w-3 h-3 border-2 border-yellow-400 border-t-transparent rounded-full animate-spin inline-block"},null,-1)),we(" "+F(ee.value==="going-down"?"Waiting for service to stop…":"Waiting for service to come back up…"),1)])):oe("",!0),O.value.length===0&&b.value==="installing"?(_(),E("div",i5,"Waiting for output…")):oe("",!0)],512),T.value?(_(),E("p",a5,F(T.value),1)):oe("",!0)])):oe("",!0),b.value==="restarting"&&ee.value==="verifying"?(_(),E("div",l5,S[27]||(S[27]=[d("span",{class:"w-4 h-4 border-2 border-primary border-t-transparent rounded-full animate-spin shrink-0"},null,-1),d("div",null,[d("p",{class:"font-medium"},"Checking version…"),d("p",{class:"text-xs opacity-70 mt-0.5"},"Confirming the installed version matches the target")],-1)]))):b.value==="restarting"&&O.value.length===0?(_(),E("div",c5,[d("div",u5,[S[28]||(S[28]=d("span",{class:"w-4 h-4 border-2 border-yellow-500 border-t-transparent rounded-full animate-spin shrink-0"},null,-1)),d("div",null,[d("p",d5,F(ee.value==="going-down"?"Stopping service…":"Starting service…"),1),d("p",f5,F(ee.value==="going-down"?"Waiting for the old process to exit":"Waiting for the service to become healthy"),1)])])])):oe("",!0),b.value==="verified"?(_(),E("div",p5,[d("div",h5,[S[31]||(S[31]=d("div",{class:"w-9 h-9 rounded-full bg-accent-green flex items-center justify-center shrink-0"},[d("svg",{class:"w-5 h-5 text-white",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2.5",d:"M5 13l4 4L19 7"})])],-1)),d("div",null,[S[30]||(S[30]=d("p",{class:"font-semibold text-gray-900 dark:text-content-primary"},"Installed successfully!",-1)),d("p",m5,[S[29]||(S[29]=we("Running version ",-1)),d("span",g5,F(U.value),1)])])]),d("button",{onClick:j,class:"mt-3 w-full py-2 px-4 rounded-xl text-sm font-semibold text-white bg-primary hover:bg-primary/90 transition-colors"}," Refresh Page to Load New Version ")])):oe("",!0),b.value==="verify-failed"?(_(),E("div",v5,[d("div",y5,[S[33]||(S[33]=d("div",{class:"w-9 h-9 rounded-full bg-accent-red/15 flex items-center justify-center shrink-0"},[d("svg",{class:"w-5 h-5 text-accent-red",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24"},[d("path",{"stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2.5",d:"M6 18L18 6M6 6l12 12"})])],-1)),d("div",b5,[S[32]||(S[32]=d("p",{class:"font-semibold text-accent-red"},"Installation may have failed",-1)),d("p",x5,F(T.value||"Version mismatch after restart"),1)])]),U.value||o.value?(_(),E("div",w5,[d("div",C5,[S[34]||(S[34]=d("p",{class:"text-content-muted mb-0.5"},"Expected",-1)),d("p",_5,F(o.value||"—"),1)]),d("div",k5,[S[35]||(S[35]=d("p",{class:"text-content-muted mb-0.5"},"Reported",-1)),d("p",S5,F(U.value||"unknown"),1)])])):oe("",!0),O.value.length>0?(_(),E("button",{key:1,onClick:S[3]||(S[3]=x=>$.value=!$.value),class:"w-full text-xs text-accent-red/70 hover:text-accent-red underline underline-offset-2 hover:no-underline transition-all"},F($.value?"Hide install log":"View install log"),1)):oe("",!0)])):oe("",!0)]),d("div",E5,[d("button",{onClick:re,disabled:!Q.value,class:fe(["flex-1 py-3 rounded-xl font-semibold text-sm transition-colors disabled:opacity-50 disabled:cursor-not-allowed",b.value==="verified"||b.value==="complete"?"bg-accent-green/20 text-accent-green cursor-default":b.value==="error"||b.value==="verify-failed"?"bg-accent-red hover:bg-accent-red/80 text-white":b.value==="restarting"?"bg-yellow-500/20 text-yellow-600 cursor-default":"bg-primary hover:bg-primary/80 text-white"])},[b.value==="installing"?(_(),E("span",A5,S[36]||(S[36]=[d("span",{class:"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"},null,-1),we(" Installing… ",-1)]))):b.value==="restarting"?(_(),E("span",T5,S[37]||(S[37]=[d("span",{class:"w-4 h-4 border-2 border-yellow-600 border-t-transparent rounded-full animate-spin"},null,-1),we(" Restarting service… ",-1)]))):(_(),E("span",M5,F(ae.value),1))],10,R5),b.value!=="installing"&&b.value!=="restarting"?(_(),E("button",{key:0,onClick:S[4]||(S[4]=x=>r("close")),class:"px-6 py-3 rounded-xl border border-stroke-subtle dark:border-stroke/20 text-content-secondary hover:text-content-primary hover:bg-background-mute transition-colors text-sm"}," Close ")):oe("",!0)])])])):oe("",!0)]))}}),L5={class:"glass-card p-3 sm:p-6 mb-5 rounded-[20px] relative z-10"},P5={class:"flex justify-between items-center"},$5={class:"flex items-center gap-3"},N5={class:"hidden sm:block"},I5={class:"text-content-primary dark:text-content-primary text-2xl lg:text-[35px] font-bold mb-1 sm:mb-2"},D5={class:"flex items-center gap-3 sm:gap-4"},V5={class:"text-right",style:{"min-width":"180px"}},F5={key:0,class:"flex items-center gap-2 justify-end"},B5={key:1,class:"space-y-1"},H5={class:"text-content-secondary dark:text-content-muted text-xs sm:text-sm"},j5={class:"text-primary font-medium"},U5={key:0,class:"text-xs text-content-muted dark:text-content-muted/80",style:{"min-height":"16px"}},q5={key:0},K5={key:2},W5={key:0,class:"text-xs text-content-muted dark:text-content-muted/60 hidden sm:block",style:{"min-height":"16px"}},G5={key:0,class:"absolute right-0 top-10 z-[100] w-48 bg-surface dark:bg-surface-elevated border border-stroke-subtle dark:border-stroke/20 rounded-xl shadow-2xl overflow-hidden"},Z5=["disabled"],z5={key:0,class:"w-4 h-4 text-content-secondary",viewBox:"0 0 20 20",fill:"none",stroke:"currentColor","stroke-width":"1.5",xmlns:"http://www.w3.org/2000/svg"},J5={key:1,class:"animate-spin rounded-full h-4 w-4 border-b-2 border-primary"},X5={class:"flex items-center justify-between mb-3"},Y5={class:"flex items-center gap-2"},Q5=["disabled"],e4=["disabled"],t4={class:"space-y-3 text-sm"},n4={key:0,class:"bg-red-50 dark:bg-background-mute p-3 rounded-lg border border-accent-red/30 border-l-2 border-l-accent-red"},r4={class:"flex items-center justify-between"},s4={class:"text-accent-red font-bold"},o4={class:"text-xs text-content-muted dark:text-content-muted mt-1"},i4={class:"mt-2 flex items-center gap-2"},a4=["disabled"],l4={key:1,class:"flex items-start gap-2 bg-amber-50 dark:bg-amber-500/10 border border-amber-200 dark:border-amber-500/30 border-l-2 border-l-amber-500 rounded-lg p-3 text-xs text-amber-800 dark:text-amber-300"},c4={key:2,class:"bg-green-50 dark:bg-background-mute p-3 rounded-lg border border-stroke-subtle dark:border-stroke/10 border-l-2 border-l-accent-green"},u4={class:"flex items-center justify-between"},d4={class:"text-accent-green font-bold"},f4={key:0,class:"text-xs text-content-muted dark:text-content-muted mt-1"},p4={class:"mt-2 flex items-center gap-2"},h4=["disabled"],m4={key:3,class:"bg-background-mute dark:bg-background-mute p-3 rounded-lg border border-stroke-subtle dark:border-stroke/10"},g4={key:4,class:"bg-red-50 dark:bg-background-mute p-3 rounded-lg border border-accent-red/30 border-l-2 border-l-accent-red"},v4={class:"text-xs text-content-secondary dark:text-content-muted"},y4={class:"bg-background-mute dark:bg-background-mute p-3 rounded-lg border border-stroke-subtle dark:border-stroke/10 border-l-2 border-l-primary"},b4={class:"flex items-center justify-between"},x4={class:"text-primary font-bold"},w4={key:0,class:"text-xs text-content-muted dark:text-content-muted mt-1"},C4={class:"flex items-center justify-between"},_4={class:"text-content-primary dark:text-content-primary font-medium"},k4={key:0,class:"mt-2"},S4={class:"text-xs text-content-muted dark:text-content-muted"},E4={class:"text-content-secondary dark:text-content-secondary"},R4={key:5,class:"bg-background-mute dark:bg-background-mute p-4 rounded-lg border border-stroke-subtle dark:border-stroke/10 text-center"},A4={key:6,class:"bg-background-mute dark:bg-background-mute p-3 rounded-lg border border-stroke-subtle dark:border-stroke/10 text-center"},T4={key:0,class:"fixed inset-0 z-[9999] bg-black/60 backdrop-blur-sm flex items-center justify-center"},M4={class:"bg-surface dark:bg-surface-elevated rounded-2xl p-8 shadow-2xl max-w-sm w-full mx-4 text-center border border-stroke-subtle dark:border-stroke/20"},O4={key:0,class:"mb-4"},L4={key:1,class:"mb-4"},P4={class:"text-sm text-content-secondary dark:text-content-muted"},$4={key:2,class:"mt-4 flex items-center justify-center gap-3"},N4=pt({name:"TopBar",__name:"TopBar",emits:["toggleMobileSidebar"],setup(e,{emit:t}){const n=t,r=Mo(),s=br(),o=B(!1),i=B(null),a=B(!1),l=B(!1),u=B(null),c=B(!1),f=B(""),p=B(!1),h=B({hasUpdate:!1,currentVersion:"",latestVersion:"",isChecking:!1,lastChecked:null,error:null,rateLimitUntil:null}),m=B({}),y=B(!0),b=B(null),T=B(r2()||"User"),O=["Chat Node","Repeater","Room Server"];function M(S){const x=S.target;i.value&&!i.value.contains(x)&&(o.value=!1),u.value&&!u.value.contains(x)&&(l.value=!1)}const $=async()=>{try{y.value=!0;const S={};for(const x of O)try{const q=await Te.get(`/adverts_by_contact_type?contact_type=${encodeURIComponent(x)}&hours=168`);q.success&&Array.isArray(q.data)?S[x]=q.data:S[x]=[]}catch(q){console.error(`Error fetching ${x} nodes:`,q),S[x]=[]}m.value=S,b.value=new Date}catch(S){console.error("Error updating tracked nodes:",S)}finally{y.value=!1}},U=async(S=!1)=>{if(!h.value.isChecking)try{h.value.isChecking=!0,h.value.error=null,await Te.post("/update/check",S?{force:!0}:{});for(let x=0;x<20;x++){const q=await Te.get("/update/status");if(q.success&&q.state!=="checking"){h.value.currentVersion=q.current_version??"",h.value.latestVersion=q.latest_version??"",h.value.hasUpdate=!!q.has_update,h.value.lastChecked=new Date,h.value.error=q.error??null,h.value.rateLimitUntil=q.rate_limit_until??null;return}await new Promise(H=>setTimeout(H,500))}h.value.error="Version check timed out"}catch(x){console.error("Error checking for updates:",x),h.value.error=x instanceof Error?x.message:"Failed to check for updates"}finally{h.value.isChecking=!1}},ee=()=>{o.value=!1,U(),s.fetchStats()},G=S=>{h.value.currentVersion=S.currentVersion,h.value.latestVersion=S.latestVersion,h.value.hasUpdate=S.hasUpdate,h.value.lastChecked=new Date},Y=()=>{vn(),r.push("/login")},L=async(S=20,x=2e3)=>{for(let q=0;qsetTimeout(H,x))}return!1},Q=async()=>{if(!c.value){c.value=!0,p.value=!1,f.value="Sending restart request...",l.value=!1;try{const S=await Te.post("/restart_service",{});S.success?(f.value="Service restarting, waiting for it to come back...",await L()?(f.value="Service is back! Reloading...",setTimeout(()=>{window.location.reload()},500)):(f.value="Service did not respond in time. Try reloading manually.",p.value=!0)):(f.value=S.error||"Restart request failed",p.value=!0)}catch(S){S.code==="ERR_NETWORK"||S.message?.includes("Network error")||S.response?.status===500||S.message?.includes("500")?(f.value="Service restarting, waiting for it to come back...",await L()?(f.value="Service is back! Reloading...",setTimeout(()=>{window.location.reload()},500)):(f.value="Service did not respond in time. Try reloading manually.",p.value=!0)):(f.value=S.message||"Restart request failed",p.value=!0)}}},ae=()=>{c.value=!1,f.value="",p.value=!1},W=()=>{window.location.reload()},N=ie(()=>Object.values(m.value).reduce((x,q)=>x+q.length,0)),J=ie(()=>O.map(x=>({type:x,count:m.value[x]?.length||0})).filter(x=>x.count>0)),he=ie(()=>!0),ce=S=>({"Chat Node":"text-blue-600 dark:text-blue-400",Repeater:"text-accent-green","Room Server":"text-accent-purple"})[S]||"text-gray-400",se=S=>{const x=m.value[S]||[];return x.length===0?"None":x.reduce((H,k)=>k.last_seen>H.last_seen?k:H,x[0]).node_name||"Unknown Node"};let re=null,be=null;const pe=()=>{re&&clearInterval(re),re=setInterval(()=>{$()},3e4),be&&clearInterval(be),be=setInterval(()=>{U()},6e5)},j=()=>{re&&(clearInterval(re),re=null),be&&(clearInterval(be),be=null)};gn(()=>{document.addEventListener("click",M),$(),U(),pe()}),ns(()=>{document.removeEventListener("click",M),j()});const D=()=>{n("toggleMobileSidebar")};return(S,x)=>(_(),E(Re,null,[d("div",L5,[d("div",P5,[d("div",$5,[d("button",{onClick:D,class:"lg:hidden w-10 h-10 rounded bg-background-mute dark:bg-surface-elevated flex items-center justify-center hover:bg-stroke-subtle dark:hover:bg-stroke/30 transition-colors"},x[10]||(x[10]=[d("svg",{class:"w-5 h-5 text-content-secondary dark:text-content-primary",viewBox:"0 0 20 20",fill:"none",xmlns:"http://www.w3.org/2000/svg"},[d("path",{d:"M3 6h14M3 10h14M3 14h14",stroke:"currentColor","stroke-width":"1.5","stroke-linecap":"round","stroke-linejoin":"round"})],-1)])),d("div",N5,[d("h1",I5,"Hi "+F(T.value)+"👋",1)])]),d("div",D5,[d("div",V5,[y.value?(_(),E("div",F5,x[11]||(x[11]=[d("div",{class:"animate-spin rounded-full h-3 w-3 border-b-2 border-primary"},null,-1),d("p",{class:"text-content-secondary dark:text-content-muted text-xs sm:text-sm"},"Loading...",-1)]))):N.value>0?(_(),E("div",B5,[d("p",H5,[x[12]||(x[12]=we(" Tracking: ",-1)),d("span",j5,F(N.value)+" node"+F(N.value===1?"":"s"),1)]),J.value.length>0?(_(),E("div",U5,[(_(!0),E(Re,null,He(J.value,(q,H)=>(_(),E("span",{key:q.type,class:"inline"},[we(F(q.count)+" "+F(q.type)+F(q.count===1?"":"s"),1),H