swayrouter 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dashboard/dist/assets/{CliTools-Ch3gKuNw.js → CliTools-5DLXOz1A.js} +1 -1
- package/dashboard/dist/assets/{Combo-BBCldjWi.js → Combo-BCvuw7s2.js} +1 -1
- package/dashboard/dist/assets/{ConsoleLog-wywAYcPT.js → ConsoleLog-BwgJ9V8I.js} +4 -4
- package/dashboard/dist/assets/{Dashboard-DxzyF41b.js → Dashboard-B-tNs8a1.js} +1 -1
- package/dashboard/dist/assets/{Header-C_9Su9BF.js → Header-9KXz4S67.js} +1 -1
- package/dashboard/dist/assets/{Keys-D0ufgcsc.js → Keys-DE32cEsn.js} +1 -1
- package/dashboard/dist/assets/Login-z7dbRqrR.js +1 -0
- package/dashboard/dist/assets/{ManageApiKey-CVXsmW2B.js → ManageApiKey-DF3A1CXL.js} +1 -1
- package/dashboard/dist/assets/{OAuthCallback-D_UZYcF6.js → OAuthCallback-I8fzY5zi.js} +1 -1
- package/dashboard/dist/assets/Provider-Caq5lvsq.js +4 -0
- package/dashboard/dist/assets/{ProviderModelAccordion-BAifkfVR.js → ProviderModelAccordion-GZSOrZZu.js} +1 -1
- package/dashboard/dist/assets/{Proxy-CU15VJ--.js → Proxy-DJVhsf4E.js} +1 -1
- package/dashboard/dist/assets/QuotaMonitor-BA4GOxkV.js +1 -0
- package/dashboard/dist/assets/{Settings-Dt4y2dC0.js → Settings-eEpS37LF.js} +1 -1
- package/dashboard/dist/assets/{Setup-DSDUwU7N.js → Setup-D9G2dVUf.js} +1 -1
- package/dashboard/dist/assets/{StatusBadge-1nAOyHU2.js → StatusBadge-DClAYX7v.js} +1 -1
- package/dashboard/dist/assets/{SwayChat-Bup7up6D.js → SwayChat-DS0GBQKQ.js} +2 -2
- package/dashboard/dist/assets/Usage-CRQCq5jc.js +4 -0
- package/dashboard/dist/assets/{accordion-DOOPDDgt.js → accordion-BkSdf_dl.js} +1 -1
- package/dashboard/dist/assets/{admin-extras-api-CCdu5TFM.js → admin-extras-api-ppLkXcD9.js} +1 -1
- package/dashboard/dist/assets/{api-keys-api-ifAC2Ok3.js → api-keys-api-CsdHmg2W.js} +1 -1
- package/dashboard/dist/assets/{card-CC0Omjcv.js → card-BOVhvx7W.js} +1 -1
- package/dashboard/dist/assets/{checkbox-7SZBrmbN.js → checkbox-DU_0LpXJ.js} +1 -1
- package/dashboard/dist/assets/{connections-api-_N54UD3S.js → connections-api-CQHf0Hwe.js} +1 -1
- package/dashboard/dist/assets/{copy-button-qBvM6H9z.js → copy-button-nPFbNAXf.js} +1 -1
- package/dashboard/dist/assets/{currency-api-SV9CBf5e.js → currency-api-CDXu9UhW.js} +1 -1
- package/dashboard/dist/assets/{flip-button-BGgkjtl0.js → flip-button-C_PNv8Iq.js} +1 -1
- package/dashboard/dist/assets/{frame-cUiti6Lq.js → frame-BLwA8c3u.js} +1 -1
- package/dashboard/dist/assets/index-CN-Y5gO6.css +1 -0
- package/dashboard/dist/assets/index-x5tLD3Ye.js +10 -0
- package/dashboard/dist/assets/{ripple-button-l8aMiVVG.js → ripple-button-BV_KcZ7W.js} +1 -1
- package/dashboard/dist/assets/{segmented-CqmEnQjZ.js → segmented-BBSMiP-0.js} +1 -1
- package/dashboard/dist/assets/select-DELc8FMO.js +1 -0
- package/dashboard/dist/assets/{skeleton-7uJDiIXe.js → skeleton-CFSSp0e0.js} +1 -1
- package/dashboard/dist/assets/{table-D0M60Tu1.js → table-lcAgAODE.js} +1 -1
- package/dashboard/dist/assets/{tabs-C6YkuulG.js → tabs-CSBJRjaH.js} +1 -1
- package/dashboard/dist/assets/{tunnel-api-DDPsBaDV.js → tunnel-api-CdE1F_Ct.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/executors/index.js +3 -2
- package/src/executors/opencode-go.js +46 -39
- package/src/executors/opencode.js +54 -31
- package/src/handlers/chatCore.js +3 -2
- package/src/providers/registry/index.js +5 -4
- package/src/providers/registry/opencode-go.js +16 -22
- package/src/providers/registry/opencode-zen.js +34 -0
- package/src/providers/registry/opencode.js +16 -12
- package/src/routes/api/providers/[id]/models/route.js +28 -0
- package/src/routes/api/providers/[id]/test/testUtils.js +15 -6
- package/src/routes/api/providers/catalog/route.js +3 -1
- package/src/routes/api/providers/suggested-models/filters.js +7 -2
- package/src/routes/api/providers/validate/route.js +14 -11
- package/src/types/provider.ts +1 -1
- package/src/utils/opencode.js +225 -0
- package/dashboard/dist/assets/Login-BeKpipS_.js +0 -1
- package/dashboard/dist/assets/Provider-BU7JfTqm.js +0 -4
- package/dashboard/dist/assets/QuotaMonitor-HzGK7bcc.js +0 -1
- package/dashboard/dist/assets/Usage-eWnrPQ_v.js +0 -4
- package/dashboard/dist/assets/index-B6j-9zHy.js +0 -10
- package/dashboard/dist/assets/index-C-_l0yYz.css +0 -1
- package/dashboard/dist/assets/select-D8pUtMXp.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as t,j as e,k as rs}from"./react-vendor-xnYrwzsL.js";import{u as ve,a as pe}from"./query-vendor-DVevaSVS.js";import{R as C}from"./ripple-button-l8aMiVVG.js";import{F as ue}from"./flip-button-BGgkjtl0.js";import{e as Ue,B as as,D as Z,m as ee,n as se,o as te,s as re,q as Y,t as U,g as J,F as H,a as Ee,E as Ye,y as xe,I as Ae,K as ns,L as is,M as os,N as ls}from"./index-B6j-9zHy.js";import{F as le,a as ce,c as De}from"./frame-cUiti6Lq.js";import{p as Pe}from"./live-mode-CHShLY4E.js";import{c as Me,e as cs,d as ds,f as Se}from"./tunnel-api-DDPsBaDV.js";import{ad as us,ag as je,an as Le,L as ne,a as ye,aA as ms,ax as ps,aB as xs,af as fs,aC as hs,D as gs,aD as bs,aE as ys,aF as vs,aG as js,ay as ws,a8 as Ns,a9 as Ss}from"./icons-vendor-CUx7SB5V.js";import{H as ze}from"./Header-C_9Su9BF.js";import{C as ks}from"./checkbox-7SZBrmbN.js";import{S as ke,a as Ce,b as Re,c as he}from"./select-D8pUtMXp.js";import{S as Cs}from"./skeleton-7uJDiIXe.js";import{T as Rs,a as Ts,b as ge,c as be}from"./tabs-C6YkuulG.js";import{A as Ps,a as Es,b as As,c as Ds}from"./accordion-DOOPDDgt.js";import{s as qe,m as Ls}from"./admin-extras-api-CCdu5TFM.js";import"./ui-vendor-BuM9f2NY.js";import"./motion-vendor-g5fpGzmJ.js";const Fe=2e3,Os=3e5,Is=5e3,Us=5,Ms=1e4,Be=[{key:"provisioning",label:"Prepare cloudflared",description:"Download or reuse the tunnel client."},{key:"connecting",label:"Start tunnel",description:"Create the tunnel and register its route."},{key:"verifying",label:"Verify reachability",description:"Check that the public endpoint responds."}];function zs({open:s,loading:a,state:l,step:x,message:r,error:f,onOpenChange:c}){const k=Be.findIndex(m=>m.key===x),y=l==="ready"?"Cloudflare Tunnel ready":l==="error"?"Tunnel setup needs attention":"Creating Cloudflare Tunnel";return e.jsx(Z,{open:s,onOpenChange:m=>{a||c(m)},children:e.jsxs(ee,{className:"sm:max-w-md",showCloseButton:!a,children:[e.jsxs(se,{children:[e.jsx(te,{children:y}),e.jsx(re,{children:a?"Keep this window open while the tunnel is being prepared.":l==="ready"?"The public endpoint is online and ready to use.":"The tunnel could not finish setup. You can close this dialog and try again."})]}),e.jsxs(H,{className:"space-y-4",children:[e.jsx("div",{className:"space-y-3","aria-live":"polite",children:Be.map((m,i)=>{const v=l==="ready"||i<k,w=l==="error"&&i===k,p=a&&i===k;return e.jsxs("div",{className:"flex gap-3",children:[e.jsx("div",{className:`mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-full border transition-colors duration-150 ${v?"border-success/40 bg-success/12 text-success":w?"border-destructive/40 bg-destructive/12 text-destructive":p?"border-primary/50 bg-primary/12 text-primary":"border-border bg-surface text-muted-foreground"}`,children:v?e.jsx(je,{className:"size-4"}):w?e.jsx(ye,{className:"size-4"}):p?e.jsx(ne,{className:"size-4 animate-spin"}):e.jsx("span",{className:"size-1.5 rounded-full bg-current opacity-60"})}),e.jsxs("div",{className:"min-w-0 pt-0.5",children:[e.jsx("p",{className:"text-sm font-medium",children:m.label}),e.jsx("p",{className:"text-xs text-muted-foreground",children:w?f:p?r:m.description})]})]},m.key)})}),e.jsx("div",{className:`rounded-lg border px-3 py-2 text-xs transition-colors duration-150 ${l==="error"?"border-destructive/25 bg-destructive/8 text-destructive-foreground":l==="ready"?"border-success/25 bg-success/8 text-success":"border-border bg-surface text-muted-foreground"}`,children:l==="error"?f:r})]}),a?null:e.jsx(Y,{children:e.jsx(C,{type:"button",onClick:()=>c(!1),children:l==="ready"?"Done":"Close"})})]})})}function qs({requireApiKey:s,requireLogin:a,hasPassword:l}){const x=ve(),[r,f]=t.useState(!0),[c,k]=t.useState(!1),[y,m]=t.useState(!0),[i,v]=t.useState(!1),[w,p]=t.useState(""),[R,T]=t.useState(""),[E,D]=t.useState(!1),[M,j]=t.useState(""),[b,P]=t.useState(null),[L,B]=t.useState(!1),[G,X]=t.useState(!1),[d,N]=t.useState(!1),[V,z]=t.useState("loading"),[q,h]=t.useState("provisioning"),[A,S]=t.useState(""),[W,o]=t.useState(""),[n,u]=t.useState(!1),[O,K]=t.useState(!1),ae=t.useRef(0),Oe=t.useRef(!1),de=pe({queryKey:["tunnel-status"],queryFn:Se,enabled:Pe(),retry:!1}),we=pe({queryKey:["settings"],queryFn:Ye,enabled:Pe(),retry:!1}),Ie=t.useCallback(g=>{var I,F,_,$;const Q=((I=g.tunnel)==null?void 0:I.settingsEnabled)??((F=g.tunnel)==null?void 0:F.enabled)??!1;p(((_=g.tunnel)==null?void 0:_.tunnelUrl)||""),T((($=g.tunnel)==null?void 0:$.publicUrl)||""),k(Q)},[]);t.useEffect(()=>{if(!de.data){f(!de.isError);return}Ie(de.data),f(!1)},[de.data,de.isError,Ie]),t.useEffect(()=>{var g;((g=we.data)==null?void 0:g.tunnelDashboardAccess)!==void 0&&m(we.data.tunnelDashboardAccess!==!1)},[we.data]),t.useEffect(()=>{if(!c)return;const g=()=>{document.hidden||x.invalidateQueries({queryKey:["tunnel-status"]})};if(document.addEventListener("visibilitychange",g),i)return()=>document.removeEventListener("visibilitychange",g);const Q=setInterval(()=>{document.hidden||x.invalidateQueries({queryKey:["tunnel-status"]})},Is);return()=>{clearInterval(Q),document.removeEventListener("visibilitychange",g)}},[c,i,x]),t.useEffect(()=>{const g=async()=>{if(document.hidden||!c||!w&&!R)return;await Me(R,w)?(ae.current=0,v(!0),Oe.current||(Oe.current=!0,K(!0))):(ae.current+=1,ae.current>=Us&&v(!1))};if(!c||!w&&!R||(g(),i))return;const Q=setInterval(()=>void g(),Ms);return()=>clearInterval(Q)},[c,w,R,i]);const We=async(g,Q)=>{try{return await Ee({[g]:Q}),!0}catch(I){return U.error(J(I,`Failed to update ${g}`)),!1}},He=async g=>{await We("tunnelDashboardAccess",g)&&m(g)},Xe=async(...g)=>{var _;h("verifying"),S("Checking the public endpoint…");const Q=g.filter(Boolean).map($=>$),I=Date.now();for(;Date.now()-I<Os;){if(await new Promise($=>setTimeout($,Fe)),await Me(...Q))return k(!0),v(!0),S("Public endpoint is responding."),!0;if((Date.now()-I)%1e4<Fe)try{if(!((_=(await Se()).tunnel)!=null&&_.enabled)){const $="The tunnel process stopped unexpectedly.";return P({type:"error",message:$}),S($),!1}}catch{}}const F="Tunnel created but the public endpoint is not reachable yet.";return P({type:"error",message:F}),S(F),!1},Ze=async()=>{B(!1),X(!0),D(!0),P(null),z("loading"),h("provisioning"),S("Preparing cloudflared…"),o(""),j("Creating tunnel…");let g=!0;(async()=>{var I;for(;g;){try{const F=await Se();if(!g)return;if((I=F.download)!=null&&I.downloading){const $=`Downloading cloudflared… ${Math.max(0,Math.min(100,F.download.progress||0))}%`;S($),j($)}else S("Creating tunnel…"),j("Creating tunnel…")}catch{}await new Promise(F=>setTimeout(F,1e3))}})();try{const I=await cs();if(g=!1,!I.success){const _=I.error||"Failed to create tunnel.";z("error"),o(_),S(_),P({type:"error",message:_});return}if(h("connecting"),S("Starting the tunnel connection…"),j("Starting tunnel connection…"),!I.tunnelUrl){const _="No tunnel URL was returned.";z("error"),o(_),S(_),P({type:"error",message:_});return}if(p(I.tunnelUrl),T(I.publicUrl||""),!await Xe(I.publicUrl,I.tunnelUrl)){z("error"),o("Tunnel created, but its public endpoint could not be verified.");return}z("ready"),S("Tunnel is online and ready to use.")}catch(I){const F=J(I,"Failed to enable tunnel");z("error"),o(F),S(F),P({type:"error",message:F})}finally{g=!1,D(!1),j("")}},es=async()=>{D(!0),P(null);try{const g=await ds();g.success?(k(!1),p(""),T(""),N(!1),P({type:"success",message:"Tunnel disabled"})):P({type:"error",message:g.error||"Failed to disable tunnel"})}catch(g){P({type:"error",message:J(g,"Failed to disable tunnel")})}finally{D(!1)}},fe=!a||!l,Ne=a?"Set a custom dashboard password first.":'Enable "Require login" and set a custom password first.',ss=r?"Checking tunnel status…":c&&E?M||"Working…":c&&i?"Active":c?O?"Tunnel reconnecting…":"Tunnel checking…":"Tunnel is disabled",ts=async()=>{const g=`${R||w}/v1`;try{await navigator.clipboard.writeText(g),u(!0),window.setTimeout(()=>u(!1),1500)}catch(Q){U.error(J(Q,"Failed to copy tunnel URL"))}};return e.jsxs(e.Fragment,{children:[e.jsxs(le,{children:[e.jsxs(ce,{className:"flex flex-row items-center gap-3 p-4",children:[e.jsx("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg border border-border bg-transparent",children:e.jsx("img",{src:"/providers/cloudflare-ai.svg",alt:"","aria-hidden":"true",width:18,height:18,className:"h-[18px] w-[18px] object-contain"})}),e.jsx("div",{children:e.jsx("p",{className:"text-sm font-medium",children:"Cloudflare Tunnel"})})]}),e.jsxs(De,{className:"space-y-4 p-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-4 rounded-lg border border-border bg-surface px-3 py-2.5",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm font-medium",children:"Tunnel status"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:ss})]}),c&&i?e.jsx("span",{className:"size-2 shrink-0 rounded-full bg-success"}):e.jsx("span",{className:"size-2 shrink-0 rounded-full bg-muted-foreground/50"})]}),c&&(R||w)?e.jsxs("div",{className:"flex items-center gap-2 rounded-lg border border-border bg-surface px-3 py-2.5",children:[e.jsx("code",{className:"min-w-0 flex-1 truncate font-mono text-xs",children:`${R||w}/v1`}),e.jsx(Ue,{label:n?"Copied":"Copy URL",children:e.jsx("button",{type:"button",onClick:()=>void ts(),className:"rounded-md p-1.5 text-muted-foreground transition-[background-color,color,scale] duration-150 ease-out hover:bg-surface-hover hover:text-primary active:scale-[0.96]","aria-label":n?"URL copied":"Copy URL",children:e.jsxs("span",{className:"relative block size-3.5","aria-hidden":"true",children:[e.jsx(us,{className:`absolute inset-0 size-3.5 transition-[opacity,scale,filter] duration-150 ease-out ${n?"scale-25 opacity-0 blur-[4px]":"scale-100 opacity-100 blur-0"}`}),e.jsx(je,{className:`absolute inset-0 size-3.5 text-success transition-[opacity,scale,filter] duration-150 ease-out ${n?"scale-100 opacity-100 blur-0":"scale-25 opacity-0 blur-[4px]"}`})]})})}),e.jsx(Ue,{label:"Disable tunnel",children:e.jsx("button",{type:"button",onClick:()=>N(!0),className:"rounded-md border border-border p-1.5 text-muted-foreground hover:border-destructive/40 hover:bg-destructive/10 hover:text-destructive","aria-label":"Disable tunnel",children:e.jsx(Le,{className:"h-3.5 w-3.5"})})})]}):null,fe&&!c?e.jsxs("div",{className:"flex items-start gap-2 rounded-lg border border-warning/30 bg-warning/5 px-3 py-2.5 text-sm text-warning",children:[e.jsx(ne,{className:"mt-0.5 h-4 w-4 shrink-0"}),e.jsx("p",{children:Ne})]}):null,c&&(!s||fe)?e.jsxs("div",{className:"flex items-start gap-2 rounded-lg border border-warning/30 bg-warning/5 px-3 py-2.5 text-sm text-warning",children:[e.jsx(ne,{className:"mt-0.5 h-4 w-4 shrink-0"}),e.jsx("p",{children:s?Ne:"Require API key is disabled — your endpoint is publicly accessible."})]}):null,b&&b.type!=="success"?e.jsx("p",{className:`text-xs ${b.type==="warning"?"text-warning":"text-destructive"}`,children:b.message}):null,e.jsxs("div",{className:"flex items-center justify-between gap-3 border-t border-border pt-4",children:[e.jsx("p",{className:"text-sm font-medium",children:"Tunnel access"}),c?e.jsx(ue,{active:y,onToggle:()=>void He(!y),activeLabel:"",inactiveLabel:""}):e.jsx(as,{size:"sm",onClick:()=>{if(fe||!s){P({type:"error",message:fe?Ne:'Enable "Require API key" before activating the tunnel.'});return}B(!0)},disabled:E,children:E?e.jsxs(e.Fragment,{children:[e.jsx(ne,{className:"h-4 w-4 animate-spin"}),M||"Working…"]}):"Enable"})]})]})]}),e.jsx(Z,{open:L,onOpenChange:B,children:e.jsxs(ee,{children:[e.jsxs(se,{children:[e.jsx(te,{children:"Enable Tunnel"}),e.jsx(re,{children:"Creates a temporary public URL for this router."})]}),e.jsxs(Y,{children:[e.jsx(C,{onClick:()=>void Ze(),children:"Start Tunnel"}),e.jsx(C,{variant:"outline",onClick:()=>B(!1),children:"Cancel"})]})]})}),e.jsx(zs,{open:G,loading:E,state:V,step:q,message:A,error:W,onOpenChange:X}),e.jsx(Z,{open:d,onOpenChange:g=>!E&&N(g),children:e.jsxs(ee,{children:[e.jsxs(se,{children:[e.jsx(te,{children:"Disable Tunnel"}),e.jsx(re,{children:"This will disconnect the public tunnel."})]}),e.jsxs(Y,{children:[e.jsx(C,{variant:"destructive",onClick:()=>void es(),disabled:E,children:E?"Disabling…":"Disable"}),e.jsx(C,{variant:"outline",onClick:()=>N(!1),disabled:E,children:"Cancel"})]})]})})]})}const _e={providerAccounts:!0,customProviders:!0,customModels:!0,combos:!0,routingSettings:!1,activateAccounts:!1};function Fs(s){return!!s&&typeof s=="object"&&!Array.isArray(s)}function Bs(s){if(!Fs(s))throw new Error("The selected file is not valid JSON data");if(s.product==="swayrouter")throw new Error("This is an Sway Router backup. Use Import JSON instead.");if(!("modelAliases"in s||"mitmAlias"in s||Array.isArray(s.providerConnections)&&Array.isArray(s.providerNodes)&&Array.isArray(s.combos)&&Array.isArray(s.customModels)&&s.formatVersion===void 0&&s.backupScope===void 0))throw new Error("This file is not a supported 9Router backup");return s}async function _s(s){try{return Bs(JSON.parse(await s.text()))}catch(a){throw a instanceof SyntaxError?new Error("The selected file is not valid JSON"):a}}async function Ge(s,a){if(s!=="local"){if(!a)throw new Error("Choose a 9Router JSON backup first");return await _s(a)}}async function Ks(){const{data:s}=await xe.get("/settings/migrate-9router");return s}async function Vs(s){const a=await Ge(s.source,s.file),{data:l}=await xe.post("/settings/migrate-9router",{action:"preview",source:s.source,payload:a,options:s.options});return l.preview}async function Qs(s){const a=await Ge(s.source,s.file),{data:l}=await xe.post("/settings/migrate-9router",{action:"migrate",source:s.source,payload:a,options:s.options,password:s.password});return l}const Ke=[{key:"analyzing",label:"Analyze source",description:"Validate 9Router data and resolve conflicts."},{key:"migrating",label:"Back up and migrate",description:"Create a safety backup, then import the selected data."},{key:"refreshing",label:"Refresh dashboard",description:"Reload providers, models, combos, and settings."},{key:"done",label:"Done",description:"The migrated data is ready to review."}],$s=[{key:"providerAccounts",label:"Provider accounts and credentials",description:"Compatible provider logins, tokens, and API keys."},{key:"customProviders",label:"Custom providers",description:"Compatible OpenAI, Anthropic, and embedding endpoints."},{key:"customModels",label:"Custom models",description:"Models whose provider is available after migration."},{key:"combos",label:"Combos",description:"Combo routes with compatible model references."},{key:"routingSettings",label:"Routing settings",description:"Provider and combo routing behavior. Off by default."},{key:"activateAccounts",label:"Activate imported accounts immediately",description:"Leave off to review accounts before routing traffic."}],Js={providerAccounts:"Provider accounts",customProviders:"Custom providers",customModels:"Custom models",combos:"Combos",routingSettings:"Routing settings"},Ys={ACCOUNT_PROVIDER_UNAVAILABLE:"Some accounts skipped",EMPTY_COMBO:"Some combos skipped",ORPHAN_CUSTOM_MODEL:"Some custom models skipped",UNSUPPORTED_ACCOUNT_PROVIDER:"Some accounts skipped",UNSUPPORTED_CUSTOM_PROVIDER:"Some providers skipped"},Gs=["settings","providers","providers-available","nodes","custom-models","combos"];function ie(s){return s==="previewing"||s==="migrating"}function Ws({open:s,onOpenChange:a}){var A,S,W,o;const l=ve(),x=t.useRef(null),[r,f]=t.useState("local"),[c,k]=t.useState(null),[y,m]=t.useState({..._e}),[i,v]=t.useState("configure"),[w,p]=t.useState(null),[R,T]=t.useState(""),[E,D]=t.useState("analyzing"),[M,j]=t.useState(""),[b,P]=t.useState(""),L=pe({queryKey:["nine-router-detection"],queryFn:Ks,enabled:s,staleTime:3e4});t.useEffect(()=>{if(!s)return;const n=L.data;n&&!n.available&&r==="local"&&f("json")},[L.data,s,r]),t.useEffect(()=>{s||(f("local"),k(null),m({..._e}),v("configure"),p(null),T(""),D("analyzing"),j(""),P(""),x.current&&(x.current.value=""))},[s]);function B(n,u){m(O=>{const K={...O,[n]:u};return n==="customModels"&&u&&(K.customProviders=!0),n==="customProviders"&&!u&&(K.customModels=!1),K})}function G(n){ie(i)||(f(n),p(null),P(""),v("configure"))}const d=(y.providerAccounts||y.customProviders||y.customModels||y.combos||y.routingSettings)&&(r==="local"?((A=L.data)==null?void 0:A.available)===!0:!!c);async function N(){if(!(!d||ie(i))){v("previewing"),D("analyzing"),j("Checking compatibility and resolving conflicts…"),P("");try{const n=await Vs({source:r,file:c,options:y});m(n.options),p(n),j(""),v("preview")}catch(n){const u=J(n,"Could not analyze the 9Router data");P(u),j(u),v("configure"),U.error(u)}}}async function V(){if(!(!w||w.totalReady<1||!R.trim()||ie(i))){v("migrating"),D("migrating"),j("Creating a safety backup and importing selected data…"),P("");try{const n=await Qs({source:r,file:c,options:y,password:R});if(!n.success)throw new Error(n.message||"Migration failed");D("refreshing"),j("Refreshing dashboard data…"),await Promise.all(Gs.map(u=>l.invalidateQueries({queryKey:[u]}))),T(""),D("done"),j(n.message||"9Router data migrated successfully."),v("ready"),U.success(n.message||"Migration complete")}catch(n){const u=J(n,"9Router migration failed");P(u),j(u),v("error"),U.error(u)}}}const z=Ke.findIndex(n=>n.key===E),q=i==="previewing"||i==="migrating"||i==="ready"||i==="error",h=((S=L.data)==null?void 0:S.available)===!0;return e.jsx(Z,{open:s,onOpenChange:n=>{!n&&ie(i)||a(n)},children:e.jsxs(ee,{className:"sm:max-w-2xl",showCloseButton:!ie(i),children:[e.jsxs(se,{children:[e.jsx(te,{children:i==="preview"?"Migration preview":i==="ready"?"Migration complete":i==="error"?"Migration needs attention":"Migrate from 9Router"}),e.jsx(re,{children:i==="configure"?"Choose a source and what you want to bring into Sway Router. Existing Sway Router data stays in place.":i==="preview"?"Review what will be added before making any changes.":i==="ready"?"A safety backup was created before your selected data was imported.":i==="error"?"No partial migration was kept. Review the error and try again.":"Keep this window open while Sway Router checks and migrates the data."})]}),i==="configure"?e.jsxs(e.Fragment,{children:[e.jsxs(H,{className:"space-y-5",children:[e.jsxs("div",{className:"grid gap-2 sm:grid-cols-2",children:[e.jsxs("button",{type:"button","aria-pressed":r==="local",disabled:L.isLoading||!h,onClick:()=>G("local"),className:`flex min-h-20 items-start gap-3 rounded-xl border p-3 text-left transition-colors duration-150 disabled:cursor-not-allowed disabled:opacity-50 ${r==="local"?"border-primary/60 bg-primary/10":"border-border bg-surface hover:bg-muted/60"}`,children:[L.isLoading?e.jsx(ne,{className:"mt-0.5 size-4 shrink-0 animate-spin text-muted-foreground"}):e.jsx(ms,{className:"mt-0.5 size-4 shrink-0"}),e.jsxs("span",{className:"min-w-0",children:[e.jsx("span",{className:"block text-sm font-medium",children:"Local installation"}),e.jsx("span",{className:"mt-0.5 block break-all text-xs text-muted-foreground",children:L.isLoading?"Looking for 9Router…":h?((W=L.data)==null?void 0:W.location)||"9Router database found":(o=L.data)!=null&&o.localOnly?"Only available on the router machine":"No local database found"})]})]}),e.jsxs("button",{type:"button","aria-pressed":r==="json",onClick:()=>G("json"),className:`flex min-h-20 items-start gap-3 rounded-xl border p-3 text-left transition-colors duration-150 ${r==="json"?"border-primary/60 bg-primary/10":"border-border bg-surface hover:bg-muted/60"}`,children:[e.jsx(ps,{className:"mt-0.5 size-4 shrink-0"}),e.jsxs("span",{className:"min-w-0",children:[e.jsx("span",{className:"block text-sm font-medium",children:"9Router JSON backup"}),e.jsx("span",{className:"mt-0.5 block text-xs text-muted-foreground",children:"Use an exported backup from this or another device."})]})]})]}),r==="json"?e.jsxs("div",{className:"flex flex-col gap-2 rounded-lg border border-border bg-surface p-3 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"truncate text-sm font-medium",children:(c==null?void 0:c.name)||"No file selected"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Choose a 9Router JSON export."})]}),e.jsx(C,{size:"sm",variant:"outline",onClick:()=>{var n;return(n=x.current)==null?void 0:n.click()},children:"Choose JSON"}),e.jsx("input",{ref:x,type:"file",accept:".json,application/json",className:"hidden",onChange:n=>{var O;const u=((O=n.target.files)==null?void 0:O[0])||null;k(u),P("")}})]}):null,e.jsx("div",{className:"space-y-2",children:$s.map(n=>{const u=n.key==="customProviders"&&y.customModels;return e.jsxs("label",{className:"flex cursor-pointer items-start gap-3 rounded-lg border border-border/70 p-3 transition-colors duration-150 hover:bg-muted/40",children:[e.jsx(ks,{checked:y[n.key],disabled:u,onCheckedChange:O=>B(n.key,O===!0),"aria-label":n.label}),e.jsxs("span",{className:"min-w-0",children:[e.jsx("span",{className:"block text-sm font-medium",children:n.label}),e.jsx("span",{className:"mt-0.5 block text-xs text-muted-foreground",children:u?"Required while Custom models is selected.":n.description})]})]},n.key)})}),b?e.jsx("p",{className:"rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:b}):null]}),e.jsxs(Y,{children:[e.jsx(C,{variant:"outline",onClick:()=>a(!1),children:"Cancel"}),e.jsx(C,{onClick:()=>void N(),disabled:!d,children:"Preview migration"})]})]}):i==="preview"&&w?e.jsxs(e.Fragment,{children:[e.jsxs(H,{className:"space-y-4",children:[e.jsx("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-3",children:Object.entries(w.sections).map(([n,u])=>e.jsxs("div",{className:"rounded-xl border border-border bg-surface p-3.5",children:[e.jsx("p",{className:"truncate text-xs font-medium text-muted-foreground",children:Js[n]}),e.jsx("p",{className:"mt-2 text-2xl font-semibold tabular-nums tracking-tight",children:u.ready.toLocaleString()}),e.jsx("p",{className:"mt-0.5 text-[11px] text-muted-foreground",children:"ready to import"}),e.jsxs("div",{className:"mt-2 flex min-h-5 flex-wrap gap-1.5 text-[10px]",children:[u.resolved?e.jsxs("span",{className:"rounded-full border border-primary/25 bg-primary/10 px-2 py-0.5 text-primary",children:[u.resolved.toLocaleString()," handled"]}):null,u.duplicates?e.jsxs("span",{className:"rounded-full border border-border bg-muted/50 px-2 py-0.5 text-muted-foreground",children:[u.duplicates.toLocaleString()," already here"]}):null,u.skipped?e.jsxs("span",{className:"rounded-full border border-warning/25 bg-warning/10 px-2 py-0.5 text-warning-foreground",children:[u.skipped.toLocaleString()," skipped"]}):null,!u.resolved&&!u.duplicates&&!u.skipped?e.jsx("span",{className:"text-muted-foreground",children:"All clear"}):null]})]},n))}),w.warnings.length>0?e.jsx("div",{className:"space-y-2 rounded-xl border border-warning/30 bg-warning/10 p-3",children:w.warnings.map(n=>e.jsxs("div",{className:"flex items-start gap-3 rounded-lg border border-warning/20 bg-background/20 p-2.5 text-warning-foreground",children:[e.jsx(ye,{className:"mt-0.5 size-4 shrink-0"}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-x-3 gap-y-1",children:[e.jsx("p",{className:"text-xs font-medium",children:Ys[n.code]||"Import note"}),e.jsxs("span",{className:"text-[10px] font-medium uppercase tracking-wide text-warning-foreground/75",children:[n.count.toLocaleString()," affected"]})]}),e.jsx("p",{className:"mt-0.5 text-xs text-warning-foreground/85",children:n.message})]})]},n.code))}):null,e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"Dashboard password"}),e.jsx(Ae,{type:"password",value:R,onChange:n=>T(n.target.value),autoComplete:"current-password",placeholder:"Enter password to confirm"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Imported accounts stay inactive unless you selected immediate activation. Existing Sway Router data will not be replaced."})]}),e.jsxs(Y,{children:[e.jsx(C,{variant:"outline",onClick:()=>{T(""),v("configure")},children:"Back"}),e.jsxs(C,{onClick:()=>void V(),disabled:!R.trim()||w.totalReady<1,children:["Migrate ",w.totalReady.toLocaleString()," items"]})]})]}):q?e.jsxs(e.Fragment,{children:[e.jsxs(H,{className:"space-y-4",children:[e.jsx("div",{className:"space-y-3","aria-live":"polite",children:Ke.map((n,u)=>{const O=i==="ready"||u<z,K=i==="error"&&u===z,ae=(i==="previewing"||i==="migrating")&&u===z;return e.jsxs("div",{className:"flex gap-3",children:[e.jsx("div",{className:`mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-full border transition-colors duration-150 ${O?"border-success/40 bg-success/12 text-success":K?"border-destructive/40 bg-destructive/12 text-destructive":ae?"border-primary/50 bg-primary/12 text-primary":"border-border bg-surface text-muted-foreground"}`,children:O?e.jsx(je,{className:"size-4"}):K?e.jsx(ye,{className:"size-4"}):ae?e.jsx(ne,{className:"size-4 animate-spin"}):e.jsx("span",{className:"size-1.5 rounded-full bg-current opacity-60"})}),e.jsxs("div",{className:"min-w-0 pt-0.5",children:[e.jsx("p",{className:"text-sm font-medium",children:n.label}),e.jsx("p",{className:"text-xs text-muted-foreground",children:K?b:ae?M:n.description})]})]},n.key)})}),e.jsx("div",{className:`rounded-lg border px-3 py-2 text-xs transition-colors duration-150 ${i==="error"?"border-destructive/25 bg-destructive/8 text-destructive":i==="ready"?"border-success/25 bg-success/8 text-success":"border-border bg-surface text-muted-foreground"}`,children:M})]}),ie(i)?null:e.jsxs(Y,{children:[i==="error"&&w?e.jsx(C,{variant:"outline",onClick:()=>{T(""),v("preview")},children:"Back to preview"}):null,e.jsx(C,{onClick:()=>a(!1),children:i==="ready"?"Done":"Close"})]})]}):null]})})}function Hs(s){if(!s||typeof s!="object"||Array.isArray(s))throw new Error("Invalid JSON backup file");const a=s;if(a.product!=="swayrouter"&&("modelAliases"in a||"mitmAlias"in a||a.formatVersion===void 0&&a.backupScope===void 0&&a.apiKeysRedacted===void 0&&Array.isArray(a.providerConnections)&&Array.isArray(a.providerNodes)))throw new Error("This is a 9Router backup. Use Migrate from 9Router instead.");if(a.formatVersion!==void 0&&a.formatVersion!==1)throw new Error(`Unsupported backup format version: ${a.formatVersion}`);if(a.backupScope!==void 0&&a.backupScope!=="configuration"&&a.backupScope!=="full")throw new Error("Invalid backup scope");if(a.providerCredentialsIncluded!==void 0&&typeof a.providerCredentialsIncluded!="boolean")throw new Error("Invalid provider credential metadata");return a}async function Xs(s,a="configuration"){const{data:l}=await xe.get("/settings/database",{headers:{"x-swayrouter-password":s},params:{scope:a}}),x=new Blob([JSON.stringify(l,null,2)],{type:"application/json;charset=utf-8"}),r=URL.createObjectURL(x),f=document.createElement("a"),c=new Date().toISOString().replace(/[:.]/g,"-");f.href=r,f.download=`sway-router-${a==="full"?"full-data":"configuration"}-backup-${c}.json`,document.body.appendChild(f),f.click(),f.remove(),URL.revokeObjectURL(r)}async function Zs(s,a,l){l==null||l("validating");let x;try{x=Hs(JSON.parse(await s.text()))}catch(f){throw f instanceof SyntaxError?new Error("Backup file is not valid JSON"):f}l==null||l("restoring");const{data:r}=await xe.post("/settings/database",{...x,password:a});return r}const Ve=[{value:"lite",label:"Lite"},{value:"full",label:"Full"},{value:"ultra",label:"Ultra"},{value:"wenyan-lite",label:"Wenyan lite"},{value:"wenyan",label:"Wenyan"},{value:"wenyan-ultra",label:"Wenyan ultra"}],Qe=[{value:"lite",label:"Lite"},{value:"full",label:"Full"},{value:"ultra",label:"Ultra"}],$e=[{key:"validating",label:"Validate file",description:"Check the JSON format and backup metadata."},{key:"restoring",label:"Restore data",description:"Import the backup into Sway Router."},{key:"refreshing",label:"Refresh dashboard",description:"Reload the restored settings and resources."},{key:"done",label:"Done",description:"The backup is ready to use."}];function Je(s,a){var l;return((l=s.find(x=>x.value===a))==null?void 0:l.label)??a}function oe(s,a,l){return Math.min(Math.max(s,a),l)}function et({open:s,imageSrc:a,onOpenChange:l,onApply:x}){const r=t.useRef(null),f=t.useRef(null),c=t.useRef(null),[k,y]=t.useState(320),[m,i]=t.useState({width:0,height:0}),[v,w]=t.useState(1),[p,R]=t.useState({x:0,y:0});t.useEffect(()=>{s&&(w(1),R({x:0,y:0}),i({width:0,height:0}))},[s,a]),t.useEffect(()=>{if(!s||!r.current)return;const d=r.current,N=()=>y(Math.max(1,d.clientWidth));N();const V=new ResizeObserver(N);return V.observe(d),()=>V.disconnect()},[s]);const E=(m.width&&m.height?k/Math.min(m.width,m.height):1)*v,D=m.width*E,M=m.height*E,j=Math.max(0,(D-k)/2),b=Math.max(0,(M-k)/2);t.useEffect(()=>{R(d=>({x:oe(d.x,-j,j),y:oe(d.y,-b,b)}))},[j,b]);function P(d){i({width:d.currentTarget.naturalWidth,height:d.currentTarget.naturalHeight})}function L(d){!m.width||!m.height||(d.currentTarget.setPointerCapture(d.pointerId),c.current={pointerId:d.pointerId,startX:d.clientX,startY:d.clientY,originX:p.x,originY:p.y})}function B(d){const N=c.current;!N||N.pointerId!==d.pointerId||R({x:oe(N.originX+d.clientX-N.startX,-j,j),y:oe(N.originY+d.clientY-N.startY,-b,b)})}function G(d){var N;((N=c.current)==null?void 0:N.pointerId)===d.pointerId&&(c.current=null,d.currentTarget.hasPointerCapture(d.pointerId)&&d.currentTarget.releasePointerCapture(d.pointerId))}function X(){const d=f.current;if(!d||!m.width||!m.height||!E)return;const N=k/E,V=oe(m.width/2-N/2-p.x/E,0,m.width-N),z=oe(m.height/2-N/2-p.y/E,0,m.height-N),q=document.createElement("canvas");q.width=384,q.height=384;const h=q.getContext("2d");if(!h){U.error("Unable to crop profile photo");return}h.imageSmoothingEnabled=!0,h.imageSmoothingQuality="high",h.drawImage(d,V,z,N,N,0,0,q.width,q.height);const A=q.toDataURL("image/jpeg",.86);if(A.length>512*1024){U.error("Cropped profile photo is still too large");return}x(A)}return e.jsx(Z,{open:s,onOpenChange:l,children:e.jsxs(ee,{className:"sm:max-w-md",children:[e.jsx(se,{children:e.jsx(te,{children:"Adjust profile photo"})}),e.jsxs(H,{className:"space-y-4",children:[e.jsxs("div",{ref:r,role:"img","aria-label":"Profile photo crop preview",className:"relative mx-auto aspect-square w-full max-w-[360px] cursor-grab touch-none overflow-hidden rounded-2xl border border-border bg-muted active:cursor-grabbing",onPointerDown:L,onPointerMove:B,onPointerUp:G,onPointerCancel:G,children:[a?e.jsx("img",{ref:f,src:a,alt:"",draggable:!1,onLoad:P,className:"absolute left-1/2 top-1/2 max-w-none select-none",style:{width:D||"100%",height:M||"100%",transform:`translate(-50%, -50%) translate(${p.x}px, ${p.y}px)`}}):null,e.jsx("div",{className:"pointer-events-none absolute inset-0 rounded-2xl ring-1 ring-inset ring-white/15"})]}),e.jsxs("div",{className:"mx-auto w-full max-w-[360px] space-y-2",children:[e.jsxs("div",{className:"grid grid-cols-[minmax(0,1fr)_3rem] items-center gap-3",children:[e.jsxs("div",{className:"flex min-w-0 items-center justify-center gap-2",children:[e.jsx(vs,{className:"size-3.5 shrink-0 text-muted-foreground"}),e.jsx("input",{"aria-label":"Photo zoom",type:"range",min:"1",max:"3",step:"0.01",value:v,onChange:d=>w(Number(d.target.value)),className:"min-w-0 flex-1 accent-primary"}),e.jsx(js,{className:"size-3.5 shrink-0 text-muted-foreground"})]}),e.jsxs("span",{className:"w-12 text-right text-xs tabular-nums text-muted-foreground",children:[Math.round(v*100),"%"]})]}),e.jsx("div",{className:"flex justify-end",children:e.jsxs("button",{type:"button",className:"inline-flex items-center gap-1 rounded-md px-1.5 py-1 text-[11px] text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground",onClick:()=>{w(1),R({x:0,y:0})},children:[e.jsx(ws,{className:"size-3"}),"Reset"]})})]})]}),e.jsxs(Y,{children:[e.jsx(C,{variant:"outline",onClick:()=>l(!1),children:"Cancel"}),e.jsx(C,{onClick:X,disabled:!m.width||!m.height,children:"Use photo"})]})]})})}function Te({label:s,active:a,onToggle:l}){return e.jsxs("div",{className:"flex items-center justify-between gap-4 rounded-xl border border-border bg-card px-4 py-3",children:[e.jsx("div",{className:"min-w-0",children:e.jsx("p",{className:"text-sm font-medium",children:s})}),e.jsx(ue,{active:a,onToggle:l,activeLabel:"",inactiveLabel:""})]})}function me({label:s,value:a,onChange:l,hint:x,autoComplete:r,autoFocus:f}){const[c,k]=t.useState(!1);return e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"text-xs font-medium text-muted-foreground",children:s}),e.jsxs("div",{className:"relative",children:[e.jsx(Ae,{type:c?"text":"password",value:a,onChange:l,autoComplete:r,autoFocus:f,className:"pr-10"}),e.jsx("button",{type:"button","aria-label":c?`Hide ${s.toLowerCase()}`:`Show ${s.toLowerCase()}`,onClick:()=>k(y=>!y),className:"absolute right-2.5 top-1/2 -translate-y-1/2 rounded-md p-1 text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",children:c?e.jsx(Ns,{className:"size-4"}):e.jsx(Ss,{className:"size-4"})})]}),x?e.jsx("span",{className:"block text-[11px] text-muted-foreground/80",children:x}):null]})}function st({open:s,onOpenChange:a,hasPassword:l,onChanged:x}){const[r,f]=t.useState(l?"verify":"new"),[c,k]=t.useState(""),[y,m]=t.useState(""),[i,v]=t.useState(""),[w,p]=t.useState(null),[R,T]=t.useState(!1);t.useEffect(()=>{s&&(f(l?"verify":"new"),k(""),m(""),v(""),p(null),T(!1))},[s,l]);function E(){R||a(!1)}async function D(){if(!c){p("Enter your current password to continue.");return}T(!0),p(null);try{await os(c),f("new")}catch(b){p(J(b,"Unable to verify current password"))}finally{T(!1)}}async function M(){if(y.length<6){p("New password must be at least 6 characters.");return}if(y!==i){p("New password and confirmation do not match.");return}T(!0),p(null);try{await Ee({newPassword:y,...l?{currentPassword:c}:{}}),await x(),a(!1)}catch(b){p(J(b,"Unable to change dashboard password"))}finally{T(!1)}}async function j(b){b.preventDefault(),r==="verify"?await D():await M()}return e.jsx(Z,{open:s,onOpenChange:b=>b?a(!0):E(),children:e.jsx(ee,{className:"sm:max-w-md",children:e.jsxs("form",{onSubmit:j,children:[e.jsxs(se,{children:[e.jsx(te,{children:r==="verify"?"Verify current password":"Set a new dashboard password"}),e.jsx(re,{children:r==="verify"?"Confirm your current password before choosing a replacement.":"Choose a password with at least 6 characters, then confirm it below."})]}),e.jsxs(H,{className:"space-y-4",children:[r==="verify"?e.jsx(me,{label:"Current password",value:c,onChange:b=>k(b.target.value),autoComplete:"current-password",autoFocus:!0}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"rounded-lg border border-success/25 bg-success/8 px-3 py-2 text-xs text-success",children:"Current password verified. You can now set a new one."}),e.jsx(me,{label:"New dashboard password",value:y,onChange:b=>m(b.target.value),hint:"At least 6 characters",autoComplete:"new-password",autoFocus:!0}),e.jsx(me,{label:"Confirm new password",value:i,onChange:b=>v(b.target.value),autoComplete:"new-password"})]}),w?e.jsx("p",{role:"alert",className:"text-xs text-destructive",children:w}):null]}),e.jsxs(Y,{children:[r==="new"&&l?e.jsx(C,{type:"button",variant:"outline",onClick:()=>{f("verify"),p(null)},disabled:R,children:"Back"}):e.jsx(C,{type:"button",variant:"outline",onClick:E,disabled:R,children:"Cancel"}),e.jsx(C,{type:"submit",disabled:R,children:R?r==="verify"?"Checking…":"Updating…":r==="verify"?"Continue":"Change password"})]})]})})})}function tt({open:s,onOpenChange:a,title:l,description:x,busy:r,onConfirm:f}){const[c,k]=t.useState("");t.useEffect(()=>{k("")},[s]);function y(){r||(k(""),a(!1))}async function m(i){i.preventDefault(),!(!c.trim()||r)&&await f(c)}return e.jsx(Z,{open:s,onOpenChange:i=>i?a(!0):y(),children:e.jsx(ee,{className:"sm:max-w-md",children:e.jsxs("form",{onSubmit:m,children:[e.jsxs(se,{children:[e.jsx(te,{children:l}),e.jsx(re,{children:x})]}),e.jsx(H,{children:e.jsx(me,{label:"Dashboard password",value:c,onChange:i=>k(i.target.value),autoComplete:"current-password",autoFocus:!0})}),e.jsxs(Y,{children:[e.jsx(C,{type:"button",variant:"outline",onClick:y,disabled:r,children:"Cancel"}),e.jsx(C,{type:"submit",disabled:r||!c.trim(),children:r?"Working…":"Continue"})]})]})})})}function rt({open:s,onOpenChange:a,busy:l,onConfirm:x}){function r(){l||a(!1)}return e.jsx(Z,{open:s,onOpenChange:f=>f?a(!0):r(),children:e.jsxs(ee,{className:"sm:max-w-md",children:[e.jsxs(se,{children:[e.jsx(te,{children:"Shut down Sway Router?"}),e.jsx(re,{children:"The router will stop accepting new requests and gracefully drain active work before the process exits."})]}),e.jsx(H,{className:"space-y-3",children:e.jsx("div",{className:"rounded-lg border border-destructive/25 bg-destructive/8 px-3 py-2 text-xs text-destructive-foreground",children:"You will need to start the router again from its service manager or terminal. This does not delete settings, providers, or usage data."})}),e.jsxs(Y,{children:[e.jsx(C,{type:"button",variant:"outline",onClick:r,disabled:l,children:"Cancel"}),e.jsxs(C,{type:"button",variant:"destructive",onClick:()=>void x(),disabled:l,children:[e.jsx(Le,{}),l?"Shutting down…":"Shut down router"]})]})]})})}function Nt(){var h,A,S,W;const s=ve(),[a]=rs(),[l,x]=t.useState(()=>{const o=a.get("tab");return o==="preferences"||o==="general"||o==="security"||o==="data"?o:"preferences"}),[r,f]=t.useState(()=>qe({requireApiKey:!0,requireLogin:!0,rtkEnabled:!0,cavemanEnabled:!1,cavemanLevel:"full",ponytailEnabled:!1,ponytailLevel:"full"})),[c,k]=t.useState(!1),[y,m]=t.useState(!1),[i,v]=t.useState(!1),[w,p]=t.useState(!1),[R,T]=t.useState(null),[E,D]=t.useState("idle"),M=t.useRef(r),j=t.useRef(null),b=t.useRef(Promise.resolve()),P=t.useRef(0),L=pe({queryKey:["settings"],queryFn:Ye,enabled:Pe(),retry:!1}),B=pe({queryKey:["settings","database-path"],queryFn:ls,enabled:l==="data",retry:!1});t.useEffect(()=>{if(L.data){const o=qe(L.data);M.current=o,f(o)}},[L.data]),t.useEffect(()=>()=>{j.current&&clearTimeout(j.current)},[]);const G=L.isLoading;function X(o){const n=++P.current;D("saving"),j.current&&clearTimeout(j.current),j.current=setTimeout(()=>{j.current=null,b.current=b.current.catch(()=>{}).then(async()=>{await Ee(o),s.setQueryData(["settings"],u=>u&&{...u,...o}),Object.prototype.hasOwnProperty.call(o,"currency")&&await s.invalidateQueries({queryKey:["currency-settings"]}),n===P.current&&D("saved")}).catch(u=>{n===P.current&&(D("error"),U.error(J(u,"Automatic save failed")))})},300)}function d(o,n){const u=o==="profileName"&&typeof n=="string"?n.trim().replace(/\s+/g," ").slice(0,40)||"Sway Router":n,O={...M.current,[o]:u};M.current=O,f(O),X(o==="profileName"||o==="profileAvatar"||o==="currency"?{[o]:u}:Ls(O))}function N(o){var K;const n=(K=o.target.files)==null?void 0:K[0];if(o.target.value="",!n)return;if(!new Set(["image/png","image/jpeg","image/webp","image/gif"]).has(n.type)){U.error("Profile photo must be PNG, JPG, WEBP, or GIF");return}if(n.size>2*1024*1024){U.error("Profile photo must be 2 MB or smaller");return}const O=new FileReader;O.onload=()=>{typeof O.result=="string"&&(T(O.result),p(!0))},O.onerror=()=>U.error("Unable to read profile photo"),O.readAsDataURL(n)}function V(o){p(o),o||T(null)}function z(o){d("profileAvatar",o),p(!1),T(null)}async function q(){v(!0);try{const o=await ns();if(o.success===!1)throw new Error(o.message||"Shutdown request was rejected");m(!1),U.success("Shutdown initiated. The router is draining active requests.")}catch(o){U.error(J(o,"Shutdown failed")),v(!1)}}return G?e.jsxs("div",{className:"space-y-4",children:[e.jsx(ze,{title:"Settings"}),e.jsx(Cs,{className:"h-64 w-full"})]}):e.jsxs("div",{className:"space-y-4",children:[e.jsx(ze,{title:"Settings"}),e.jsxs(Rs,{value:l,className:"gap-2",onValueChange:o=>x(o),children:[e.jsxs("div",{className:"flex min-h-8 flex-wrap items-center justify-between gap-2",children:[e.jsxs(Ts,{className:"w-fit max-w-full justify-start overflow-x-auto",children:[e.jsx(ge,{value:"preferences",children:"Preferences"}),e.jsx(ge,{value:"general",children:"General"}),e.jsx(ge,{value:"security",children:"Security"}),e.jsx(ge,{value:"data",children:"Data"})]}),e.jsx("div",{className:"min-h-4 text-right text-xs text-muted-foreground","aria-live":"polite",children:E==="saving"?"Saving changes…":E==="saved"?"All changes saved":E==="error"?e.jsx("span",{className:"text-destructive",children:"Automatic save failed"}):null})]}),e.jsxs(be,{value:"general",className:"space-y-3",children:[e.jsxs("div",{className:"space-y-2 pt-1",children:[e.jsx("p",{className:"text-xs font-medium text-muted-foreground",children:"Token saver"}),e.jsx(Te,{label:"RTK",active:r.rtkEnabled,onToggle:()=>d("rtkEnabled",!r.rtkEnabled)}),e.jsxs("div",{className:"rounded-xl border border-border bg-card px-4 py-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsx("div",{className:"min-w-0",children:e.jsx("p",{className:"text-sm font-medium",children:"Caveman"})}),e.jsx(ue,{active:r.cavemanEnabled,onToggle:()=>d("cavemanEnabled",!r.cavemanEnabled),activeLabel:"",inactiveLabel:""})]}),e.jsx("div",{className:"mt-3",children:e.jsxs(ke,{value:r.cavemanLevel,onValueChange:o=>d("cavemanLevel",o??"full"),disabled:!r.cavemanEnabled,children:[e.jsx(Ce,{size:"sm",className:"w-full sm:w-44",children:e.jsx("span",{className:"truncate",children:Je(Ve,r.cavemanLevel)})}),e.jsx(Re,{children:Ve.map(o=>e.jsx(he,{value:o.value,children:o.label},o.value))})]})})]}),e.jsxs("div",{className:"rounded-xl border border-border bg-card px-4 py-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsx("div",{className:"min-w-0",children:e.jsx("p",{className:"text-sm font-medium",children:"Ponytail"})}),e.jsx(ue,{active:r.ponytailEnabled,onToggle:()=>d("ponytailEnabled",!r.ponytailEnabled),activeLabel:"",inactiveLabel:""})]}),e.jsx("div",{className:"mt-3",children:e.jsxs(ke,{value:r.ponytailLevel,onValueChange:o=>d("ponytailLevel",o??"full"),disabled:!r.ponytailEnabled,children:[e.jsx(Ce,{size:"sm",className:"w-full sm:w-44",children:e.jsx("span",{className:"truncate",children:Je(Qe,r.ponytailLevel)})}),e.jsx(Re,{children:Qe.map(o=>e.jsx(he,{value:o.value,children:o.label},o.value))})]})})]})]}),e.jsxs("div",{className:"space-y-3 border-t border-border/70 pt-3",children:[e.jsx("p",{className:"text-xs font-medium text-muted-foreground",children:"Advanced"}),e.jsx(Ps,{className:"rounded-xl border border-border bg-card px-4",children:e.jsxs(Es,{value:"payload-capture",className:"border-0",children:[e.jsxs("div",{className:"flex items-center justify-between gap-4 py-3",children:[e.jsx("p",{className:"text-sm font-medium",children:"Capture full request payloads"}),e.jsx(ue,{active:r.payloadCaptureEnabled,onToggle:()=>d("payloadCaptureEnabled",!r.payloadCaptureEnabled),activeLabel:"",inactiveLabel:""})]}),e.jsx(As,{className:"w-fit flex-none justify-start gap-1 py-2 text-xs text-muted-foreground",children:"Details"}),e.jsx(Ds,{className:"pb-3",children:e.jsx("div",{className:"rounded-lg border border-warning/30 bg-warning/10 px-3 py-2 text-xs text-warning-foreground",children:"Payloads may include API keys, cookies, prompts, and provider responses. Applies to new request details."})})]})}),e.jsx(qs,{requireApiKey:r.requireApiKey,requireLogin:r.requireLogin,hasPassword:!!((h=L.data)!=null&&h.hasPassword)})]})]}),e.jsx(be,{value:"preferences",className:"space-y-4",children:e.jsxs(le,{children:[e.jsx(ce,{className:"p-4",children:e.jsx("p",{className:"text-sm font-medium",children:"Profile & display"})}),e.jsxs(De,{className:"space-y-5 p-4",children:[e.jsxs("div",{className:"flex flex-col gap-4 sm:flex-row sm:items-center",children:[e.jsx("img",{src:r.profileAvatar||"/logo/avatar.svg",alt:"Profile preview",className:"size-16 shrink-0 rounded-2xl border border-border bg-muted object-cover"}),e.jsxs("div",{className:"min-w-0 space-y-2",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:"Profile photo"}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground",children:"PNG, JPG, WEBP, or GIF — max 2 MB."})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("label",{htmlFor:"profile-photo-upload",className:"inline-flex h-8 cursor-pointer items-center gap-1.5 rounded-lg border border-input bg-popover px-2.5 text-sm font-medium text-foreground transition-colors hover:bg-accent/50",children:[e.jsx(xs,{className:"size-3.5"}),"Choose photo"]}),e.jsx("input",{id:"profile-photo-upload",type:"file",accept:"image/png,image/jpeg,image/webp,image/gif",className:"sr-only",onChange:N}),r.profileAvatar?e.jsxs(C,{size:"sm",variant:"ghost",onClick:()=>d("profileAvatar",""),children:[e.jsx(fs,{className:"size-3.5"}),"Delete"]}):null]})]})]}),e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"text-xs font-medium text-muted-foreground",children:"Profile name"}),e.jsx(Ae,{value:r.profileName,onChange:o=>d("profileName",o.target.value),maxLength:40,placeholder:"Sway Router"}),e.jsx("span",{className:"block text-[11px] text-muted-foreground/80",children:"Shown in the sidebar account card."})]}),e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"block text-xs font-medium text-muted-foreground",children:"Cost currency"}),e.jsxs(ke,{value:r.currency,onValueChange:o=>d("currency",o==="IDR"?"IDR":"USD"),children:[e.jsx(Ce,{size:"sm",className:"w-full sm:w-56",children:e.jsx("span",{className:"truncate",children:r.currency==="IDR"?"IDR · Indonesian Rupiah":"USD · US Dollar"})}),e.jsxs(Re,{children:[e.jsx(he,{value:"USD",children:"USD · US Dollar"}),e.jsx(he,{value:"IDR",children:"IDR · Indonesian Rupiah"})]})]})]})]})]})}),e.jsxs(be,{value:"security",className:"space-y-4",children:[e.jsx(Te,{label:"Require API key",active:r.requireApiKey,onToggle:()=>d("requireApiKey",!r.requireApiKey)}),e.jsx(Te,{label:"Require dashboard auth",active:r.requireLogin,onToggle:()=>d("requireLogin",!r.requireLogin)}),e.jsxs("div",{className:"flex items-center justify-between gap-4 rounded-xl border border-border bg-card px-4 py-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm font-medium",children:"Dashboard password"}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground",children:(A=L.data)!=null&&A.hasPassword?"Password is set. Verify it before replacing it.":"No custom password is set yet."})]}),e.jsx(C,{size:"sm",variant:"outline",onClick:()=>k(!0),children:(S=L.data)!=null&&S.hasPassword?"Change password":"Set password"})]}),e.jsx(st,{open:c,onOpenChange:k,hasPassword:!!((W=L.data)!=null&&W.hasPassword),onChanged:async()=>{await s.invalidateQueries({queryKey:["settings"]}),U.success("Dashboard password changed")}}),e.jsx("div",{className:"rounded-xl border border-destructive/30 bg-destructive/[0.04] px-4 py-3",children:e.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm font-medium",children:"Danger zone"}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground",children:"Stop the router gracefully. Active requests can finish before the process exits."})]}),e.jsxs(C,{size:"sm",variant:"destructive-outline",onClick:()=>m(!0),disabled:i,children:[e.jsx(Le,{}),"Shutdown router"]})]})}),e.jsx(rt,{open:y,onOpenChange:m,busy:i,onConfirm:q})]}),e.jsx(be,{value:"data",className:"space-y-4",children:e.jsx(at,{dbPath:B.data,loading:B.isLoading})})]}),e.jsx(et,{open:w,imageSrc:R||"",onOpenChange:V,onApply:z})]})}function at({dbPath:s,loading:a}){const l=ve(),x=t.useRef(null),[r,f]=t.useState(!1),[c,k]=t.useState(null),[y,m]=t.useState(""),[i,v]=t.useState("idle"),[w,p]=t.useState("validating"),[R,T]=t.useState(""),[E,D]=t.useState(""),[M,j]=t.useState(!1),[b,P]=t.useState(!1),[L,B]=t.useState(!1),G=a?"Loading…":s?is(s):"Unavailable";function X(){j(!0)}async function d(h){P(!0);try{await Xs(h,"full"),U.success("Backup downloaded"),j(!1)}catch(A){U.error(J(A,"Download failed"))}finally{P(!1)}}function N(){r||(k(null),m(""),v("idle"),p("validating"),T(""),D(""),x.current&&(x.current.value=""))}function V(h){if(!h.name.toLowerCase().endsWith(".json")){U.error("Please select a .json backup file"),x.current&&(x.current.value="");return}m(""),v("idle"),p("validating"),T(""),D(""),k(h)}async function z(){const h=c;if(!(!h||!y.trim()||r)){f(!0),v("loading"),p("validating"),T("Checking the backup file…"),D("");try{const A=await Zs(h,y,S=>{p(S),T(S==="validating"?"Checking the backup file…":"Restoring data from the backup…")});if(!A.success)throw new Error(A.message||"Restore failed");p("refreshing"),T("Refreshing dashboard data…"),await Promise.all([l.invalidateQueries({queryKey:["settings"]}),l.invalidateQueries({queryKey:["keys"]}),l.invalidateQueries({queryKey:["providers"]}),l.invalidateQueries({queryKey:["providers-available"]}),l.invalidateQueries({queryKey:["nodes"]}),l.invalidateQueries({queryKey:["custom-models"]}),l.invalidateQueries({queryKey:["combos"]})]),p("done"),T(A.message||"Backup restored successfully."),v("ready"),U.success(A.message||"Backup restored")}catch(A){const S=J(A,"Restore failed");v("error"),D(S),T(S),U.error(S)}finally{f(!1)}}}const q=$e.findIndex(h=>h.key===w);return e.jsxs("div",{className:"space-y-4",children:[e.jsxs(le,{children:[e.jsxs(ce,{className:"flex flex-row items-center gap-3 p-4 pb-3",children:[e.jsx("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg border border-border bg-transparent",children:e.jsx(hs,{className:"h-4 w-4 text-white"})}),e.jsx("div",{children:e.jsx("p",{className:"text-sm font-medium",children:"Database Location"})})]}),e.jsx(De,{className:"p-4",children:e.jsx("code",{className:"block break-all rounded-md bg-surface px-3 py-1.5 font-mono text-xs text-muted-foreground",children:G})})]}),e.jsx(le,{children:e.jsxs(ce,{className:"flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx("div",{className:"min-w-0",children:e.jsx("p",{className:"text-sm font-medium",children:"Export JSON"})}),e.jsxs(C,{size:"sm",variant:"outline",onClick:X,disabled:b,className:"shrink-0 self-start sm:self-auto",children:[e.jsx(gs,{className:"h-4 w-4"}),b?"Exporting…":"Export JSON"]})]})}),e.jsx(le,{children:e.jsxs(ce,{className:"flex flex-row items-center justify-between gap-3 p-4",children:[e.jsx("div",{children:e.jsx("p",{className:"text-sm font-medium",children:"Restore from Backup"})}),e.jsxs(C,{size:"sm",variant:"outline",onClick:()=>{var h;return(h=x.current)==null?void 0:h.click()},disabled:r,children:[e.jsx(bs,{className:"h-4 w-4"}),r?"Restoring…":"Import JSON"]}),e.jsx("input",{ref:x,type:"file",accept:".json,application/json",className:"hidden",onChange:h=>{var S;const A=(S=h.target.files)==null?void 0:S[0];A&&V(A)}})]})}),e.jsx(le,{children:e.jsxs(ce,{className:"flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm font-medium",children:"Migrate from 9Router"}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground",children:"Preview and merge compatible accounts, providers, models, combos, and routing settings."})]}),e.jsxs(C,{size:"sm",variant:"outline",onClick:()=>B(!0),className:"shrink-0 self-start sm:self-auto",children:[e.jsx(ys,{className:"h-4 w-4"}),"Start migration"]})]})}),e.jsx(Z,{open:!!c,onOpenChange:h=>{h||N()},children:e.jsxs(ee,{className:"sm:max-w-md",showCloseButton:!r,children:[e.jsxs(se,{children:[e.jsx(te,{children:i==="idle"?"Restore backup?":i==="ready"?"Backup restored":i==="error"?"Restore needs attention":"Restoring backup"}),e.jsx(re,{children:i==="idle"?e.jsxs(e.Fragment,{children:["Restore ",e.jsx("span",{className:"font-medium text-foreground",children:c==null?void 0:c.name})," and replace the current data? This full backup includes provider credentials, configuration, usage history, daily totals, and request details. Redacted gateway API keys will be preserved."]}):r?"Keep this window open while the backup is being restored.":i==="ready"?"Your restored data is loaded and ready to use.":"The backup could not be restored. Close this dialog and try again."})]}),i==="idle"?e.jsxs(e.Fragment,{children:[e.jsx(H,{children:e.jsx(me,{label:"Dashboard password",value:y,onChange:h=>m(h.target.value),autoComplete:"current-password",autoFocus:!0})}),e.jsxs(Y,{children:[e.jsx(C,{variant:"outline",onClick:N,children:"Cancel"}),e.jsx(C,{variant:"destructive",onClick:()=>void z(),disabled:!y.trim(),children:"Restore"})]})]}):e.jsxs(e.Fragment,{children:[e.jsxs(H,{className:"space-y-4",children:[e.jsx("div",{className:"space-y-3","aria-live":"polite",children:$e.map((h,A)=>{const S=i==="ready"||A<q,W=i==="error"&&A===q,o=i==="loading"&&A===q;return e.jsxs("div",{className:"flex gap-3",children:[e.jsx("div",{className:`mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-full border transition-colors duration-150 ${S?"border-success/40 bg-success/12 text-success":W?"border-destructive/40 bg-destructive/12 text-destructive":o?"border-primary/50 bg-primary/12 text-primary":"border-border bg-surface text-muted-foreground"}`,children:S?e.jsx(je,{className:"size-4"}):W?e.jsx(ye,{className:"size-4"}):o?e.jsx(ne,{className:"size-4 animate-spin"}):e.jsx("span",{className:"size-1.5 rounded-full bg-current opacity-60"})}),e.jsxs("div",{className:"min-w-0 pt-0.5",children:[e.jsx("p",{className:"text-sm font-medium",children:h.label}),e.jsx("p",{className:"text-xs text-muted-foreground",children:W?E:o?R:h.description})]})]},h.key)})}),e.jsx("div",{className:`rounded-lg border px-3 py-2 text-xs transition-colors duration-150 ${i==="error"?"border-destructive/25 bg-destructive/8 text-destructive-foreground":i==="ready"?"border-success/25 bg-success/8 text-success":"border-border bg-surface text-muted-foreground"}`,children:R})]}),r?null:e.jsx(Y,{children:e.jsx(C,{onClick:N,children:i==="ready"?"Done":"Close"})})]})]})}),e.jsx(tt,{open:M,onOpenChange:j,title:"Export JSON",description:"Enter your dashboard password. This file includes provider credentials, usage history, and captured request details. Store it securely.",busy:b,onConfirm:d}),e.jsx(Ws,{open:L,onOpenChange:B})]})}export{Nt as default};
|
|
1
|
+
import{r as t,j as e,k as rs}from"./react-vendor-xnYrwzsL.js";import{u as ve,a as pe}from"./query-vendor-DVevaSVS.js";import{R as C}from"./ripple-button-BV_KcZ7W.js";import{F as ue}from"./flip-button-C_PNv8Iq.js";import{e as Ue,B as as,D as Z,m as ee,n as se,o as te,s as re,q as Y,t as U,g as J,F as H,a as Ee,E as Ye,y as xe,I as Ae,K as ns,L as is,M as os,N as ls}from"./index-x5tLD3Ye.js";import{F as le,a as ce,c as De}from"./frame-BLwA8c3u.js";import{p as Pe}from"./live-mode-CHShLY4E.js";import{c as Me,e as cs,d as ds,f as Se}from"./tunnel-api-CdE1F_Ct.js";import{ad as us,ag as je,an as Le,L as ne,a as ye,aA as ms,ax as ps,aB as xs,af as fs,aC as hs,D as gs,aD as bs,aE as ys,aF as vs,aG as js,ay as ws,a8 as Ns,a9 as Ss}from"./icons-vendor-CUx7SB5V.js";import{H as ze}from"./Header-9KXz4S67.js";import{C as ks}from"./checkbox-DU_0LpXJ.js";import{S as ke,a as Ce,b as Re,c as he}from"./select-DELc8FMO.js";import{S as Cs}from"./skeleton-CFSSp0e0.js";import{T as Rs,a as Ts,b as ge,c as be}from"./tabs-CSBJRjaH.js";import{A as Ps,a as Es,b as As,c as Ds}from"./accordion-BkSdf_dl.js";import{s as qe,m as Ls}from"./admin-extras-api-ppLkXcD9.js";import"./ui-vendor-BuM9f2NY.js";import"./motion-vendor-g5fpGzmJ.js";const Fe=2e3,Os=3e5,Is=5e3,Us=5,Ms=1e4,Be=[{key:"provisioning",label:"Prepare cloudflared",description:"Download or reuse the tunnel client."},{key:"connecting",label:"Start tunnel",description:"Create the tunnel and register its route."},{key:"verifying",label:"Verify reachability",description:"Check that the public endpoint responds."}];function zs({open:s,loading:a,state:l,step:x,message:r,error:f,onOpenChange:c}){const k=Be.findIndex(m=>m.key===x),y=l==="ready"?"Cloudflare Tunnel ready":l==="error"?"Tunnel setup needs attention":"Creating Cloudflare Tunnel";return e.jsx(Z,{open:s,onOpenChange:m=>{a||c(m)},children:e.jsxs(ee,{className:"sm:max-w-md",showCloseButton:!a,children:[e.jsxs(se,{children:[e.jsx(te,{children:y}),e.jsx(re,{children:a?"Keep this window open while the tunnel is being prepared.":l==="ready"?"The public endpoint is online and ready to use.":"The tunnel could not finish setup. You can close this dialog and try again."})]}),e.jsxs(H,{className:"space-y-4",children:[e.jsx("div",{className:"space-y-3","aria-live":"polite",children:Be.map((m,i)=>{const v=l==="ready"||i<k,w=l==="error"&&i===k,p=a&&i===k;return e.jsxs("div",{className:"flex gap-3",children:[e.jsx("div",{className:`mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-full border transition-colors duration-150 ${v?"border-success/40 bg-success/12 text-success":w?"border-destructive/40 bg-destructive/12 text-destructive":p?"border-primary/50 bg-primary/12 text-primary":"border-border bg-surface text-muted-foreground"}`,children:v?e.jsx(je,{className:"size-4"}):w?e.jsx(ye,{className:"size-4"}):p?e.jsx(ne,{className:"size-4 animate-spin"}):e.jsx("span",{className:"size-1.5 rounded-full bg-current opacity-60"})}),e.jsxs("div",{className:"min-w-0 pt-0.5",children:[e.jsx("p",{className:"text-sm font-medium",children:m.label}),e.jsx("p",{className:"text-xs text-muted-foreground",children:w?f:p?r:m.description})]})]},m.key)})}),e.jsx("div",{className:`rounded-lg border px-3 py-2 text-xs transition-colors duration-150 ${l==="error"?"border-destructive/25 bg-destructive/8 text-destructive-foreground":l==="ready"?"border-success/25 bg-success/8 text-success":"border-border bg-surface text-muted-foreground"}`,children:l==="error"?f:r})]}),a?null:e.jsx(Y,{children:e.jsx(C,{type:"button",onClick:()=>c(!1),children:l==="ready"?"Done":"Close"})})]})})}function qs({requireApiKey:s,requireLogin:a,hasPassword:l}){const x=ve(),[r,f]=t.useState(!0),[c,k]=t.useState(!1),[y,m]=t.useState(!0),[i,v]=t.useState(!1),[w,p]=t.useState(""),[R,T]=t.useState(""),[E,D]=t.useState(!1),[M,j]=t.useState(""),[b,P]=t.useState(null),[L,B]=t.useState(!1),[G,X]=t.useState(!1),[d,N]=t.useState(!1),[V,z]=t.useState("loading"),[q,h]=t.useState("provisioning"),[A,S]=t.useState(""),[W,o]=t.useState(""),[n,u]=t.useState(!1),[O,K]=t.useState(!1),ae=t.useRef(0),Oe=t.useRef(!1),de=pe({queryKey:["tunnel-status"],queryFn:Se,enabled:Pe(),retry:!1}),we=pe({queryKey:["settings"],queryFn:Ye,enabled:Pe(),retry:!1}),Ie=t.useCallback(g=>{var I,F,_,$;const Q=((I=g.tunnel)==null?void 0:I.settingsEnabled)??((F=g.tunnel)==null?void 0:F.enabled)??!1;p(((_=g.tunnel)==null?void 0:_.tunnelUrl)||""),T((($=g.tunnel)==null?void 0:$.publicUrl)||""),k(Q)},[]);t.useEffect(()=>{if(!de.data){f(!de.isError);return}Ie(de.data),f(!1)},[de.data,de.isError,Ie]),t.useEffect(()=>{var g;((g=we.data)==null?void 0:g.tunnelDashboardAccess)!==void 0&&m(we.data.tunnelDashboardAccess!==!1)},[we.data]),t.useEffect(()=>{if(!c)return;const g=()=>{document.hidden||x.invalidateQueries({queryKey:["tunnel-status"]})};if(document.addEventListener("visibilitychange",g),i)return()=>document.removeEventListener("visibilitychange",g);const Q=setInterval(()=>{document.hidden||x.invalidateQueries({queryKey:["tunnel-status"]})},Is);return()=>{clearInterval(Q),document.removeEventListener("visibilitychange",g)}},[c,i,x]),t.useEffect(()=>{const g=async()=>{if(document.hidden||!c||!w&&!R)return;await Me(R,w)?(ae.current=0,v(!0),Oe.current||(Oe.current=!0,K(!0))):(ae.current+=1,ae.current>=Us&&v(!1))};if(!c||!w&&!R||(g(),i))return;const Q=setInterval(()=>void g(),Ms);return()=>clearInterval(Q)},[c,w,R,i]);const We=async(g,Q)=>{try{return await Ee({[g]:Q}),!0}catch(I){return U.error(J(I,`Failed to update ${g}`)),!1}},He=async g=>{await We("tunnelDashboardAccess",g)&&m(g)},Xe=async(...g)=>{var _;h("verifying"),S("Checking the public endpoint…");const Q=g.filter(Boolean).map($=>$),I=Date.now();for(;Date.now()-I<Os;){if(await new Promise($=>setTimeout($,Fe)),await Me(...Q))return k(!0),v(!0),S("Public endpoint is responding."),!0;if((Date.now()-I)%1e4<Fe)try{if(!((_=(await Se()).tunnel)!=null&&_.enabled)){const $="The tunnel process stopped unexpectedly.";return P({type:"error",message:$}),S($),!1}}catch{}}const F="Tunnel created but the public endpoint is not reachable yet.";return P({type:"error",message:F}),S(F),!1},Ze=async()=>{B(!1),X(!0),D(!0),P(null),z("loading"),h("provisioning"),S("Preparing cloudflared…"),o(""),j("Creating tunnel…");let g=!0;(async()=>{var I;for(;g;){try{const F=await Se();if(!g)return;if((I=F.download)!=null&&I.downloading){const $=`Downloading cloudflared… ${Math.max(0,Math.min(100,F.download.progress||0))}%`;S($),j($)}else S("Creating tunnel…"),j("Creating tunnel…")}catch{}await new Promise(F=>setTimeout(F,1e3))}})();try{const I=await cs();if(g=!1,!I.success){const _=I.error||"Failed to create tunnel.";z("error"),o(_),S(_),P({type:"error",message:_});return}if(h("connecting"),S("Starting the tunnel connection…"),j("Starting tunnel connection…"),!I.tunnelUrl){const _="No tunnel URL was returned.";z("error"),o(_),S(_),P({type:"error",message:_});return}if(p(I.tunnelUrl),T(I.publicUrl||""),!await Xe(I.publicUrl,I.tunnelUrl)){z("error"),o("Tunnel created, but its public endpoint could not be verified.");return}z("ready"),S("Tunnel is online and ready to use.")}catch(I){const F=J(I,"Failed to enable tunnel");z("error"),o(F),S(F),P({type:"error",message:F})}finally{g=!1,D(!1),j("")}},es=async()=>{D(!0),P(null);try{const g=await ds();g.success?(k(!1),p(""),T(""),N(!1),P({type:"success",message:"Tunnel disabled"})):P({type:"error",message:g.error||"Failed to disable tunnel"})}catch(g){P({type:"error",message:J(g,"Failed to disable tunnel")})}finally{D(!1)}},fe=!a||!l,Ne=a?"Set a custom dashboard password first.":'Enable "Require login" and set a custom password first.',ss=r?"Checking tunnel status…":c&&E?M||"Working…":c&&i?"Active":c?O?"Tunnel reconnecting…":"Tunnel checking…":"Tunnel is disabled",ts=async()=>{const g=`${R||w}/v1`;try{await navigator.clipboard.writeText(g),u(!0),window.setTimeout(()=>u(!1),1500)}catch(Q){U.error(J(Q,"Failed to copy tunnel URL"))}};return e.jsxs(e.Fragment,{children:[e.jsxs(le,{children:[e.jsxs(ce,{className:"flex flex-row items-center gap-3 p-4",children:[e.jsx("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg border border-border bg-transparent",children:e.jsx("img",{src:"/providers/cloudflare-ai.svg",alt:"","aria-hidden":"true",width:18,height:18,className:"h-[18px] w-[18px] object-contain"})}),e.jsx("div",{children:e.jsx("p",{className:"text-sm font-medium",children:"Cloudflare Tunnel"})})]}),e.jsxs(De,{className:"space-y-4 p-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-4 rounded-lg border border-border bg-surface px-3 py-2.5",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm font-medium",children:"Tunnel status"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:ss})]}),c&&i?e.jsx("span",{className:"size-2 shrink-0 rounded-full bg-success"}):e.jsx("span",{className:"size-2 shrink-0 rounded-full bg-muted-foreground/50"})]}),c&&(R||w)?e.jsxs("div",{className:"flex items-center gap-2 rounded-lg border border-border bg-surface px-3 py-2.5",children:[e.jsx("code",{className:"min-w-0 flex-1 truncate font-mono text-xs",children:`${R||w}/v1`}),e.jsx(Ue,{label:n?"Copied":"Copy URL",children:e.jsx("button",{type:"button",onClick:()=>void ts(),className:"rounded-md p-1.5 text-muted-foreground transition-[background-color,color,scale] duration-150 ease-out hover:bg-surface-hover hover:text-primary active:scale-[0.96]","aria-label":n?"URL copied":"Copy URL",children:e.jsxs("span",{className:"relative block size-3.5","aria-hidden":"true",children:[e.jsx(us,{className:`absolute inset-0 size-3.5 transition-[opacity,scale,filter] duration-150 ease-out ${n?"scale-25 opacity-0 blur-[4px]":"scale-100 opacity-100 blur-0"}`}),e.jsx(je,{className:`absolute inset-0 size-3.5 text-success transition-[opacity,scale,filter] duration-150 ease-out ${n?"scale-100 opacity-100 blur-0":"scale-25 opacity-0 blur-[4px]"}`})]})})}),e.jsx(Ue,{label:"Disable tunnel",children:e.jsx("button",{type:"button",onClick:()=>N(!0),className:"rounded-md border border-border p-1.5 text-muted-foreground hover:border-destructive/40 hover:bg-destructive/10 hover:text-destructive","aria-label":"Disable tunnel",children:e.jsx(Le,{className:"h-3.5 w-3.5"})})})]}):null,fe&&!c?e.jsxs("div",{className:"flex items-start gap-2 rounded-lg border border-warning/30 bg-warning/5 px-3 py-2.5 text-sm text-warning",children:[e.jsx(ne,{className:"mt-0.5 h-4 w-4 shrink-0"}),e.jsx("p",{children:Ne})]}):null,c&&(!s||fe)?e.jsxs("div",{className:"flex items-start gap-2 rounded-lg border border-warning/30 bg-warning/5 px-3 py-2.5 text-sm text-warning",children:[e.jsx(ne,{className:"mt-0.5 h-4 w-4 shrink-0"}),e.jsx("p",{children:s?Ne:"Require API key is disabled — your endpoint is publicly accessible."})]}):null,b&&b.type!=="success"?e.jsx("p",{className:`text-xs ${b.type==="warning"?"text-warning":"text-destructive"}`,children:b.message}):null,e.jsxs("div",{className:"flex items-center justify-between gap-3 border-t border-border pt-4",children:[e.jsx("p",{className:"text-sm font-medium",children:"Tunnel access"}),c?e.jsx(ue,{active:y,onToggle:()=>void He(!y),activeLabel:"",inactiveLabel:""}):e.jsx(as,{size:"sm",onClick:()=>{if(fe||!s){P({type:"error",message:fe?Ne:'Enable "Require API key" before activating the tunnel.'});return}B(!0)},disabled:E,children:E?e.jsxs(e.Fragment,{children:[e.jsx(ne,{className:"h-4 w-4 animate-spin"}),M||"Working…"]}):"Enable"})]})]})]}),e.jsx(Z,{open:L,onOpenChange:B,children:e.jsxs(ee,{children:[e.jsxs(se,{children:[e.jsx(te,{children:"Enable Tunnel"}),e.jsx(re,{children:"Creates a temporary public URL for this router."})]}),e.jsxs(Y,{children:[e.jsx(C,{onClick:()=>void Ze(),children:"Start Tunnel"}),e.jsx(C,{variant:"outline",onClick:()=>B(!1),children:"Cancel"})]})]})}),e.jsx(zs,{open:G,loading:E,state:V,step:q,message:A,error:W,onOpenChange:X}),e.jsx(Z,{open:d,onOpenChange:g=>!E&&N(g),children:e.jsxs(ee,{children:[e.jsxs(se,{children:[e.jsx(te,{children:"Disable Tunnel"}),e.jsx(re,{children:"This will disconnect the public tunnel."})]}),e.jsxs(Y,{children:[e.jsx(C,{variant:"destructive",onClick:()=>void es(),disabled:E,children:E?"Disabling…":"Disable"}),e.jsx(C,{variant:"outline",onClick:()=>N(!1),disabled:E,children:"Cancel"})]})]})})]})}const _e={providerAccounts:!0,customProviders:!0,customModels:!0,combos:!0,routingSettings:!1,activateAccounts:!1};function Fs(s){return!!s&&typeof s=="object"&&!Array.isArray(s)}function Bs(s){if(!Fs(s))throw new Error("The selected file is not valid JSON data");if(s.product==="swayrouter")throw new Error("This is an Sway Router backup. Use Import JSON instead.");if(!("modelAliases"in s||"mitmAlias"in s||Array.isArray(s.providerConnections)&&Array.isArray(s.providerNodes)&&Array.isArray(s.combos)&&Array.isArray(s.customModels)&&s.formatVersion===void 0&&s.backupScope===void 0))throw new Error("This file is not a supported 9Router backup");return s}async function _s(s){try{return Bs(JSON.parse(await s.text()))}catch(a){throw a instanceof SyntaxError?new Error("The selected file is not valid JSON"):a}}async function Ge(s,a){if(s!=="local"){if(!a)throw new Error("Choose a 9Router JSON backup first");return await _s(a)}}async function Ks(){const{data:s}=await xe.get("/settings/migrate-9router");return s}async function Vs(s){const a=await Ge(s.source,s.file),{data:l}=await xe.post("/settings/migrate-9router",{action:"preview",source:s.source,payload:a,options:s.options});return l.preview}async function Qs(s){const a=await Ge(s.source,s.file),{data:l}=await xe.post("/settings/migrate-9router",{action:"migrate",source:s.source,payload:a,options:s.options,password:s.password});return l}const Ke=[{key:"analyzing",label:"Analyze source",description:"Validate 9Router data and resolve conflicts."},{key:"migrating",label:"Back up and migrate",description:"Create a safety backup, then import the selected data."},{key:"refreshing",label:"Refresh dashboard",description:"Reload providers, models, combos, and settings."},{key:"done",label:"Done",description:"The migrated data is ready to review."}],$s=[{key:"providerAccounts",label:"Provider accounts and credentials",description:"Compatible provider logins, tokens, and API keys."},{key:"customProviders",label:"Custom providers",description:"Compatible OpenAI, Anthropic, and embedding endpoints."},{key:"customModels",label:"Custom models",description:"Models whose provider is available after migration."},{key:"combos",label:"Combos",description:"Combo routes with compatible model references."},{key:"routingSettings",label:"Routing settings",description:"Provider and combo routing behavior. Off by default."},{key:"activateAccounts",label:"Activate imported accounts immediately",description:"Leave off to review accounts before routing traffic."}],Js={providerAccounts:"Provider accounts",customProviders:"Custom providers",customModels:"Custom models",combos:"Combos",routingSettings:"Routing settings"},Ys={ACCOUNT_PROVIDER_UNAVAILABLE:"Some accounts skipped",EMPTY_COMBO:"Some combos skipped",ORPHAN_CUSTOM_MODEL:"Some custom models skipped",UNSUPPORTED_ACCOUNT_PROVIDER:"Some accounts skipped",UNSUPPORTED_CUSTOM_PROVIDER:"Some providers skipped"},Gs=["settings","providers","providers-available","nodes","custom-models","combos"];function ie(s){return s==="previewing"||s==="migrating"}function Ws({open:s,onOpenChange:a}){var A,S,W,o;const l=ve(),x=t.useRef(null),[r,f]=t.useState("local"),[c,k]=t.useState(null),[y,m]=t.useState({..._e}),[i,v]=t.useState("configure"),[w,p]=t.useState(null),[R,T]=t.useState(""),[E,D]=t.useState("analyzing"),[M,j]=t.useState(""),[b,P]=t.useState(""),L=pe({queryKey:["nine-router-detection"],queryFn:Ks,enabled:s,staleTime:3e4});t.useEffect(()=>{if(!s)return;const n=L.data;n&&!n.available&&r==="local"&&f("json")},[L.data,s,r]),t.useEffect(()=>{s||(f("local"),k(null),m({..._e}),v("configure"),p(null),T(""),D("analyzing"),j(""),P(""),x.current&&(x.current.value=""))},[s]);function B(n,u){m(O=>{const K={...O,[n]:u};return n==="customModels"&&u&&(K.customProviders=!0),n==="customProviders"&&!u&&(K.customModels=!1),K})}function G(n){ie(i)||(f(n),p(null),P(""),v("configure"))}const d=(y.providerAccounts||y.customProviders||y.customModels||y.combos||y.routingSettings)&&(r==="local"?((A=L.data)==null?void 0:A.available)===!0:!!c);async function N(){if(!(!d||ie(i))){v("previewing"),D("analyzing"),j("Checking compatibility and resolving conflicts…"),P("");try{const n=await Vs({source:r,file:c,options:y});m(n.options),p(n),j(""),v("preview")}catch(n){const u=J(n,"Could not analyze the 9Router data");P(u),j(u),v("configure"),U.error(u)}}}async function V(){if(!(!w||w.totalReady<1||!R.trim()||ie(i))){v("migrating"),D("migrating"),j("Creating a safety backup and importing selected data…"),P("");try{const n=await Qs({source:r,file:c,options:y,password:R});if(!n.success)throw new Error(n.message||"Migration failed");D("refreshing"),j("Refreshing dashboard data…"),await Promise.all(Gs.map(u=>l.invalidateQueries({queryKey:[u]}))),T(""),D("done"),j(n.message||"9Router data migrated successfully."),v("ready"),U.success(n.message||"Migration complete")}catch(n){const u=J(n,"9Router migration failed");P(u),j(u),v("error"),U.error(u)}}}const z=Ke.findIndex(n=>n.key===E),q=i==="previewing"||i==="migrating"||i==="ready"||i==="error",h=((S=L.data)==null?void 0:S.available)===!0;return e.jsx(Z,{open:s,onOpenChange:n=>{!n&&ie(i)||a(n)},children:e.jsxs(ee,{className:"sm:max-w-2xl",showCloseButton:!ie(i),children:[e.jsxs(se,{children:[e.jsx(te,{children:i==="preview"?"Migration preview":i==="ready"?"Migration complete":i==="error"?"Migration needs attention":"Migrate from 9Router"}),e.jsx(re,{children:i==="configure"?"Choose a source and what you want to bring into Sway Router. Existing Sway Router data stays in place.":i==="preview"?"Review what will be added before making any changes.":i==="ready"?"A safety backup was created before your selected data was imported.":i==="error"?"No partial migration was kept. Review the error and try again.":"Keep this window open while Sway Router checks and migrates the data."})]}),i==="configure"?e.jsxs(e.Fragment,{children:[e.jsxs(H,{className:"space-y-5",children:[e.jsxs("div",{className:"grid gap-2 sm:grid-cols-2",children:[e.jsxs("button",{type:"button","aria-pressed":r==="local",disabled:L.isLoading||!h,onClick:()=>G("local"),className:`flex min-h-20 items-start gap-3 rounded-xl border p-3 text-left transition-colors duration-150 disabled:cursor-not-allowed disabled:opacity-50 ${r==="local"?"border-primary/60 bg-primary/10":"border-border bg-surface hover:bg-muted/60"}`,children:[L.isLoading?e.jsx(ne,{className:"mt-0.5 size-4 shrink-0 animate-spin text-muted-foreground"}):e.jsx(ms,{className:"mt-0.5 size-4 shrink-0"}),e.jsxs("span",{className:"min-w-0",children:[e.jsx("span",{className:"block text-sm font-medium",children:"Local installation"}),e.jsx("span",{className:"mt-0.5 block break-all text-xs text-muted-foreground",children:L.isLoading?"Looking for 9Router…":h?((W=L.data)==null?void 0:W.location)||"9Router database found":(o=L.data)!=null&&o.localOnly?"Only available on the router machine":"No local database found"})]})]}),e.jsxs("button",{type:"button","aria-pressed":r==="json",onClick:()=>G("json"),className:`flex min-h-20 items-start gap-3 rounded-xl border p-3 text-left transition-colors duration-150 ${r==="json"?"border-primary/60 bg-primary/10":"border-border bg-surface hover:bg-muted/60"}`,children:[e.jsx(ps,{className:"mt-0.5 size-4 shrink-0"}),e.jsxs("span",{className:"min-w-0",children:[e.jsx("span",{className:"block text-sm font-medium",children:"9Router JSON backup"}),e.jsx("span",{className:"mt-0.5 block text-xs text-muted-foreground",children:"Use an exported backup from this or another device."})]})]})]}),r==="json"?e.jsxs("div",{className:"flex flex-col gap-2 rounded-lg border border-border bg-surface p-3 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"truncate text-sm font-medium",children:(c==null?void 0:c.name)||"No file selected"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Choose a 9Router JSON export."})]}),e.jsx(C,{size:"sm",variant:"outline",onClick:()=>{var n;return(n=x.current)==null?void 0:n.click()},children:"Choose JSON"}),e.jsx("input",{ref:x,type:"file",accept:".json,application/json",className:"hidden",onChange:n=>{var O;const u=((O=n.target.files)==null?void 0:O[0])||null;k(u),P("")}})]}):null,e.jsx("div",{className:"space-y-2",children:$s.map(n=>{const u=n.key==="customProviders"&&y.customModels;return e.jsxs("label",{className:"flex cursor-pointer items-start gap-3 rounded-lg border border-border/70 p-3 transition-colors duration-150 hover:bg-muted/40",children:[e.jsx(ks,{checked:y[n.key],disabled:u,onCheckedChange:O=>B(n.key,O===!0),"aria-label":n.label}),e.jsxs("span",{className:"min-w-0",children:[e.jsx("span",{className:"block text-sm font-medium",children:n.label}),e.jsx("span",{className:"mt-0.5 block text-xs text-muted-foreground",children:u?"Required while Custom models is selected.":n.description})]})]},n.key)})}),b?e.jsx("p",{className:"rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive",children:b}):null]}),e.jsxs(Y,{children:[e.jsx(C,{variant:"outline",onClick:()=>a(!1),children:"Cancel"}),e.jsx(C,{onClick:()=>void N(),disabled:!d,children:"Preview migration"})]})]}):i==="preview"&&w?e.jsxs(e.Fragment,{children:[e.jsxs(H,{className:"space-y-4",children:[e.jsx("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-3",children:Object.entries(w.sections).map(([n,u])=>e.jsxs("div",{className:"rounded-xl border border-border bg-surface p-3.5",children:[e.jsx("p",{className:"truncate text-xs font-medium text-muted-foreground",children:Js[n]}),e.jsx("p",{className:"mt-2 text-2xl font-semibold tabular-nums tracking-tight",children:u.ready.toLocaleString()}),e.jsx("p",{className:"mt-0.5 text-[11px] text-muted-foreground",children:"ready to import"}),e.jsxs("div",{className:"mt-2 flex min-h-5 flex-wrap gap-1.5 text-[10px]",children:[u.resolved?e.jsxs("span",{className:"rounded-full border border-primary/25 bg-primary/10 px-2 py-0.5 text-primary",children:[u.resolved.toLocaleString()," handled"]}):null,u.duplicates?e.jsxs("span",{className:"rounded-full border border-border bg-muted/50 px-2 py-0.5 text-muted-foreground",children:[u.duplicates.toLocaleString()," already here"]}):null,u.skipped?e.jsxs("span",{className:"rounded-full border border-warning/25 bg-warning/10 px-2 py-0.5 text-warning-foreground",children:[u.skipped.toLocaleString()," skipped"]}):null,!u.resolved&&!u.duplicates&&!u.skipped?e.jsx("span",{className:"text-muted-foreground",children:"All clear"}):null]})]},n))}),w.warnings.length>0?e.jsx("div",{className:"space-y-2 rounded-xl border border-warning/30 bg-warning/10 p-3",children:w.warnings.map(n=>e.jsxs("div",{className:"flex items-start gap-3 rounded-lg border border-warning/20 bg-background/20 p-2.5 text-warning-foreground",children:[e.jsx(ye,{className:"mt-0.5 size-4 shrink-0"}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-x-3 gap-y-1",children:[e.jsx("p",{className:"text-xs font-medium",children:Ys[n.code]||"Import note"}),e.jsxs("span",{className:"text-[10px] font-medium uppercase tracking-wide text-warning-foreground/75",children:[n.count.toLocaleString()," affected"]})]}),e.jsx("p",{className:"mt-0.5 text-xs text-warning-foreground/85",children:n.message})]})]},n.code))}):null,e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"Dashboard password"}),e.jsx(Ae,{type:"password",value:R,onChange:n=>T(n.target.value),autoComplete:"current-password",placeholder:"Enter password to confirm"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Imported accounts stay inactive unless you selected immediate activation. Existing Sway Router data will not be replaced."})]}),e.jsxs(Y,{children:[e.jsx(C,{variant:"outline",onClick:()=>{T(""),v("configure")},children:"Back"}),e.jsxs(C,{onClick:()=>void V(),disabled:!R.trim()||w.totalReady<1,children:["Migrate ",w.totalReady.toLocaleString()," items"]})]})]}):q?e.jsxs(e.Fragment,{children:[e.jsxs(H,{className:"space-y-4",children:[e.jsx("div",{className:"space-y-3","aria-live":"polite",children:Ke.map((n,u)=>{const O=i==="ready"||u<z,K=i==="error"&&u===z,ae=(i==="previewing"||i==="migrating")&&u===z;return e.jsxs("div",{className:"flex gap-3",children:[e.jsx("div",{className:`mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-full border transition-colors duration-150 ${O?"border-success/40 bg-success/12 text-success":K?"border-destructive/40 bg-destructive/12 text-destructive":ae?"border-primary/50 bg-primary/12 text-primary":"border-border bg-surface text-muted-foreground"}`,children:O?e.jsx(je,{className:"size-4"}):K?e.jsx(ye,{className:"size-4"}):ae?e.jsx(ne,{className:"size-4 animate-spin"}):e.jsx("span",{className:"size-1.5 rounded-full bg-current opacity-60"})}),e.jsxs("div",{className:"min-w-0 pt-0.5",children:[e.jsx("p",{className:"text-sm font-medium",children:n.label}),e.jsx("p",{className:"text-xs text-muted-foreground",children:K?b:ae?M:n.description})]})]},n.key)})}),e.jsx("div",{className:`rounded-lg border px-3 py-2 text-xs transition-colors duration-150 ${i==="error"?"border-destructive/25 bg-destructive/8 text-destructive":i==="ready"?"border-success/25 bg-success/8 text-success":"border-border bg-surface text-muted-foreground"}`,children:M})]}),ie(i)?null:e.jsxs(Y,{children:[i==="error"&&w?e.jsx(C,{variant:"outline",onClick:()=>{T(""),v("preview")},children:"Back to preview"}):null,e.jsx(C,{onClick:()=>a(!1),children:i==="ready"?"Done":"Close"})]})]}):null]})})}function Hs(s){if(!s||typeof s!="object"||Array.isArray(s))throw new Error("Invalid JSON backup file");const a=s;if(a.product!=="swayrouter"&&("modelAliases"in a||"mitmAlias"in a||a.formatVersion===void 0&&a.backupScope===void 0&&a.apiKeysRedacted===void 0&&Array.isArray(a.providerConnections)&&Array.isArray(a.providerNodes)))throw new Error("This is a 9Router backup. Use Migrate from 9Router instead.");if(a.formatVersion!==void 0&&a.formatVersion!==1)throw new Error(`Unsupported backup format version: ${a.formatVersion}`);if(a.backupScope!==void 0&&a.backupScope!=="configuration"&&a.backupScope!=="full")throw new Error("Invalid backup scope");if(a.providerCredentialsIncluded!==void 0&&typeof a.providerCredentialsIncluded!="boolean")throw new Error("Invalid provider credential metadata");return a}async function Xs(s,a="configuration"){const{data:l}=await xe.get("/settings/database",{headers:{"x-swayrouter-password":s},params:{scope:a}}),x=new Blob([JSON.stringify(l,null,2)],{type:"application/json;charset=utf-8"}),r=URL.createObjectURL(x),f=document.createElement("a"),c=new Date().toISOString().replace(/[:.]/g,"-");f.href=r,f.download=`sway-router-${a==="full"?"full-data":"configuration"}-backup-${c}.json`,document.body.appendChild(f),f.click(),f.remove(),URL.revokeObjectURL(r)}async function Zs(s,a,l){l==null||l("validating");let x;try{x=Hs(JSON.parse(await s.text()))}catch(f){throw f instanceof SyntaxError?new Error("Backup file is not valid JSON"):f}l==null||l("restoring");const{data:r}=await xe.post("/settings/database",{...x,password:a});return r}const Ve=[{value:"lite",label:"Lite"},{value:"full",label:"Full"},{value:"ultra",label:"Ultra"},{value:"wenyan-lite",label:"Wenyan lite"},{value:"wenyan",label:"Wenyan"},{value:"wenyan-ultra",label:"Wenyan ultra"}],Qe=[{value:"lite",label:"Lite"},{value:"full",label:"Full"},{value:"ultra",label:"Ultra"}],$e=[{key:"validating",label:"Validate file",description:"Check the JSON format and backup metadata."},{key:"restoring",label:"Restore data",description:"Import the backup into Sway Router."},{key:"refreshing",label:"Refresh dashboard",description:"Reload the restored settings and resources."},{key:"done",label:"Done",description:"The backup is ready to use."}];function Je(s,a){var l;return((l=s.find(x=>x.value===a))==null?void 0:l.label)??a}function oe(s,a,l){return Math.min(Math.max(s,a),l)}function et({open:s,imageSrc:a,onOpenChange:l,onApply:x}){const r=t.useRef(null),f=t.useRef(null),c=t.useRef(null),[k,y]=t.useState(320),[m,i]=t.useState({width:0,height:0}),[v,w]=t.useState(1),[p,R]=t.useState({x:0,y:0});t.useEffect(()=>{s&&(w(1),R({x:0,y:0}),i({width:0,height:0}))},[s,a]),t.useEffect(()=>{if(!s||!r.current)return;const d=r.current,N=()=>y(Math.max(1,d.clientWidth));N();const V=new ResizeObserver(N);return V.observe(d),()=>V.disconnect()},[s]);const E=(m.width&&m.height?k/Math.min(m.width,m.height):1)*v,D=m.width*E,M=m.height*E,j=Math.max(0,(D-k)/2),b=Math.max(0,(M-k)/2);t.useEffect(()=>{R(d=>({x:oe(d.x,-j,j),y:oe(d.y,-b,b)}))},[j,b]);function P(d){i({width:d.currentTarget.naturalWidth,height:d.currentTarget.naturalHeight})}function L(d){!m.width||!m.height||(d.currentTarget.setPointerCapture(d.pointerId),c.current={pointerId:d.pointerId,startX:d.clientX,startY:d.clientY,originX:p.x,originY:p.y})}function B(d){const N=c.current;!N||N.pointerId!==d.pointerId||R({x:oe(N.originX+d.clientX-N.startX,-j,j),y:oe(N.originY+d.clientY-N.startY,-b,b)})}function G(d){var N;((N=c.current)==null?void 0:N.pointerId)===d.pointerId&&(c.current=null,d.currentTarget.hasPointerCapture(d.pointerId)&&d.currentTarget.releasePointerCapture(d.pointerId))}function X(){const d=f.current;if(!d||!m.width||!m.height||!E)return;const N=k/E,V=oe(m.width/2-N/2-p.x/E,0,m.width-N),z=oe(m.height/2-N/2-p.y/E,0,m.height-N),q=document.createElement("canvas");q.width=384,q.height=384;const h=q.getContext("2d");if(!h){U.error("Unable to crop profile photo");return}h.imageSmoothingEnabled=!0,h.imageSmoothingQuality="high",h.drawImage(d,V,z,N,N,0,0,q.width,q.height);const A=q.toDataURL("image/jpeg",.86);if(A.length>512*1024){U.error("Cropped profile photo is still too large");return}x(A)}return e.jsx(Z,{open:s,onOpenChange:l,children:e.jsxs(ee,{className:"sm:max-w-md",children:[e.jsx(se,{children:e.jsx(te,{children:"Adjust profile photo"})}),e.jsxs(H,{className:"space-y-4",children:[e.jsxs("div",{ref:r,role:"img","aria-label":"Profile photo crop preview",className:"relative mx-auto aspect-square w-full max-w-[360px] cursor-grab touch-none overflow-hidden rounded-2xl border border-border bg-muted active:cursor-grabbing",onPointerDown:L,onPointerMove:B,onPointerUp:G,onPointerCancel:G,children:[a?e.jsx("img",{ref:f,src:a,alt:"",draggable:!1,onLoad:P,className:"absolute left-1/2 top-1/2 max-w-none select-none",style:{width:D||"100%",height:M||"100%",transform:`translate(-50%, -50%) translate(${p.x}px, ${p.y}px)`}}):null,e.jsx("div",{className:"pointer-events-none absolute inset-0 rounded-2xl ring-1 ring-inset ring-white/15"})]}),e.jsxs("div",{className:"mx-auto w-full max-w-[360px] space-y-2",children:[e.jsxs("div",{className:"grid grid-cols-[minmax(0,1fr)_3rem] items-center gap-3",children:[e.jsxs("div",{className:"flex min-w-0 items-center justify-center gap-2",children:[e.jsx(vs,{className:"size-3.5 shrink-0 text-muted-foreground"}),e.jsx("input",{"aria-label":"Photo zoom",type:"range",min:"1",max:"3",step:"0.01",value:v,onChange:d=>w(Number(d.target.value)),className:"min-w-0 flex-1 accent-primary"}),e.jsx(js,{className:"size-3.5 shrink-0 text-muted-foreground"})]}),e.jsxs("span",{className:"w-12 text-right text-xs tabular-nums text-muted-foreground",children:[Math.round(v*100),"%"]})]}),e.jsx("div",{className:"flex justify-end",children:e.jsxs("button",{type:"button",className:"inline-flex items-center gap-1 rounded-md px-1.5 py-1 text-[11px] text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground",onClick:()=>{w(1),R({x:0,y:0})},children:[e.jsx(ws,{className:"size-3"}),"Reset"]})})]})]}),e.jsxs(Y,{children:[e.jsx(C,{variant:"outline",onClick:()=>l(!1),children:"Cancel"}),e.jsx(C,{onClick:X,disabled:!m.width||!m.height,children:"Use photo"})]})]})})}function Te({label:s,active:a,onToggle:l}){return e.jsxs("div",{className:"flex items-center justify-between gap-4 rounded-xl border border-border bg-card px-4 py-3",children:[e.jsx("div",{className:"min-w-0",children:e.jsx("p",{className:"text-sm font-medium",children:s})}),e.jsx(ue,{active:a,onToggle:l,activeLabel:"",inactiveLabel:""})]})}function me({label:s,value:a,onChange:l,hint:x,autoComplete:r,autoFocus:f}){const[c,k]=t.useState(!1);return e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"text-xs font-medium text-muted-foreground",children:s}),e.jsxs("div",{className:"relative",children:[e.jsx(Ae,{type:c?"text":"password",value:a,onChange:l,autoComplete:r,autoFocus:f,className:"pr-10"}),e.jsx("button",{type:"button","aria-label":c?`Hide ${s.toLowerCase()}`:`Show ${s.toLowerCase()}`,onClick:()=>k(y=>!y),className:"absolute right-2.5 top-1/2 -translate-y-1/2 rounded-md p-1 text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",children:c?e.jsx(Ns,{className:"size-4"}):e.jsx(Ss,{className:"size-4"})})]}),x?e.jsx("span",{className:"block text-[11px] text-muted-foreground/80",children:x}):null]})}function st({open:s,onOpenChange:a,hasPassword:l,onChanged:x}){const[r,f]=t.useState(l?"verify":"new"),[c,k]=t.useState(""),[y,m]=t.useState(""),[i,v]=t.useState(""),[w,p]=t.useState(null),[R,T]=t.useState(!1);t.useEffect(()=>{s&&(f(l?"verify":"new"),k(""),m(""),v(""),p(null),T(!1))},[s,l]);function E(){R||a(!1)}async function D(){if(!c){p("Enter your current password to continue.");return}T(!0),p(null);try{await os(c),f("new")}catch(b){p(J(b,"Unable to verify current password"))}finally{T(!1)}}async function M(){if(y.length<6){p("New password must be at least 6 characters.");return}if(y!==i){p("New password and confirmation do not match.");return}T(!0),p(null);try{await Ee({newPassword:y,...l?{currentPassword:c}:{}}),await x(),a(!1)}catch(b){p(J(b,"Unable to change dashboard password"))}finally{T(!1)}}async function j(b){b.preventDefault(),r==="verify"?await D():await M()}return e.jsx(Z,{open:s,onOpenChange:b=>b?a(!0):E(),children:e.jsx(ee,{className:"sm:max-w-md",children:e.jsxs("form",{onSubmit:j,children:[e.jsxs(se,{children:[e.jsx(te,{children:r==="verify"?"Verify current password":"Set a new dashboard password"}),e.jsx(re,{children:r==="verify"?"Confirm your current password before choosing a replacement.":"Choose a password with at least 6 characters, then confirm it below."})]}),e.jsxs(H,{className:"space-y-4",children:[r==="verify"?e.jsx(me,{label:"Current password",value:c,onChange:b=>k(b.target.value),autoComplete:"current-password",autoFocus:!0}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"rounded-lg border border-success/25 bg-success/8 px-3 py-2 text-xs text-success",children:"Current password verified. You can now set a new one."}),e.jsx(me,{label:"New dashboard password",value:y,onChange:b=>m(b.target.value),hint:"At least 6 characters",autoComplete:"new-password",autoFocus:!0}),e.jsx(me,{label:"Confirm new password",value:i,onChange:b=>v(b.target.value),autoComplete:"new-password"})]}),w?e.jsx("p",{role:"alert",className:"text-xs text-destructive",children:w}):null]}),e.jsxs(Y,{children:[r==="new"&&l?e.jsx(C,{type:"button",variant:"outline",onClick:()=>{f("verify"),p(null)},disabled:R,children:"Back"}):e.jsx(C,{type:"button",variant:"outline",onClick:E,disabled:R,children:"Cancel"}),e.jsx(C,{type:"submit",disabled:R,children:R?r==="verify"?"Checking…":"Updating…":r==="verify"?"Continue":"Change password"})]})]})})})}function tt({open:s,onOpenChange:a,title:l,description:x,busy:r,onConfirm:f}){const[c,k]=t.useState("");t.useEffect(()=>{k("")},[s]);function y(){r||(k(""),a(!1))}async function m(i){i.preventDefault(),!(!c.trim()||r)&&await f(c)}return e.jsx(Z,{open:s,onOpenChange:i=>i?a(!0):y(),children:e.jsx(ee,{className:"sm:max-w-md",children:e.jsxs("form",{onSubmit:m,children:[e.jsxs(se,{children:[e.jsx(te,{children:l}),e.jsx(re,{children:x})]}),e.jsx(H,{children:e.jsx(me,{label:"Dashboard password",value:c,onChange:i=>k(i.target.value),autoComplete:"current-password",autoFocus:!0})}),e.jsxs(Y,{children:[e.jsx(C,{type:"button",variant:"outline",onClick:y,disabled:r,children:"Cancel"}),e.jsx(C,{type:"submit",disabled:r||!c.trim(),children:r?"Working…":"Continue"})]})]})})})}function rt({open:s,onOpenChange:a,busy:l,onConfirm:x}){function r(){l||a(!1)}return e.jsx(Z,{open:s,onOpenChange:f=>f?a(!0):r(),children:e.jsxs(ee,{className:"sm:max-w-md",children:[e.jsxs(se,{children:[e.jsx(te,{children:"Shut down Sway Router?"}),e.jsx(re,{children:"The router will stop accepting new requests and gracefully drain active work before the process exits."})]}),e.jsx(H,{className:"space-y-3",children:e.jsx("div",{className:"rounded-lg border border-destructive/25 bg-destructive/8 px-3 py-2 text-xs text-destructive-foreground",children:"You will need to start the router again from its service manager or terminal. This does not delete settings, providers, or usage data."})}),e.jsxs(Y,{children:[e.jsx(C,{type:"button",variant:"outline",onClick:r,disabled:l,children:"Cancel"}),e.jsxs(C,{type:"button",variant:"destructive",onClick:()=>void x(),disabled:l,children:[e.jsx(Le,{}),l?"Shutting down…":"Shut down router"]})]})]})})}function Nt(){var h,A,S,W;const s=ve(),[a]=rs(),[l,x]=t.useState(()=>{const o=a.get("tab");return o==="preferences"||o==="general"||o==="security"||o==="data"?o:"preferences"}),[r,f]=t.useState(()=>qe({requireApiKey:!0,requireLogin:!0,rtkEnabled:!0,cavemanEnabled:!1,cavemanLevel:"full",ponytailEnabled:!1,ponytailLevel:"full"})),[c,k]=t.useState(!1),[y,m]=t.useState(!1),[i,v]=t.useState(!1),[w,p]=t.useState(!1),[R,T]=t.useState(null),[E,D]=t.useState("idle"),M=t.useRef(r),j=t.useRef(null),b=t.useRef(Promise.resolve()),P=t.useRef(0),L=pe({queryKey:["settings"],queryFn:Ye,enabled:Pe(),retry:!1}),B=pe({queryKey:["settings","database-path"],queryFn:ls,enabled:l==="data",retry:!1});t.useEffect(()=>{if(L.data){const o=qe(L.data);M.current=o,f(o)}},[L.data]),t.useEffect(()=>()=>{j.current&&clearTimeout(j.current)},[]);const G=L.isLoading;function X(o){const n=++P.current;D("saving"),j.current&&clearTimeout(j.current),j.current=setTimeout(()=>{j.current=null,b.current=b.current.catch(()=>{}).then(async()=>{await Ee(o),s.setQueryData(["settings"],u=>u&&{...u,...o}),Object.prototype.hasOwnProperty.call(o,"currency")&&await s.invalidateQueries({queryKey:["currency-settings"]}),n===P.current&&D("saved")}).catch(u=>{n===P.current&&(D("error"),U.error(J(u,"Automatic save failed")))})},300)}function d(o,n){const u=o==="profileName"&&typeof n=="string"?n.trim().replace(/\s+/g," ").slice(0,40)||"Sway Router":n,O={...M.current,[o]:u};M.current=O,f(O),X(o==="profileName"||o==="profileAvatar"||o==="currency"?{[o]:u}:Ls(O))}function N(o){var K;const n=(K=o.target.files)==null?void 0:K[0];if(o.target.value="",!n)return;if(!new Set(["image/png","image/jpeg","image/webp","image/gif"]).has(n.type)){U.error("Profile photo must be PNG, JPG, WEBP, or GIF");return}if(n.size>2*1024*1024){U.error("Profile photo must be 2 MB or smaller");return}const O=new FileReader;O.onload=()=>{typeof O.result=="string"&&(T(O.result),p(!0))},O.onerror=()=>U.error("Unable to read profile photo"),O.readAsDataURL(n)}function V(o){p(o),o||T(null)}function z(o){d("profileAvatar",o),p(!1),T(null)}async function q(){v(!0);try{const o=await ns();if(o.success===!1)throw new Error(o.message||"Shutdown request was rejected");m(!1),U.success("Shutdown initiated. The router is draining active requests.")}catch(o){U.error(J(o,"Shutdown failed")),v(!1)}}return G?e.jsxs("div",{className:"space-y-4",children:[e.jsx(ze,{title:"Settings"}),e.jsx(Cs,{className:"h-64 w-full"})]}):e.jsxs("div",{className:"space-y-4",children:[e.jsx(ze,{title:"Settings"}),e.jsxs(Rs,{value:l,className:"gap-2",onValueChange:o=>x(o),children:[e.jsxs("div",{className:"flex min-h-8 flex-wrap items-center justify-between gap-2",children:[e.jsxs(Ts,{className:"w-fit max-w-full justify-start overflow-x-auto",children:[e.jsx(ge,{value:"preferences",children:"Preferences"}),e.jsx(ge,{value:"general",children:"General"}),e.jsx(ge,{value:"security",children:"Security"}),e.jsx(ge,{value:"data",children:"Data"})]}),e.jsx("div",{className:"min-h-4 text-right text-xs text-muted-foreground","aria-live":"polite",children:E==="saving"?"Saving changes…":E==="saved"?"All changes saved":E==="error"?e.jsx("span",{className:"text-destructive",children:"Automatic save failed"}):null})]}),e.jsxs(be,{value:"general",className:"space-y-3",children:[e.jsxs("div",{className:"space-y-2 pt-1",children:[e.jsx("p",{className:"text-xs font-medium text-muted-foreground",children:"Token saver"}),e.jsx(Te,{label:"RTK",active:r.rtkEnabled,onToggle:()=>d("rtkEnabled",!r.rtkEnabled)}),e.jsxs("div",{className:"rounded-xl border border-border bg-card px-4 py-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsx("div",{className:"min-w-0",children:e.jsx("p",{className:"text-sm font-medium",children:"Caveman"})}),e.jsx(ue,{active:r.cavemanEnabled,onToggle:()=>d("cavemanEnabled",!r.cavemanEnabled),activeLabel:"",inactiveLabel:""})]}),e.jsx("div",{className:"mt-3",children:e.jsxs(ke,{value:r.cavemanLevel,onValueChange:o=>d("cavemanLevel",o??"full"),disabled:!r.cavemanEnabled,children:[e.jsx(Ce,{size:"sm",className:"w-full sm:w-44",children:e.jsx("span",{className:"truncate",children:Je(Ve,r.cavemanLevel)})}),e.jsx(Re,{children:Ve.map(o=>e.jsx(he,{value:o.value,children:o.label},o.value))})]})})]}),e.jsxs("div",{className:"rounded-xl border border-border bg-card px-4 py-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsx("div",{className:"min-w-0",children:e.jsx("p",{className:"text-sm font-medium",children:"Ponytail"})}),e.jsx(ue,{active:r.ponytailEnabled,onToggle:()=>d("ponytailEnabled",!r.ponytailEnabled),activeLabel:"",inactiveLabel:""})]}),e.jsx("div",{className:"mt-3",children:e.jsxs(ke,{value:r.ponytailLevel,onValueChange:o=>d("ponytailLevel",o??"full"),disabled:!r.ponytailEnabled,children:[e.jsx(Ce,{size:"sm",className:"w-full sm:w-44",children:e.jsx("span",{className:"truncate",children:Je(Qe,r.ponytailLevel)})}),e.jsx(Re,{children:Qe.map(o=>e.jsx(he,{value:o.value,children:o.label},o.value))})]})})]})]}),e.jsxs("div",{className:"space-y-3 border-t border-border/70 pt-3",children:[e.jsx("p",{className:"text-xs font-medium text-muted-foreground",children:"Advanced"}),e.jsx(Ps,{className:"rounded-xl border border-border bg-card px-4",children:e.jsxs(Es,{value:"payload-capture",className:"border-0",children:[e.jsxs("div",{className:"flex items-center justify-between gap-4 py-3",children:[e.jsx("p",{className:"text-sm font-medium",children:"Capture full request payloads"}),e.jsx(ue,{active:r.payloadCaptureEnabled,onToggle:()=>d("payloadCaptureEnabled",!r.payloadCaptureEnabled),activeLabel:"",inactiveLabel:""})]}),e.jsx(As,{className:"w-fit flex-none justify-start gap-1 py-2 text-xs text-muted-foreground",children:"Details"}),e.jsx(Ds,{className:"pb-3",children:e.jsx("div",{className:"rounded-lg border border-warning/30 bg-warning/10 px-3 py-2 text-xs text-warning-foreground",children:"Payloads may include API keys, cookies, prompts, and provider responses. Applies to new request details."})})]})}),e.jsx(qs,{requireApiKey:r.requireApiKey,requireLogin:r.requireLogin,hasPassword:!!((h=L.data)!=null&&h.hasPassword)})]})]}),e.jsx(be,{value:"preferences",className:"space-y-4",children:e.jsxs(le,{children:[e.jsx(ce,{className:"p-4",children:e.jsx("p",{className:"text-sm font-medium",children:"Profile & display"})}),e.jsxs(De,{className:"space-y-5 p-4",children:[e.jsxs("div",{className:"flex flex-col gap-4 sm:flex-row sm:items-center",children:[e.jsx("img",{src:r.profileAvatar||"/logo/avatar.svg",alt:"Profile preview",className:"size-16 shrink-0 rounded-2xl border border-border bg-muted object-cover"}),e.jsxs("div",{className:"min-w-0 space-y-2",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:"Profile photo"}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground",children:"PNG, JPG, WEBP, or GIF — max 2 MB."})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("label",{htmlFor:"profile-photo-upload",className:"inline-flex h-8 cursor-pointer items-center gap-1.5 rounded-lg border border-input bg-popover px-2.5 text-sm font-medium text-foreground transition-colors hover:bg-accent/50",children:[e.jsx(xs,{className:"size-3.5"}),"Choose photo"]}),e.jsx("input",{id:"profile-photo-upload",type:"file",accept:"image/png,image/jpeg,image/webp,image/gif",className:"sr-only",onChange:N}),r.profileAvatar?e.jsxs(C,{size:"sm",variant:"ghost",onClick:()=>d("profileAvatar",""),children:[e.jsx(fs,{className:"size-3.5"}),"Delete"]}):null]})]})]}),e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"text-xs font-medium text-muted-foreground",children:"Profile name"}),e.jsx(Ae,{value:r.profileName,onChange:o=>d("profileName",o.target.value),maxLength:40,placeholder:"Sway Router"}),e.jsx("span",{className:"block text-[11px] text-muted-foreground/80",children:"Shown in the sidebar account card."})]}),e.jsxs("label",{className:"block space-y-1.5",children:[e.jsx("span",{className:"block text-xs font-medium text-muted-foreground",children:"Cost currency"}),e.jsxs(ke,{value:r.currency,onValueChange:o=>d("currency",o==="IDR"?"IDR":"USD"),children:[e.jsx(Ce,{size:"sm",className:"w-full sm:w-56",children:e.jsx("span",{className:"truncate",children:r.currency==="IDR"?"IDR · Indonesian Rupiah":"USD · US Dollar"})}),e.jsxs(Re,{children:[e.jsx(he,{value:"USD",children:"USD · US Dollar"}),e.jsx(he,{value:"IDR",children:"IDR · Indonesian Rupiah"})]})]})]})]})]})}),e.jsxs(be,{value:"security",className:"space-y-4",children:[e.jsx(Te,{label:"Require API key",active:r.requireApiKey,onToggle:()=>d("requireApiKey",!r.requireApiKey)}),e.jsx(Te,{label:"Require dashboard auth",active:r.requireLogin,onToggle:()=>d("requireLogin",!r.requireLogin)}),e.jsxs("div",{className:"flex items-center justify-between gap-4 rounded-xl border border-border bg-card px-4 py-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm font-medium",children:"Dashboard password"}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground",children:(A=L.data)!=null&&A.hasPassword?"Password is set. Verify it before replacing it.":"No custom password is set yet."})]}),e.jsx(C,{size:"sm",variant:"outline",onClick:()=>k(!0),children:(S=L.data)!=null&&S.hasPassword?"Change password":"Set password"})]}),e.jsx(st,{open:c,onOpenChange:k,hasPassword:!!((W=L.data)!=null&&W.hasPassword),onChanged:async()=>{await s.invalidateQueries({queryKey:["settings"]}),U.success("Dashboard password changed")}}),e.jsx("div",{className:"rounded-xl border border-destructive/30 bg-destructive/[0.04] px-4 py-3",children:e.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm font-medium",children:"Danger zone"}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground",children:"Stop the router gracefully. Active requests can finish before the process exits."})]}),e.jsxs(C,{size:"sm",variant:"destructive-outline",onClick:()=>m(!0),disabled:i,children:[e.jsx(Le,{}),"Shutdown router"]})]})}),e.jsx(rt,{open:y,onOpenChange:m,busy:i,onConfirm:q})]}),e.jsx(be,{value:"data",className:"space-y-4",children:e.jsx(at,{dbPath:B.data,loading:B.isLoading})})]}),e.jsx(et,{open:w,imageSrc:R||"",onOpenChange:V,onApply:z})]})}function at({dbPath:s,loading:a}){const l=ve(),x=t.useRef(null),[r,f]=t.useState(!1),[c,k]=t.useState(null),[y,m]=t.useState(""),[i,v]=t.useState("idle"),[w,p]=t.useState("validating"),[R,T]=t.useState(""),[E,D]=t.useState(""),[M,j]=t.useState(!1),[b,P]=t.useState(!1),[L,B]=t.useState(!1),G=a?"Loading…":s?is(s):"Unavailable";function X(){j(!0)}async function d(h){P(!0);try{await Xs(h,"full"),U.success("Backup downloaded"),j(!1)}catch(A){U.error(J(A,"Download failed"))}finally{P(!1)}}function N(){r||(k(null),m(""),v("idle"),p("validating"),T(""),D(""),x.current&&(x.current.value=""))}function V(h){if(!h.name.toLowerCase().endsWith(".json")){U.error("Please select a .json backup file"),x.current&&(x.current.value="");return}m(""),v("idle"),p("validating"),T(""),D(""),k(h)}async function z(){const h=c;if(!(!h||!y.trim()||r)){f(!0),v("loading"),p("validating"),T("Checking the backup file…"),D("");try{const A=await Zs(h,y,S=>{p(S),T(S==="validating"?"Checking the backup file…":"Restoring data from the backup…")});if(!A.success)throw new Error(A.message||"Restore failed");p("refreshing"),T("Refreshing dashboard data…"),await Promise.all([l.invalidateQueries({queryKey:["settings"]}),l.invalidateQueries({queryKey:["keys"]}),l.invalidateQueries({queryKey:["providers"]}),l.invalidateQueries({queryKey:["providers-available"]}),l.invalidateQueries({queryKey:["nodes"]}),l.invalidateQueries({queryKey:["custom-models"]}),l.invalidateQueries({queryKey:["combos"]})]),p("done"),T(A.message||"Backup restored successfully."),v("ready"),U.success(A.message||"Backup restored")}catch(A){const S=J(A,"Restore failed");v("error"),D(S),T(S),U.error(S)}finally{f(!1)}}}const q=$e.findIndex(h=>h.key===w);return e.jsxs("div",{className:"space-y-4",children:[e.jsxs(le,{children:[e.jsxs(ce,{className:"flex flex-row items-center gap-3 p-4 pb-3",children:[e.jsx("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg border border-border bg-transparent",children:e.jsx(hs,{className:"h-4 w-4 text-white"})}),e.jsx("div",{children:e.jsx("p",{className:"text-sm font-medium",children:"Database Location"})})]}),e.jsx(De,{className:"p-4",children:e.jsx("code",{className:"block break-all rounded-md bg-surface px-3 py-1.5 font-mono text-xs text-muted-foreground",children:G})})]}),e.jsx(le,{children:e.jsxs(ce,{className:"flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between",children:[e.jsx("div",{className:"min-w-0",children:e.jsx("p",{className:"text-sm font-medium",children:"Export JSON"})}),e.jsxs(C,{size:"sm",variant:"outline",onClick:X,disabled:b,className:"shrink-0 self-start sm:self-auto",children:[e.jsx(gs,{className:"h-4 w-4"}),b?"Exporting…":"Export JSON"]})]})}),e.jsx(le,{children:e.jsxs(ce,{className:"flex flex-row items-center justify-between gap-3 p-4",children:[e.jsx("div",{children:e.jsx("p",{className:"text-sm font-medium",children:"Restore from Backup"})}),e.jsxs(C,{size:"sm",variant:"outline",onClick:()=>{var h;return(h=x.current)==null?void 0:h.click()},disabled:r,children:[e.jsx(bs,{className:"h-4 w-4"}),r?"Restoring…":"Import JSON"]}),e.jsx("input",{ref:x,type:"file",accept:".json,application/json",className:"hidden",onChange:h=>{var S;const A=(S=h.target.files)==null?void 0:S[0];A&&V(A)}})]})}),e.jsx(le,{children:e.jsxs(ce,{className:"flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm font-medium",children:"Migrate from 9Router"}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground",children:"Preview and merge compatible accounts, providers, models, combos, and routing settings."})]}),e.jsxs(C,{size:"sm",variant:"outline",onClick:()=>B(!0),className:"shrink-0 self-start sm:self-auto",children:[e.jsx(ys,{className:"h-4 w-4"}),"Start migration"]})]})}),e.jsx(Z,{open:!!c,onOpenChange:h=>{h||N()},children:e.jsxs(ee,{className:"sm:max-w-md",showCloseButton:!r,children:[e.jsxs(se,{children:[e.jsx(te,{children:i==="idle"?"Restore backup?":i==="ready"?"Backup restored":i==="error"?"Restore needs attention":"Restoring backup"}),e.jsx(re,{children:i==="idle"?e.jsxs(e.Fragment,{children:["Restore ",e.jsx("span",{className:"font-medium text-foreground",children:c==null?void 0:c.name})," and replace the current data? This full backup includes provider credentials, configuration, usage history, daily totals, and request details. Redacted gateway API keys will be preserved."]}):r?"Keep this window open while the backup is being restored.":i==="ready"?"Your restored data is loaded and ready to use.":"The backup could not be restored. Close this dialog and try again."})]}),i==="idle"?e.jsxs(e.Fragment,{children:[e.jsx(H,{children:e.jsx(me,{label:"Dashboard password",value:y,onChange:h=>m(h.target.value),autoComplete:"current-password",autoFocus:!0})}),e.jsxs(Y,{children:[e.jsx(C,{variant:"outline",onClick:N,children:"Cancel"}),e.jsx(C,{variant:"destructive",onClick:()=>void z(),disabled:!y.trim(),children:"Restore"})]})]}):e.jsxs(e.Fragment,{children:[e.jsxs(H,{className:"space-y-4",children:[e.jsx("div",{className:"space-y-3","aria-live":"polite",children:$e.map((h,A)=>{const S=i==="ready"||A<q,W=i==="error"&&A===q,o=i==="loading"&&A===q;return e.jsxs("div",{className:"flex gap-3",children:[e.jsx("div",{className:`mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-full border transition-colors duration-150 ${S?"border-success/40 bg-success/12 text-success":W?"border-destructive/40 bg-destructive/12 text-destructive":o?"border-primary/50 bg-primary/12 text-primary":"border-border bg-surface text-muted-foreground"}`,children:S?e.jsx(je,{className:"size-4"}):W?e.jsx(ye,{className:"size-4"}):o?e.jsx(ne,{className:"size-4 animate-spin"}):e.jsx("span",{className:"size-1.5 rounded-full bg-current opacity-60"})}),e.jsxs("div",{className:"min-w-0 pt-0.5",children:[e.jsx("p",{className:"text-sm font-medium",children:h.label}),e.jsx("p",{className:"text-xs text-muted-foreground",children:W?E:o?R:h.description})]})]},h.key)})}),e.jsx("div",{className:`rounded-lg border px-3 py-2 text-xs transition-colors duration-150 ${i==="error"?"border-destructive/25 bg-destructive/8 text-destructive-foreground":i==="ready"?"border-success/25 bg-success/8 text-success":"border-border bg-surface text-muted-foreground"}`,children:R})]}),r?null:e.jsx(Y,{children:e.jsx(C,{onClick:N,children:i==="ready"?"Done":"Close"})})]})]})}),e.jsx(tt,{open:M,onOpenChange:j,title:"Export JSON",description:"Enter your dashboard password. This file includes provider credentials, usage history, and captured request details. Store it securely.",busy:b,onConfirm:d}),e.jsx(Ws,{open:L,onOpenChange:B})]})}export{Nt as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{d as g,r as a,j as e}from"./react-vendor-xnYrwzsL.js";import{u,I as w,T as b,a as j,g as v}from"./index-
|
|
1
|
+
import{d as g,r as a,j as e}from"./react-vendor-xnYrwzsL.js";import{u,I as w,T as b,a as j,g as v}from"./index-x5tLD3Ye.js";import{R as S}from"./ripple-button-BV_KcZ7W.js";import{C as y,a as N,b as C,c as P}from"./card-BOVhvx7W.js";import{a8 as E,a9 as R}from"./icons-vendor-CUx7SB5V.js";import"./query-vendor-DVevaSVS.js";import"./ui-vendor-BuM9f2NY.js";import"./motion-vendor-g5fpGzmJ.js";function z(){const d=g(),c=u(s=>s.setToken),m=u(s=>s.setAuthMeta),[r,h]=a.useState(""),[t,p]=a.useState(!1),[o,n]=a.useState(!1),[i,l]=a.useState(null);async function x(s){s.preventDefault(),n(!0),l(null);try{await j({newPassword:r}),c("dashboard-session"),m({authenticated:!0,hasPassword:!0,requireLogin:!0}),d("/dashboard",{replace:!0})}catch(f){l(v(f,"Setup failed"))}finally{n(!1)}}return e.jsx("div",{className:"flex min-h-svh w-full items-center justify-center bg-background p-4",children:e.jsxs(y,{className:"w-full max-w-sm border-border bg-card",children:[e.jsxs(N,{className:"text-center",children:[e.jsx("img",{src:"/logo/sway.svg",alt:"Sway Router",className:"mx-auto mb-2 h-12 w-12 rounded-xl object-contain"}),e.jsx(C,{className:"text-xl",children:"Welcome to Sway Router"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Set your dashboard password"})]}),e.jsx(P,{children:e.jsxs("form",{onSubmit:x,className:"space-y-4",children:[e.jsxs("div",{className:"relative",children:[e.jsx(w,{type:t?"text":"password",placeholder:"Password",value:r,onChange:s=>h(s.target.value),required:!0,minLength:8,autoFocus:!0,className:"pr-10"}),e.jsx("button",{type:"button",onClick:()=>p(!t),className:"absolute right-1 top-1/2 grid size-8 -translate-y-1/2 place-items-center rounded-md text-muted-foreground transition-colors hover:bg-surface-hover hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring","aria-label":t?"Hide password":"Show password","aria-pressed":t,children:t?e.jsx(E,{className:"h-4 w-4"}):e.jsx(R,{className:"h-4 w-4"})})]}),i?e.jsx("p",{className:"text-sm text-destructive",children:i}):null,e.jsx(S,{type:"submit",className:"w-full",disabled:o,children:o?e.jsx(b,{children:"Setting up…"}):"Set Password & Continue"})]})})]})})}export{z as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./react-vendor-xnYrwzsL.js";import{c as u,h as n}from"./index-
|
|
1
|
+
import{j as e}from"./react-vendor-xnYrwzsL.js";import{c as u,h as n}from"./index-x5tLD3Ye.js";function g({tone:r,children:a,className:d,dotClassName:s,...t}){const o=u("size-1.5 rounded-full bg-muted-foreground/64",r==="ok"&&"bg-emerald-500",r==="warn"&&"bg-amber-500",r==="err"&&"bg-red-500",r==="muted"&&"bg-muted-foreground/64",s);return e.jsxs(n,{variant:"outline",className:d,...t,children:[e.jsx("span",{"aria-hidden":"true",className:o}),a]})}export{g as S};
|