diff --git a/cmd/capi/antigravity.go b/cmd/capi/antigravity.go index 6726444..6ae251d 100644 --- a/cmd/capi/antigravity.go +++ b/cmd/capi/antigravity.go @@ -98,6 +98,34 @@ func isAntigravityAccount(account OpenAIAccount) bool { return isAntigravitySource(account.Source) } +// isAntigravityChannel reports whether a channel is a first-class Antigravity +// account pool (provider == "antigravity"), which routes through the Google +// OAuth + Cloud Code path rather than the codex path. +func isAntigravityChannel(channel Channel) bool { + return isAntigravitySource(channel.Provider) +} + +// ensureAntigravityChannelLocked keeps an Antigravity channel's provider stable +// and registers its model catalog. It mirrors ensureCodexChannelLocked but for +// the Antigravity provider, so account import / periodic upkeep never rewrites +// it to codex. Callers must hold s.mu. +func (s *Server) ensureAntigravityChannelLocked(channel *Channel) bool { + if channel == nil { + return false + } + changed := false + if !strings.EqualFold(strings.TrimSpace(channel.Provider), "antigravity") { + channel.Provider = "antigravity" + changed = true + } + for _, modelID := range antigravityModelIDs() { + if s.ensureImportedModelLocked(modelID) { + changed = true + } + } + return changed +} + // checkAntigravityAccount validates an Antigravity account for the batch/health // check. It refreshes the Google token when needed and warms the project cache; // only a failed token refresh ejects the account, so a transient loadCodeAssist diff --git a/cmd/capi/antigravity_test.go b/cmd/capi/antigravity_test.go index 17e4148..28d497c 100644 --- a/cmd/capi/antigravity_test.go +++ b/cmd/capi/antigravity_test.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "strings" "testing" "github.com/gin-gonic/gin" @@ -153,3 +154,28 @@ func TestParseDataURL(t *testing.T) { t.Fatalf("non-base64 data URL should not parse") } } + +func TestAntigravityChannelIsNotCodex(t *testing.T) { + // A first-class Antigravity pool must route through the antigravity path, + // never the codex path, even once it holds accounts. + channel := Channel{Provider: "antigravity", OpenAIAccounts: []OpenAIAccount{{ID: "a", AccessToken: "x", Source: "antigravity"}}} + if !isAntigravityChannel(channel) { + t.Fatalf("expected antigravity channel") + } + if isCodexChannel(channel) { + t.Fatalf("antigravity channel must not be treated as codex") + } + codex := Channel{Provider: "codex", OpenAIAccounts: []OpenAIAccount{{ID: "b", AccessToken: "x"}}} + if isAntigravityChannel(codex) || !isCodexChannel(codex) { + t.Fatalf("codex channel classification regressed") + } +} + +func TestAntigravityClientSecretDecodes(t *testing.T) { + if antigravityOAuthClientSecret == "" { + t.Fatalf("client secret failed to decode") + } + if strings.ContainsAny(antigravityOAuthClientSecret, "\x00") { + t.Fatalf("client secret decoded to garbage") + } +} diff --git a/cmd/capi/main.go b/cmd/capi/main.go index c929ca8..a3e23fd 100644 --- a/cmd/capi/main.go +++ b/cmd/capi/main.go @@ -3200,6 +3200,11 @@ func (s *Server) importOpenAIAccounts(c *gin.Context) { } } for _, account := range accounts { + // Accounts imported into a first-class Antigravity pool are Antigravity + // accounts regardless of the file's declared source. + if isAntigravityChannel(*channel) && !isAntigravitySource(account.Source) { + account.Source = "antigravity" + } if strings.TrimSpace(account.AccessToken) == "" && strings.TrimSpace(account.SessionToken) != "" { account.AccessToken, account.ExpiresAt, _ = fetchChatGPTAccessTokenViaSessionCookie(account.SessionToken) } @@ -6934,6 +6939,9 @@ func chatCompletionUsageFromCodex(usage gin.H, messages []ChatMessage) gin.H { } func (s *Server) fetchUpstreamModelIDs(channel Channel, upstreamKey string) ([]string, error) { + if isAntigravityChannel(channel) { + return antigravityModelIDs(), nil + } if isCodexChannel(channel) { return codexChannelModelIDs(), nil } @@ -7934,6 +7942,9 @@ func (s *Server) shouldUseCompatibleProvider(channel Channel) bool { if strings.EqualFold(s.providerMode, "compatible") { return true } + if isAntigravityChannel(channel) && len(channel.OpenAIAccounts) > 0 { + return true + } if isCodexChannel(channel) && len(channel.OpenAIAccounts) > 0 { return true } @@ -9177,6 +9188,9 @@ func codexChannelModelIDs() []string { } func isCodexChannel(channel Channel) bool { + if isAntigravityChannel(channel) { + return false + } return strings.EqualFold(strings.TrimSpace(channel.Provider), "codex") || len(channel.OpenAIAccounts) > 0 } @@ -9184,6 +9198,10 @@ func (s *Server) ensureCodexChannelLocked(channel *Channel) bool { if channel == nil { return false } + // An Antigravity account pool is its own provider; never rewrite it to codex. + if isAntigravityChannel(*channel) { + return s.ensureAntigravityChannelLocked(channel) + } changed := false if !strings.EqualFold(strings.TrimSpace(channel.Provider), "codex") { channel.Provider = "codex" @@ -9268,6 +9286,8 @@ func providerLabel(provider string) string { switch strings.ToLower(strings.TrimSpace(provider)) { case "codex": return "Codex" + case "antigravity", "agy", "google-antigravity": + return "Antigravity" case "cpa", "cliproxyapi", "cli-proxy-api": return "CLIProxyAPI" case "openai": @@ -10572,7 +10592,11 @@ func (s *Server) normalizeStateCollections() bool { s.state.Channels[i].Models = []string{} changed = true } - if isCodexChannel(s.state.Channels[i]) { + if isAntigravityChannel(s.state.Channels[i]) { + if s.ensureAntigravityChannelLocked(&s.state.Channels[i]) { + changed = true + } + } else if isCodexChannel(s.state.Channels[i]) { if s.ensureCodexChannelLocked(&s.state.Channels[i]) { changed = true } diff --git a/dist/assets/index-B2BgeCFL.js b/dist/assets/index-B9-tgVyd.js similarity index 54% rename from dist/assets/index-B2BgeCFL.js rename to dist/assets/index-B9-tgVyd.js index 70beaf7..ccd44ce 100644 --- a/dist/assets/index-B2BgeCFL.js +++ b/dist/assets/index-B9-tgVyd.js @@ -1,12 +1,12 @@ -(function(){const m=document.createElement("link").relList;if(m&&m.supports&&m.supports("modulepreload"))return;for(const A of document.querySelectorAll('link[rel="modulepreload"]'))r(A);new MutationObserver(A=>{for(const E of A)if(E.type==="childList")for(const L of E.addedNodes)L.tagName==="LINK"&&L.rel==="modulepreload"&&r(L)}).observe(document,{childList:!0,subtree:!0});function h(A){const E={};return A.integrity&&(E.integrity=A.integrity),A.referrerPolicy&&(E.referrerPolicy=A.referrerPolicy),A.crossOrigin==="use-credentials"?E.credentials="include":A.crossOrigin==="anonymous"?E.credentials="omit":E.credentials="same-origin",E}function r(A){if(A.ep)return;A.ep=!0;const E=h(A);fetch(A.href,E)}})();function H0(c){return c&&c.__esModule&&Object.prototype.hasOwnProperty.call(c,"default")?c.default:c}var Qc={exports:{}},is={};var em;function B0(){if(em)return is;em=1;var c=Symbol.for("react.transitional.element"),m=Symbol.for("react.fragment");function h(r,A,E){var L=null;if(E!==void 0&&(L=""+E),A.key!==void 0&&(L=""+A.key),"key"in A){E={};for(var $ in A)$!=="key"&&(E[$]=A[$])}else E=A;return A=E.ref,{$$typeof:c,type:r,key:L,ref:A!==void 0?A:null,props:E}}return is.Fragment=m,is.jsx=h,is.jsxs=h,is}var tm;function q0(){return tm||(tm=1,Qc.exports=B0()),Qc.exports}var n=q0(),Xc={exports:{}},Ce={};var lm;function G0(){if(lm)return Ce;lm=1;var c=Symbol.for("react.transitional.element"),m=Symbol.for("react.portal"),h=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),A=Symbol.for("react.profiler"),E=Symbol.for("react.consumer"),L=Symbol.for("react.context"),$=Symbol.for("react.forward_ref"),C=Symbol.for("react.suspense"),y=Symbol.for("react.memo"),R=Symbol.for("react.lazy"),z=Symbol.for("react.activity"),P=Symbol.iterator;function ee(d){return d===null||typeof d!="object"?null:(d=P&&d[P]||d["@@iterator"],typeof d=="function"?d:null)}var de={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},ne=Object.assign,le={};function ie(d,x,G){this.props=d,this.context=x,this.refs=le,this.updater=G||de}ie.prototype.isReactComponent={},ie.prototype.setState=function(d,x){if(typeof d!="object"&&typeof d!="function"&&d!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,d,x,"setState")},ie.prototype.forceUpdate=function(d){this.updater.enqueueForceUpdate(this,d,"forceUpdate")};function xe(){}xe.prototype=ie.prototype;function Y(d,x,G){this.props=d,this.context=x,this.refs=le,this.updater=G||de}var ge=Y.prototype=new xe;ge.constructor=Y,ne(ge,ie.prototype),ge.isPureReactComponent=!0;var F=Array.isArray;function me(){}var D={H:null,A:null,T:null,S:null},ae=Object.prototype.hasOwnProperty;function fe(d,x,G){var X=G.ref;return{$$typeof:c,type:d,key:x,ref:X!==void 0?X:null,props:G}}function Ae(d,x){return fe(d.type,x,d.props)}function Te(d){return typeof d=="object"&&d!==null&&d.$$typeof===c}function ue(d){var x={"=":"=0",":":"=2"};return"$"+d.replace(/[=:]/g,function(G){return x[G]})}var Z=/\/+/g;function re(d,x){return typeof d=="object"&&d!==null&&d.key!=null?ue(""+d.key):x.toString(36)}function J(d){switch(d.status){case"fulfilled":return d.value;case"rejected":throw d.reason;default:switch(typeof d.status=="string"?d.then(me,me):(d.status="pending",d.then(function(x){d.status==="pending"&&(d.status="fulfilled",d.value=x)},function(x){d.status==="pending"&&(d.status="rejected",d.reason=x)})),d.status){case"fulfilled":return d.value;case"rejected":throw d.reason}}throw d}function T(d,x,G,X,se){var ve=typeof d;(ve==="undefined"||ve==="boolean")&&(d=null);var N=!1;if(d===null)N=!0;else switch(ve){case"bigint":case"string":case"number":N=!0;break;case"object":switch(d.$$typeof){case c:case m:N=!0;break;case R:return N=d._init,T(N(d._payload),x,G,X,se)}}if(N)return se=se(d),N=X===""?"."+re(d,0):X,F(se)?(G="",N!=null&&(G=N.replace(Z,"$&/")+"/"),T(se,x,G,"",function(bt){return bt})):se!=null&&(Te(se)&&(se=Ae(se,G+(se.key==null||d&&d.key===se.key?"":(""+se.key).replace(Z,"$&/")+"/")+N)),x.push(se)),1;N=0;var Ne=X===""?".":X+":";if(F(d))for(var Se=0;Se>>1,O=T[Q];if(0>>1;QA(G,B))XA(se,G)?(T[Q]=se,T[X]=B,Q=X):(T[Q]=G,T[x]=B,Q=x);else if(XA(se,B))T[Q]=se,T[X]=B,Q=X;else break e}}return k}function A(T,k){var B=T.sortIndex-k.sortIndex;return B!==0?B:T.id-k.id}if(c.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var E=performance;c.unstable_now=function(){return E.now()}}else{var L=Date,$=L.now();c.unstable_now=function(){return L.now()-$}}var C=[],y=[],R=1,z=null,P=3,ee=!1,de=!1,ne=!1,le=!1,ie=typeof setTimeout=="function"?setTimeout:null,xe=typeof clearTimeout=="function"?clearTimeout:null,Y=typeof setImmediate<"u"?setImmediate:null;function ge(T){for(var k=h(y);k!==null;){if(k.callback===null)r(y);else if(k.startTime<=T)r(y),k.sortIndex=k.expirationTime,m(C,k);else break;k=h(y)}}function F(T){if(ne=!1,ge(T),!de)if(h(C)!==null)de=!0,me||(me=!0,ue());else{var k=h(y);k!==null&&J(F,k.startTime-T)}}var me=!1,D=-1,ae=5,fe=-1;function Ae(){return le?!0:!(c.unstable_now()-feT&&Ae());){var Q=z.callback;if(typeof Q=="function"){z.callback=null,P=z.priorityLevel;var O=Q(z.expirationTime<=T);if(T=c.unstable_now(),typeof O=="function"){z.callback=O,ge(T),k=!0;break t}z===h(C)&&r(C),ge(T)}else r(C);z=h(C)}if(z!==null)k=!0;else{var d=h(y);d!==null&&J(F,d.startTime-T),k=!1}}break e}finally{z=null,P=B,ee=!1}k=void 0}}finally{k?ue():me=!1}}}var ue;if(typeof Y=="function")ue=function(){Y(Te)};else if(typeof MessageChannel<"u"){var Z=new MessageChannel,re=Z.port2;Z.port1.onmessage=Te,ue=function(){re.postMessage(null)}}else ue=function(){ie(Te,0)};function J(T,k){D=ie(function(){T(c.unstable_now())},k)}c.unstable_IdlePriority=5,c.unstable_ImmediatePriority=1,c.unstable_LowPriority=4,c.unstable_NormalPriority=3,c.unstable_Profiling=null,c.unstable_UserBlockingPriority=2,c.unstable_cancelCallback=function(T){T.callback=null},c.unstable_forceFrameRate=function(T){0>T||125Q?(T.sortIndex=B,m(y,T),h(C)===null&&T===h(y)&&(ne?(xe(D),D=-1):ne=!0,J(F,B-Q))):(T.sortIndex=O,m(C,T),de||ee||(de=!0,me||(me=!0,ue()))),T},c.unstable_shouldYield=Ae,c.unstable_wrapCallback=function(T){var k=P;return function(){var B=P;P=k;try{return T.apply(this,arguments)}finally{P=B}}}})(Vc)),Vc}var sm;function k0(){return sm||(sm=1,Zc.exports=L0()),Zc.exports}var Jc={exports:{}},gt={};var im;function Q0(){if(im)return gt;im=1;var c=Pc();function m(C){var y="https://react.dev/errors/"+C;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(c)}catch(m){console.error(m)}}return c(),Jc.exports=Q0(),Jc.exports}var cm;function K0(){if(cm)return us;cm=1;var c=k0(),m=Pc(),h=X0();function r(e){var t="https://react.dev/errors/"+e;if(1O||(e.current=Q[O],Q[O]=null,O--)}function G(e,t){O++,Q[O]=e.current,e.current=t}var X=d(null),se=d(null),ve=d(null),N=d(null);function Ne(e,t){switch(G(ve,t),G(se,e),G(X,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Nf(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Nf(t),e=Af(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}x(X),G(X,e)}function Se(){x(X),x(se),x(ve)}function bt(e){e.memoizedState!==null&&G(N,e);var t=X.current,l=Af(t,e.type);t!==l&&(G(se,e),G(X,l))}function I(e){se.current===e&&(x(X),x(se)),N.current===e&&(x(N),ls._currentValue=B)}var Ke,We;function Pe(e){if(Ke===void 0)try{throw Error()}catch(l){var t=l.stack.trim().match(/\n( *(at )?)/);Ke=t&&t[1]||"",We=-1{for(const E of A)if(E.type==="childList")for(const L of E.addedNodes)L.tagName==="LINK"&&L.rel==="modulepreload"&&r(L)}).observe(document,{childList:!0,subtree:!0});function h(A){const E={};return A.integrity&&(E.integrity=A.integrity),A.referrerPolicy&&(E.referrerPolicy=A.referrerPolicy),A.crossOrigin==="use-credentials"?E.credentials="include":A.crossOrigin==="anonymous"?E.credentials="omit":E.credentials="same-origin",E}function r(A){if(A.ep)return;A.ep=!0;const E=h(A);fetch(A.href,E)}})();function B0(u){return u&&u.__esModule&&Object.prototype.hasOwnProperty.call(u,"default")?u.default:u}var Qc={exports:{}},is={};var tm;function q0(){if(tm)return is;tm=1;var u=Symbol.for("react.transitional.element"),m=Symbol.for("react.fragment");function h(r,A,E){var L=null;if(E!==void 0&&(L=""+E),A.key!==void 0&&(L=""+A.key),"key"in A){E={};for(var $ in A)$!=="key"&&(E[$]=A[$])}else E=A;return A=E.ref,{$$typeof:u,type:r,key:L,ref:A!==void 0?A:null,props:E}}return is.Fragment=m,is.jsx=h,is.jsxs=h,is}var lm;function G0(){return lm||(lm=1,Qc.exports=q0()),Qc.exports}var n=G0(),Xc={exports:{}},Ce={};var am;function Y0(){if(am)return Ce;am=1;var u=Symbol.for("react.transitional.element"),m=Symbol.for("react.portal"),h=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),A=Symbol.for("react.profiler"),E=Symbol.for("react.consumer"),L=Symbol.for("react.context"),$=Symbol.for("react.forward_ref"),C=Symbol.for("react.suspense"),y=Symbol.for("react.memo"),R=Symbol.for("react.lazy"),z=Symbol.for("react.activity"),P=Symbol.iterator;function ee(d){return d===null||typeof d!="object"?null:(d=P&&d[P]||d["@@iterator"],typeof d=="function"?d:null)}var de={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},ne=Object.assign,le={};function ie(d,x,G){this.props=d,this.context=x,this.refs=le,this.updater=G||de}ie.prototype.isReactComponent={},ie.prototype.setState=function(d,x){if(typeof d!="object"&&typeof d!="function"&&d!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,d,x,"setState")},ie.prototype.forceUpdate=function(d){this.updater.enqueueForceUpdate(this,d,"forceUpdate")};function xe(){}xe.prototype=ie.prototype;function Y(d,x,G){this.props=d,this.context=x,this.refs=le,this.updater=G||de}var ge=Y.prototype=new xe;ge.constructor=Y,ne(ge,ie.prototype),ge.isPureReactComponent=!0;var F=Array.isArray;function me(){}var D={H:null,A:null,T:null,S:null},ae=Object.prototype.hasOwnProperty;function fe(d,x,G){var X=G.ref;return{$$typeof:u,type:d,key:x,ref:X!==void 0?X:null,props:G}}function Ae(d,x){return fe(d.type,x,d.props)}function Te(d){return typeof d=="object"&&d!==null&&d.$$typeof===u}function ue(d){var x={"=":"=0",":":"=2"};return"$"+d.replace(/[=:]/g,function(G){return x[G]})}var Z=/\/+/g;function re(d,x){return typeof d=="object"&&d!==null&&d.key!=null?ue(""+d.key):x.toString(36)}function J(d){switch(d.status){case"fulfilled":return d.value;case"rejected":throw d.reason;default:switch(typeof d.status=="string"?d.then(me,me):(d.status="pending",d.then(function(x){d.status==="pending"&&(d.status="fulfilled",d.value=x)},function(x){d.status==="pending"&&(d.status="rejected",d.reason=x)})),d.status){case"fulfilled":return d.value;case"rejected":throw d.reason}}throw d}function T(d,x,G,X,se){var ve=typeof d;(ve==="undefined"||ve==="boolean")&&(d=null);var N=!1;if(d===null)N=!0;else switch(ve){case"bigint":case"string":case"number":N=!0;break;case"object":switch(d.$$typeof){case u:case m:N=!0;break;case R:return N=d._init,T(N(d._payload),x,G,X,se)}}if(N)return se=se(d),N=X===""?"."+re(d,0):X,F(se)?(G="",N!=null&&(G=N.replace(Z,"$&/")+"/"),T(se,x,G,"",function(bt){return bt})):se!=null&&(Te(se)&&(se=Ae(se,G+(se.key==null||d&&d.key===se.key?"":(""+se.key).replace(Z,"$&/")+"/")+N)),x.push(se)),1;N=0;var Ne=X===""?".":X+":";if(F(d))for(var Se=0;Se>>1,O=T[Q];if(0>>1;QA(G,B))XA(se,G)?(T[Q]=se,T[X]=B,Q=X):(T[Q]=G,T[x]=B,Q=x);else if(XA(se,B))T[Q]=se,T[X]=B,Q=X;else break e}}return k}function A(T,k){var B=T.sortIndex-k.sortIndex;return B!==0?B:T.id-k.id}if(u.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var E=performance;u.unstable_now=function(){return E.now()}}else{var L=Date,$=L.now();u.unstable_now=function(){return L.now()-$}}var C=[],y=[],R=1,z=null,P=3,ee=!1,de=!1,ne=!1,le=!1,ie=typeof setTimeout=="function"?setTimeout:null,xe=typeof clearTimeout=="function"?clearTimeout:null,Y=typeof setImmediate<"u"?setImmediate:null;function ge(T){for(var k=h(y);k!==null;){if(k.callback===null)r(y);else if(k.startTime<=T)r(y),k.sortIndex=k.expirationTime,m(C,k);else break;k=h(y)}}function F(T){if(ne=!1,ge(T),!de)if(h(C)!==null)de=!0,me||(me=!0,ue());else{var k=h(y);k!==null&&J(F,k.startTime-T)}}var me=!1,D=-1,ae=5,fe=-1;function Ae(){return le?!0:!(u.unstable_now()-feT&&Ae());){var Q=z.callback;if(typeof Q=="function"){z.callback=null,P=z.priorityLevel;var O=Q(z.expirationTime<=T);if(T=u.unstable_now(),typeof O=="function"){z.callback=O,ge(T),k=!0;break t}z===h(C)&&r(C),ge(T)}else r(C);z=h(C)}if(z!==null)k=!0;else{var d=h(y);d!==null&&J(F,d.startTime-T),k=!1}}break e}finally{z=null,P=B,ee=!1}k=void 0}}finally{k?ue():me=!1}}}var ue;if(typeof Y=="function")ue=function(){Y(Te)};else if(typeof MessageChannel<"u"){var Z=new MessageChannel,re=Z.port2;Z.port1.onmessage=Te,ue=function(){re.postMessage(null)}}else ue=function(){ie(Te,0)};function J(T,k){D=ie(function(){T(u.unstable_now())},k)}u.unstable_IdlePriority=5,u.unstable_ImmediatePriority=1,u.unstable_LowPriority=4,u.unstable_NormalPriority=3,u.unstable_Profiling=null,u.unstable_UserBlockingPriority=2,u.unstable_cancelCallback=function(T){T.callback=null},u.unstable_forceFrameRate=function(T){0>T||125Q?(T.sortIndex=B,m(y,T),h(C)===null&&T===h(y)&&(ne?(xe(D),D=-1):ne=!0,J(F,B-Q))):(T.sortIndex=O,m(C,T),de||ee||(de=!0,me||(me=!0,ue()))),T},u.unstable_shouldYield=Ae,u.unstable_wrapCallback=function(T){var k=P;return function(){var B=P;P=k;try{return T.apply(this,arguments)}finally{P=B}}}})(Vc)),Vc}var im;function Q0(){return im||(im=1,Zc.exports=k0()),Zc.exports}var Jc={exports:{}},gt={};var um;function X0(){if(um)return gt;um=1;var u=eo();function m(C){var y="https://react.dev/errors/"+C;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(u)}catch(m){console.error(m)}}return u(),Jc.exports=X0(),Jc.exports}var om;function Z0(){if(om)return us;om=1;var u=Q0(),m=eo(),h=K0();function r(e){var t="https://react.dev/errors/"+e;if(1O||(e.current=Q[O],Q[O]=null,O--)}function G(e,t){O++,Q[O]=e.current,e.current=t}var X=d(null),se=d(null),ve=d(null),N=d(null);function Ne(e,t){switch(G(ve,t),G(se,e),G(X,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Af(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Af(t),e=Cf(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}x(X),G(X,e)}function Se(){x(X),x(se),x(ve)}function bt(e){e.memoizedState!==null&&G(N,e);var t=X.current,l=Cf(t,e.type);t!==l&&(G(se,e),G(X,l))}function I(e){se.current===e&&(x(X),x(se)),N.current===e&&(x(N),ls._currentValue=B)}var Ke,We;function Pe(e){if(Ke===void 0)try{throw Error()}catch(l){var t=l.stack.trim().match(/\n( *(at )?)/);Ke=t&&t[1]||"",We=-1)":-1s||f[a]!==j[s]){var U=` `+f[a].replace(" at new "," at ");return e.displayName&&U.includes("")&&(U=U.replace("",e.displayName)),U}while(1<=a&&0<=s);break}}}finally{tl=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?Pe(l):""}function cl(e,t){switch(e.tag){case 26:case 27:case 5:return Pe(e.type);case 16:return Pe("Lazy");case 13:return e.child!==t&&t!==null?Pe("Suspense Fallback"):Pe("Suspense");case 19:return Pe("SuspenseList");case 0:case 15:return kt(e.type,!1);case 11:return kt(e.type.render,!1);case 1:return kt(e.type,!0);case 31:return Pe("Activity");default:return""}}function V(e){try{var t="",l=null;do t+=cl(e,l),l=e,e=e.return;while(e);return t}catch(a){return` Error generating stack: `+a.message+` -`+a.stack}}var _=Object.prototype.hasOwnProperty,Ee=c.unstable_scheduleCallback,et=c.unstable_cancelCallback,xt=c.unstable_shouldYield,ft=c.unstable_requestPaint,tt=c.unstable_now,zi=c.unstable_getCurrentPriorityLevel,hn=c.unstable_ImmediatePriority,ia=c.unstable_UserBlockingPriority,ua=c.unstable_NormalPriority,Oi=c.unstable_LowPriority,w=c.unstable_IdlePriority,K=c.log,te=c.unstable_setDisableYieldValue,W=null,ye=null;function qe(e){if(typeof K=="function"&&te(e),ye&&typeof ye.setStrictMode=="function")try{ye.setStrictMode(W,e)}catch{}}var Ze=Math.clz32?Math.clz32:ca,Ut=Math.log,Rl=Math.LN2;function ca(e){return e>>>=0,e===0?32:31-(Ut(e)/Rl|0)|0}var Ea=256,Ma=262144,wl=4194304;function hl(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function os(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var s=0,i=e.suspendedLanes,u=e.pingedLanes;e=e.warmLanes;var o=a&134217727;return o!==0?(a=o&~i,a!==0?s=hl(a):(u&=o,u!==0?s=hl(u):l||(l=o&~e,l!==0&&(s=hl(l))))):(o=a&~i,o!==0?s=hl(o):u!==0?s=hl(u):l||(l=a&~e,l!==0&&(s=hl(l)))),s===0?0:t!==0&&t!==s&&(t&i)===0&&(i=s&-s,l=t&-t,i>=l||i===32&&(l&4194048)!==0)?t:s}function pn(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Nm(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function lo(){var e=wl;return wl<<=1,(wl&62914560)===0&&(wl=4194304),e}function _i(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function vn(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Am(e,t,l,a,s,i){var u=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var o=e.entanglements,f=e.expirationTimes,j=e.hiddenUpdates;for(l=u&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var Om=/[\n"\\]/g;function Xt(e){return e.replace(Om,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function Bi(e,t,l,a,s,i,u,o){e.name="",u!=null&&typeof u!="function"&&typeof u!="symbol"&&typeof u!="boolean"?e.type=u:e.removeAttribute("type"),t!=null?u==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+Qt(t)):e.value!==""+Qt(t)&&(e.value=""+Qt(t)):u!=="submit"&&u!=="reset"||e.removeAttribute("value"),t!=null?qi(e,u,Qt(t)):l!=null?qi(e,u,Qt(l)):a!=null&&e.removeAttribute("value"),s==null&&i!=null&&(e.defaultChecked=!!i),s!=null&&(e.checked=s&&typeof s!="function"&&typeof s!="symbol"),o!=null&&typeof o!="function"&&typeof o!="symbol"&&typeof o!="boolean"?e.name=""+Qt(o):e.removeAttribute("name")}function vo(e,t,l,a,s,i,u,o){if(i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"&&(e.type=i),t!=null||l!=null){if(!(i!=="submit"&&i!=="reset"||t!=null)){Hi(e);return}l=l!=null?""+Qt(l):"",t=t!=null?""+Qt(t):l,o||t===e.value||(e.value=t),e.defaultValue=t}a=a??s,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=o?e.checked:!!a,e.defaultChecked=!!a,u!=null&&typeof u!="function"&&typeof u!="symbol"&&typeof u!="boolean"&&(e.name=u),Hi(e)}function qi(e,t,l){t==="number"&&fs(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function Ra(e,t,l,a){if(e=e.options,t){t={};for(var s=0;s"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Qi=!1;if(yl)try{var xn={};Object.defineProperty(xn,"passive",{get:function(){Qi=!0}}),window.addEventListener("test",xn,xn),window.removeEventListener("test",xn,xn)}catch{Qi=!1}var Bl=null,Xi=null,hs=null;function No(){if(hs)return hs;var e,t=Xi,l=t.length,a,s="value"in Bl?Bl.value:Bl.textContent,i=s.length;for(e=0;e=Nn),zo=" ",Oo=!1;function _o(e,t){switch(e){case"keyup":return nh.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Do(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var qa=!1;function ih(e,t){switch(e){case"compositionend":return Do(t);case"keypress":return t.which!==32?null:(Oo=!0,zo);case"textInput":return e=t.data,e===zo&&Oo?null:e;default:return null}}function uh(e,t){if(qa)return e==="compositionend"||!$i&&_o(e,t)?(e=No(),hs=Xi=Bl=null,qa=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Yo(l)}}function ko(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?ko(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Qo(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=fs(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=fs(e.document)}return t}function Ii(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var ph=yl&&"documentMode"in document&&11>=document.documentMode,Ga=null,Pi=null,En=null,eu=!1;function Xo(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;eu||Ga==null||Ga!==fs(a)||(a=Ga,"selectionStart"in a&&Ii(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),En&&Tn(En,a)||(En=a,a=ui(Pi,"onSelect"),0>=u,s-=u,ol=1<<32-Ze(t)+s|l<ze?(Ue=oe,oe=null):Ue=oe.sibling;var He=S(v,oe,b[ze],H);if(He===null){oe===null&&(oe=Ue);break}e&&oe&&He.alternate===null&&t(v,oe),p=i(He,p,ze),we===null?he=He:we.sibling=He,we=He,oe=Ue}if(ze===b.length)return l(v,oe),Re&&bl(v,ze),he;if(oe===null){for(;zeze?(Ue=oe,oe=null):Ue=oe.sibling;var sa=S(v,oe,He.value,H);if(sa===null){oe===null&&(oe=Ue);break}e&&oe&&sa.alternate===null&&t(v,oe),p=i(sa,p,ze),we===null?he=sa:we.sibling=sa,we=sa,oe=Ue}if(He.done)return l(v,oe),Re&&bl(v,ze),he;if(oe===null){for(;!He.done;ze++,He=b.next())He=q(v,He.value,H),He!==null&&(p=i(He,p,ze),we===null?he=He:we.sibling=He,we=He);return Re&&bl(v,ze),he}for(oe=a(oe);!He.done;ze++,He=b.next())He=M(oe,v,ze,He.value,H),He!==null&&(e&&He.alternate!==null&&oe.delete(He.key===null?ze:He.key),p=i(He,p,ze),we===null?he=He:we.sibling=He,we=He);return e&&oe.forEach(function(w0){return t(v,w0)}),Re&&bl(v,ze),he}function Qe(v,p,b,H){if(typeof b=="object"&&b!==null&&b.type===ne&&b.key===null&&(b=b.props.children),typeof b=="object"&&b!==null){switch(b.$$typeof){case ee:e:{for(var he=b.key;p!==null;){if(p.key===he){if(he=b.type,he===ne){if(p.tag===7){l(v,p.sibling),H=s(p,b.props.children),H.return=v,v=H;break e}}else if(p.elementType===he||typeof he=="object"&&he!==null&&he.$$typeof===ae&&ba(he)===p.type){l(v,p.sibling),H=s(p,b.props),Un(H,b),H.return=v,v=H;break e}l(v,p);break}else t(v,p);p=p.sibling}b.type===ne?(H=ha(b.props.children,v.mode,H,b.key),H.return=v,v=H):(H=As(b.type,b.key,b.props,null,v.mode,H),Un(H,b),H.return=v,v=H)}return u(v);case de:e:{for(he=b.key;p!==null;){if(p.key===he)if(p.tag===4&&p.stateNode.containerInfo===b.containerInfo&&p.stateNode.implementation===b.implementation){l(v,p.sibling),H=s(p,b.children||[]),H.return=v,v=H;break e}else{l(v,p);break}else t(v,p);p=p.sibling}H=uu(b,v.mode,H),H.return=v,v=H}return u(v);case ae:return b=ba(b),Qe(v,p,b,H)}if(J(b))return ce(v,p,b,H);if(ue(b)){if(he=ue(b),typeof he!="function")throw Error(r(150));return b=he.call(b),je(v,p,b,H)}if(typeof b.then=="function")return Qe(v,p,_s(b),H);if(b.$$typeof===Y)return Qe(v,p,Es(v,b),H);Ds(v,b)}return typeof b=="string"&&b!==""||typeof b=="number"||typeof b=="bigint"?(b=""+b,p!==null&&p.tag===6?(l(v,p.sibling),H=s(p,b),H.return=v,v=H):(l(v,p),H=iu(b,v.mode,H),H.return=v,v=H),u(v)):l(v,p)}return function(v,p,b,H){try{Dn=0;var he=Qe(v,p,b,H);return Wa=null,he}catch(oe){if(oe===$a||oe===zs)throw oe;var we=wt(29,oe,null,v.mode);return we.lanes=H,we.return=v,we}}}var ja=mr(!0),hr=mr(!1),kl=!1;function bu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function xu(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ql(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Xl(e,t,l){var a=e.updateQueue;if(a===null)return null;if(a=a.shared,(Be&2)!==0){var s=a.pending;return s===null?t.next=t:(t.next=s.next,s.next=t),a.pending=t,t=Ns(e),Fo(e,null,l),t}return Ss(e,a,t,l),Ns(e)}function Rn(e,t,l){if(t=t.updateQueue,t!==null&&(t=t.shared,(l&4194048)!==0)){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,no(e,l)}}function ju(e,t){var l=e.updateQueue,a=e.alternate;if(a!==null&&(a=a.updateQueue,l===a)){var s=null,i=null;if(l=l.firstBaseUpdate,l!==null){do{var u={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};i===null?s=i=u:i=i.next=u,l=l.next}while(l!==null);i===null?s=i=t:i=i.next=t}else s=i=t;l={baseState:a.baseState,firstBaseUpdate:s,lastBaseUpdate:i,shared:a.shared,callbacks:a.callbacks},e.updateQueue=l;return}e=l.lastBaseUpdate,e===null?l.firstBaseUpdate=t:e.next=t,l.lastBaseUpdate=t}var Su=!1;function wn(){if(Su){var e=Ja;if(e!==null)throw e}}function Hn(e,t,l,a){Su=!1;var s=e.updateQueue;kl=!1;var i=s.firstBaseUpdate,u=s.lastBaseUpdate,o=s.shared.pending;if(o!==null){s.shared.pending=null;var f=o,j=f.next;f.next=null,u===null?i=j:u.next=j,u=f;var U=e.alternate;U!==null&&(U=U.updateQueue,o=U.lastBaseUpdate,o!==u&&(o===null?U.firstBaseUpdate=j:o.next=j,U.lastBaseUpdate=f))}if(i!==null){var q=s.baseState;u=0,U=j=f=null,o=i;do{var S=o.lane&-536870913,M=S!==o.lane;if(M?(De&S)===S:(a&S)===S){S!==0&&S===Va&&(Su=!0),U!==null&&(U=U.next={lane:0,tag:o.tag,payload:o.payload,callback:null,next:null});e:{var ce=e,je=o;S=t;var Qe=l;switch(je.tag){case 1:if(ce=je.payload,typeof ce=="function"){q=ce.call(Qe,q,S);break e}q=ce;break e;case 3:ce.flags=ce.flags&-65537|128;case 0:if(ce=je.payload,S=typeof ce=="function"?ce.call(Qe,q,S):ce,S==null)break e;q=z({},q,S);break e;case 2:kl=!0}}S=o.callback,S!==null&&(e.flags|=64,M&&(e.flags|=8192),M=s.callbacks,M===null?s.callbacks=[S]:M.push(S))}else M={lane:S,tag:o.tag,payload:o.payload,callback:o.callback,next:null},U===null?(j=U=M,f=q):U=U.next=M,u|=S;if(o=o.next,o===null){if(o=s.shared.pending,o===null)break;M=o,o=M.next,M.next=null,s.lastBaseUpdate=M,s.shared.pending=null}}while(!0);U===null&&(f=q),s.baseState=f,s.firstBaseUpdate=j,s.lastBaseUpdate=U,i===null&&(s.shared.lanes=0),$l|=u,e.lanes=u,e.memoizedState=q}}function pr(e,t){if(typeof e!="function")throw Error(r(191,e));e.call(t)}function vr(e,t){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;ei?i:8;var u=T.T,o={};T.T=o,Lu(e,!1,t,l);try{var f=s(),j=T.S;if(j!==null&&j(o,f),f!==null&&typeof f=="object"&&typeof f.then=="function"){var U=Ah(f,a);Gn(e,t,U,Yt(e))}else Gn(e,t,a,Yt(e))}catch(q){Gn(e,t,{then:function(){},status:"rejected",reason:q},Yt())}finally{k.p=i,u!==null&&o.types!==null&&(u.types=o.types),T.T=u}}function Oh(){}function Gu(e,t,l,a){if(e.tag!==5)throw Error(r(476));var s=Jr(e).queue;Vr(e,s,t,B,l===null?Oh:function(){return $r(e),l(a)})}function Jr(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:B,baseState:B,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Nl,lastRenderedState:B},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Nl,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function $r(e){var t=Jr(e);t.next===null&&(t=e.alternate.memoizedState),Gn(e,t.next.queue,{},Yt())}function Yu(){return pt(ls)}function Wr(){return at().memoizedState}function Fr(){return at().memoizedState}function _h(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=Yt();e=Ql(l);var a=Xl(t,e,l);a!==null&&(zt(a,t,l),Rn(a,t,l)),t={cache:pu()},e.payload=t;return}t=t.return}}function Dh(e,t,l){var a=Yt();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},ks(e)?Pr(t,l):(l=nu(e,t,l,a),l!==null&&(zt(l,e,a),ed(l,t,a)))}function Ir(e,t,l){var a=Yt();Gn(e,t,l,a)}function Gn(e,t,l,a){var s={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(ks(e))Pr(t,s);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var u=t.lastRenderedState,o=i(u,l);if(s.hasEagerState=!0,s.eagerState=o,Rt(o,u))return Ss(e,t,s,0),Xe===null&&js(),!1}catch{}if(l=nu(e,t,s,a),l!==null)return zt(l,e,a),ed(l,t,a),!0}return!1}function Lu(e,t,l,a){if(a={lane:2,revertLane:bc(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},ks(e)){if(t)throw Error(r(479))}else t=nu(e,l,a,2),t!==null&&zt(t,e,2)}function ks(e){var t=e.alternate;return e===Me||t!==null&&t===Me}function Pr(e,t){Ia=ws=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function ed(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,no(e,l)}}var Yn={readContext:pt,use:qs,useCallback:Fe,useContext:Fe,useEffect:Fe,useImperativeHandle:Fe,useLayoutEffect:Fe,useInsertionEffect:Fe,useMemo:Fe,useReducer:Fe,useRef:Fe,useState:Fe,useDebugValue:Fe,useDeferredValue:Fe,useTransition:Fe,useSyncExternalStore:Fe,useId:Fe,useHostTransitionStatus:Fe,useFormState:Fe,useActionState:Fe,useOptimistic:Fe,useMemoCache:Fe,useCacheRefresh:Fe};Yn.useEffectEvent=Fe;var td={readContext:pt,use:qs,useCallback:function(e,t){return jt().memoizedState=[e,t===void 0?null:t],e},useContext:pt,useEffect:qr,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,Ys(4194308,4,kr.bind(null,t,e),l)},useLayoutEffect:function(e,t){return Ys(4194308,4,e,t)},useInsertionEffect:function(e,t){Ys(4,2,e,t)},useMemo:function(e,t){var l=jt();t=t===void 0?null:t;var a=e();if(Sa){qe(!0);try{e()}finally{qe(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=jt();if(l!==void 0){var s=l(t);if(Sa){qe(!0);try{l(t)}finally{qe(!1)}}}else s=t;return a.memoizedState=a.baseState=s,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:s},a.queue=e,e=e.dispatch=Dh.bind(null,Me,e),[a.memoizedState,e]},useRef:function(e){var t=jt();return e={current:e},t.memoizedState=e},useState:function(e){e=Ru(e);var t=e.queue,l=Ir.bind(null,Me,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:Bu,useDeferredValue:function(e,t){var l=jt();return qu(l,e,t)},useTransition:function(){var e=Ru(!1);return e=Vr.bind(null,Me,e.queue,!0,!1),jt().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=Me,s=jt();if(Re){if(l===void 0)throw Error(r(407));l=l()}else{if(l=t(),Xe===null)throw Error(r(349));(De&127)!==0||Sr(a,t,l)}s.memoizedState=l;var i={value:l,getSnapshot:t};return s.queue=i,qr(Ar.bind(null,a,i,e),[e]),a.flags|=2048,en(9,{destroy:void 0},Nr.bind(null,a,i,l,t),null),l},useId:function(){var e=jt(),t=Xe.identifierPrefix;if(Re){var l=rl,a=ol;l=(a&~(1<<32-Ze(a)-1)).toString(32)+l,t="_"+t+"R_"+l,l=Hs++,0<\/script>",i=i.removeChild(i.firstChild);break;case"select":i=typeof a.is=="string"?u.createElement("select",{is:a.is}):u.createElement("select"),a.multiple?i.multiple=!0:a.size&&(i.size=a.size);break;default:i=typeof a.is=="string"?u.createElement(s,{is:a.is}):u.createElement(s)}}i[mt]=t,i[Nt]=a;e:for(u=t.child;u!==null;){if(u.tag===5||u.tag===6)i.appendChild(u.stateNode);else if(u.tag!==4&&u.tag!==27&&u.child!==null){u.child.return=u,u=u.child;continue}if(u===t)break e;for(;u.sibling===null;){if(u.return===null||u.return===t)break e;u=u.return}u.sibling.return=u.return,u=u.sibling}t.stateNode=i;e:switch(yt(i,s,a),s){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break e;case"img":a=!0;break e;default:a=!1}a&&Cl(t)}}return Je(t),tc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,l),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==a&&Cl(t);else{if(typeof a!="string"&&t.stateNode===null)throw Error(r(166));if(e=ve.current,Ka(t)){if(e=t.stateNode,l=t.memoizedProps,a=null,s=ht,s!==null)switch(s.tag){case 27:case 5:a=s.memoizedProps}e[mt]=t,e=!!(e.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||jf(e.nodeValue,l)),e||Yl(t,!0)}else e=ci(e).createTextNode(a),e[mt]=t,t.stateNode=e}return Je(t),null;case 31:if(l=t.memoizedState,e===null||e.memoizedState!==null){if(a=Ka(t),l!==null){if(e===null){if(!a)throw Error(r(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(r(557));e[mt]=t}else pa(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Je(t),e=!1}else l=du(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return t.flags&256?(Bt(t),t):(Bt(t),null);if((t.flags&128)!==0)throw Error(r(558))}return Je(t),null;case 13:if(a=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(s=Ka(t),a!==null&&a.dehydrated!==null){if(e===null){if(!s)throw Error(r(318));if(s=t.memoizedState,s=s!==null?s.dehydrated:null,!s)throw Error(r(317));s[mt]=t}else pa(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Je(t),s=!1}else s=du(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=s),s=!0;if(!s)return t.flags&256?(Bt(t),t):(Bt(t),null)}return Bt(t),(t.flags&128)!==0?(t.lanes=l,t):(l=a!==null,e=e!==null&&e.memoizedState!==null,l&&(a=t.child,s=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(s=a.alternate.memoizedState.cachePool.pool),i=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(i=a.memoizedState.cachePool.pool),i!==s&&(a.flags|=2048)),l!==e&&l&&(t.child.flags|=8192),Vs(t,t.updateQueue),Je(t),null);case 4:return Se(),e===null&&Nc(t.stateNode.containerInfo),Je(t),null;case 10:return jl(t.type),Je(t),null;case 19:if(x(lt),a=t.memoizedState,a===null)return Je(t),null;if(s=(t.flags&128)!==0,i=a.rendering,i===null)if(s)kn(a,!1);else{if(Ie!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(i=Rs(e),i!==null){for(t.flags|=128,kn(a,!1),e=i.updateQueue,t.updateQueue=e,Vs(t,e),t.subtreeFlags=0,e=l,l=t.child;l!==null;)Io(l,e),l=l.sibling;return G(lt,lt.current&1|2),Re&&bl(t,a.treeForkCount),t.child}e=e.sibling}a.tail!==null&&tt()>Is&&(t.flags|=128,s=!0,kn(a,!1),t.lanes=4194304)}else{if(!s)if(e=Rs(i),e!==null){if(t.flags|=128,s=!0,e=e.updateQueue,t.updateQueue=e,Vs(t,e),kn(a,!0),a.tail===null&&a.tailMode==="hidden"&&!i.alternate&&!Re)return Je(t),null}else 2*tt()-a.renderingStartTime>Is&&l!==536870912&&(t.flags|=128,s=!0,kn(a,!1),t.lanes=4194304);a.isBackwards?(i.sibling=t.child,t.child=i):(e=a.last,e!==null?e.sibling=i:t.child=i,a.last=i)}return a.tail!==null?(e=a.tail,a.rendering=e,a.tail=e.sibling,a.renderingStartTime=tt(),e.sibling=null,l=lt.current,G(lt,s?l&1|2:l&1),Re&&bl(t,a.treeForkCount),e):(Je(t),null);case 22:case 23:return Bt(t),Au(),a=t.memoizedState!==null,e!==null?e.memoizedState!==null!==a&&(t.flags|=8192):a&&(t.flags|=8192),a?(l&536870912)!==0&&(t.flags&128)===0&&(Je(t),t.subtreeFlags&6&&(t.flags|=8192)):Je(t),l=t.updateQueue,l!==null&&Vs(t,l.retryQueue),l=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(l=e.memoizedState.cachePool.pool),a=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),a!==l&&(t.flags|=2048),e!==null&&x(ga),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),jl(st),Je(t),null;case 25:return null;case 30:return null}throw Error(r(156,t.tag))}function Bh(e,t){switch(ou(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return jl(st),Se(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return I(t),null;case 31:if(t.memoizedState!==null){if(Bt(t),t.alternate===null)throw Error(r(340));pa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(Bt(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(r(340));pa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return x(lt),null;case 4:return Se(),null;case 10:return jl(t.type),null;case 22:case 23:return Bt(t),Au(),e!==null&&x(ga),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return jl(st),null;case 25:return null;default:return null}}function Cd(e,t){switch(ou(t),t.tag){case 3:jl(st),Se();break;case 26:case 27:case 5:I(t);break;case 4:Se();break;case 31:t.memoizedState!==null&&Bt(t);break;case 13:Bt(t);break;case 19:x(lt);break;case 10:jl(t.type);break;case 22:case 23:Bt(t),Au(),e!==null&&x(ga);break;case 24:jl(st)}}function Qn(e,t){try{var l=t.updateQueue,a=l!==null?l.lastEffect:null;if(a!==null){var s=a.next;l=s;do{if((l.tag&e)===e){a=void 0;var i=l.create,u=l.inst;a=i(),u.destroy=a}l=l.next}while(l!==s)}}catch(o){Ye(t,t.return,o)}}function Vl(e,t,l){try{var a=t.updateQueue,s=a!==null?a.lastEffect:null;if(s!==null){var i=s.next;a=i;do{if((a.tag&e)===e){var u=a.inst,o=u.destroy;if(o!==void 0){u.destroy=void 0,s=t;var f=l,j=o;try{j()}catch(U){Ye(s,f,U)}}}a=a.next}while(a!==i)}}catch(U){Ye(t,t.return,U)}}function Td(e){var t=e.updateQueue;if(t!==null){var l=e.stateNode;try{vr(t,l)}catch(a){Ye(e,e.return,a)}}}function Ed(e,t,l){l.props=Na(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(a){Ye(e,t,a)}}function Xn(e,t){try{var l=e.ref;if(l!==null){switch(e.tag){case 26:case 27:case 5:var a=e.stateNode;break;case 30:a=e.stateNode;break;default:a=e.stateNode}typeof l=="function"?e.refCleanup=l(a):l.current=a}}catch(s){Ye(e,t,s)}}function dl(e,t){var l=e.ref,a=e.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(s){Ye(e,t,s)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(s){Ye(e,t,s)}else l.current=null}function Md(e){var t=e.type,l=e.memoizedProps,a=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":l.autoFocus&&a.focus();break e;case"img":l.src?a.src=l.src:l.srcSet&&(a.srcset=l.srcSet)}}catch(s){Ye(e,e.return,s)}}function lc(e,t,l){try{var a=e.stateNode;s0(a,e.type,l,t),a[Nt]=t}catch(s){Ye(e,e.return,s)}}function zd(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&ea(e.type)||e.tag===4}function ac(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||zd(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&ea(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function nc(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(e,t):(t=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,t.appendChild(e),l=l._reactRootContainer,l!=null||t.onclick!==null||(t.onclick=vl));else if(a!==4&&(a===27&&ea(e.type)&&(l=e.stateNode,t=null),e=e.child,e!==null))for(nc(e,t,l),e=e.sibling;e!==null;)nc(e,t,l),e=e.sibling}function Js(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?l.insertBefore(e,t):l.appendChild(e);else if(a!==4&&(a===27&&ea(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(Js(e,t,l),e=e.sibling;e!==null;)Js(e,t,l),e=e.sibling}function Od(e){var t=e.stateNode,l=e.memoizedProps;try{for(var a=e.type,s=t.attributes;s.length;)t.removeAttributeNode(s[0]);yt(t,a,l),t[mt]=e,t[Nt]=l}catch(i){Ye(e,e.return,i)}}var Tl=!1,ct=!1,sc=!1,_d=typeof WeakSet=="function"?WeakSet:Set,dt=null;function qh(e,t){if(e=e.containerInfo,Tc=pi,e=Qo(e),Ii(e)){if("selectionStart"in e)var l={start:e.selectionStart,end:e.selectionEnd};else e:{l=(l=e.ownerDocument)&&l.defaultView||window;var a=l.getSelection&&l.getSelection();if(a&&a.rangeCount!==0){l=a.anchorNode;var s=a.anchorOffset,i=a.focusNode;a=a.focusOffset;try{l.nodeType,i.nodeType}catch{l=null;break e}var u=0,o=-1,f=-1,j=0,U=0,q=e,S=null;t:for(;;){for(var M;q!==l||s!==0&&q.nodeType!==3||(o=u+s),q!==i||a!==0&&q.nodeType!==3||(f=u+a),q.nodeType===3&&(u+=q.nodeValue.length),(M=q.firstChild)!==null;)S=q,q=M;for(;;){if(q===e)break t;if(S===l&&++j===s&&(o=u),S===i&&++U===a&&(f=u),(M=q.nextSibling)!==null)break;q=S,S=q.parentNode}q=M}l=o===-1||f===-1?null:{start:o,end:f}}else l=null}l=l||{start:0,end:0}}else l=null;for(Ec={focusedElem:e,selectionRange:l},pi=!1,dt=t;dt!==null;)if(t=dt,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,dt=e;else for(;dt!==null;){switch(t=dt,i=t.alternate,e=t.flags,t.tag){case 0:if((e&4)!==0&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(l=0;l title"))),yt(i,a,l),i[mt]=e,rt(i),a=i;break e;case"link":var u=qf("link","href",s).get(a+(l.href||""));if(u){for(var o=0;oQe&&(u=Qe,Qe=je,je=u);var v=Lo(o,je),p=Lo(o,Qe);if(v&&p&&(M.rangeCount!==1||M.anchorNode!==v.node||M.anchorOffset!==v.offset||M.focusNode!==p.node||M.focusOffset!==p.offset)){var b=q.createRange();b.setStart(v.node,v.offset),M.removeAllRanges(),je>Qe?(M.addRange(b),M.extend(p.node,p.offset)):(b.setEnd(p.node,p.offset),M.addRange(b))}}}}for(q=[],M=o;M=M.parentNode;)M.nodeType===1&&q.push({element:M,left:M.scrollLeft,top:M.scrollTop});for(typeof o.focus=="function"&&o.focus(),o=0;ol?32:l,T.T=null,l=fc,fc=null;var i=Fl,u=_l;if(ot=0,sn=Fl=null,_l=0,(Be&6)!==0)throw Error(r(331));var o=Be;if(Be|=4,kd(i.current),Gd(i,i.current,u,l),Be=o,Wn(0,!1),ye&&typeof ye.onPostCommitFiberRoot=="function")try{ye.onPostCommitFiberRoot(W,i)}catch{}return!0}finally{k.p=s,T.T=a,uf(e,t)}}function of(e,t,l){t=Zt(l,t),t=Ku(e.stateNode,t,2),e=Xl(e,t,2),e!==null&&(vn(e,2),fl(e))}function Ye(e,t,l){if(e.tag===3)of(e,e,l);else for(;t!==null;){if(t.tag===3){of(t,e,l);break}else if(t.tag===1){var a=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(Wl===null||!Wl.has(a))){e=Zt(l,e),l=od(2),a=Xl(t,l,2),a!==null&&(rd(l,a,t,e),vn(a,2),fl(a));break}}t=t.return}}function vc(e,t,l){var a=e.pingCache;if(a===null){a=e.pingCache=new Lh;var s=new Set;a.set(t,s)}else s=a.get(t),s===void 0&&(s=new Set,a.set(t,s));s.has(l)||(cc=!0,s.add(l),e=Zh.bind(null,e,t,l),t.then(e,e))}function Zh(e,t,l){var a=e.pingCache;a!==null&&a.delete(t),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,Xe===e&&(De&l)===l&&(Ie===4||Ie===3&&(De&62914560)===De&&300>tt()-Fs?(Be&2)===0&&un(e,0):oc|=l,nn===De&&(nn=0)),fl(e)}function rf(e,t){t===0&&(t=lo()),e=ma(e,t),e!==null&&(vn(e,t),fl(e))}function Vh(e){var t=e.memoizedState,l=0;t!==null&&(l=t.retryLane),rf(e,l)}function Jh(e,t){var l=0;switch(e.tag){case 31:case 13:var a=e.stateNode,s=e.memoizedState;s!==null&&(l=s.retryLane);break;case 19:a=e.stateNode;break;case 22:a=e.stateNode._retryCache;break;default:throw Error(r(314))}a!==null&&a.delete(t),rf(e,l)}function $h(e,t){return Ee(e,t)}var ni=null,on=null,yc=!1,si=!1,gc=!1,Pl=0;function fl(e){e!==on&&e.next===null&&(on===null?ni=on=e:on=on.next=e),si=!0,yc||(yc=!0,Fh())}function Wn(e,t){if(!gc&&si){gc=!0;do for(var l=!1,a=ni;a!==null;){if(e!==0){var s=a.pendingLanes;if(s===0)var i=0;else{var u=a.suspendedLanes,o=a.pingedLanes;i=(1<<31-Ze(42|e)+1)-1,i&=s&~(u&~o),i=i&201326741?i&201326741|1:i?i|2:0}i!==0&&(l=!0,hf(a,i))}else i=De,i=os(a,a===Xe?i:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(i&3)===0||pn(a,i)||(l=!0,hf(a,i));a=a.next}while(l);gc=!1}}function Wh(){df()}function df(){si=yc=!1;var e=0;Pl!==0&&u0()&&(e=Pl);for(var t=tt(),l=null,a=ni;a!==null;){var s=a.next,i=ff(a,t);i===0?(a.next=null,l===null?ni=s:l.next=s,s===null&&(on=l)):(l=a,(e!==0||(i&3)!==0)&&(si=!0)),a=s}ot!==0&&ot!==5||Wn(e),Pl!==0&&(Pl=0)}function ff(e,t){for(var l=e.suspendedLanes,a=e.pingedLanes,s=e.expirationTimes,i=e.pendingLanes&-62914561;0o)break;var U=f.transferSize,q=f.initiatorType;U&&Sf(q)&&(f=f.responseEnd,u+=U*(f"u"?null:document;function Rf(e,t,l){var a=rn;if(a&&typeof t=="string"&&t){var s=Xt(t);s='link[rel="'+e+'"][href="'+s+'"]',typeof l=="string"&&(s+='[crossorigin="'+l+'"]'),Uf.has(s)||(Uf.add(s),e={rel:e,crossOrigin:l,href:t},a.querySelector(s)===null&&(t=a.createElement("link"),yt(t,"link",e),rt(t),a.head.appendChild(t)))}}function v0(e){Dl.D(e),Rf("dns-prefetch",e,null)}function y0(e,t){Dl.C(e,t),Rf("preconnect",e,t)}function g0(e,t,l){Dl.L(e,t,l);var a=rn;if(a&&e&&t){var s='link[rel="preload"][as="'+Xt(t)+'"]';t==="image"&&l&&l.imageSrcSet?(s+='[imagesrcset="'+Xt(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(s+='[imagesizes="'+Xt(l.imageSizes)+'"]')):s+='[href="'+Xt(e)+'"]';var i=s;switch(t){case"style":i=dn(e);break;case"script":i=fn(e)}It.has(i)||(e=z({rel:"preload",href:t==="image"&&l&&l.imageSrcSet?void 0:e,as:t},l),It.set(i,e),a.querySelector(s)!==null||t==="style"&&a.querySelector(es(i))||t==="script"&&a.querySelector(ts(i))||(t=a.createElement("link"),yt(t,"link",e),rt(t),a.head.appendChild(t)))}}function b0(e,t){Dl.m(e,t);var l=rn;if(l&&e){var a=t&&typeof t.as=="string"?t.as:"script",s='link[rel="modulepreload"][as="'+Xt(a)+'"][href="'+Xt(e)+'"]',i=s;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":i=fn(e)}if(!It.has(i)&&(e=z({rel:"modulepreload",href:e},t),It.set(i,e),l.querySelector(s)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(ts(i)))return}a=l.createElement("link"),yt(a,"link",e),rt(a),l.head.appendChild(a)}}}function x0(e,t,l){Dl.S(e,t,l);var a=rn;if(a&&e){var s=Da(a).hoistableStyles,i=dn(e);t=t||"default";var u=s.get(i);if(!u){var o={loading:0,preload:null};if(u=a.querySelector(es(i)))o.loading=5;else{e=z({rel:"stylesheet",href:e,"data-precedence":t},l),(l=It.get(i))&&Rc(e,l);var f=u=a.createElement("link");rt(f),yt(f,"link",e),f._p=new Promise(function(j,U){f.onload=j,f.onerror=U}),f.addEventListener("load",function(){o.loading|=1}),f.addEventListener("error",function(){o.loading|=2}),o.loading|=4,ri(u,t,a)}u={type:"stylesheet",instance:u,count:1,state:o},s.set(i,u)}}}function j0(e,t){Dl.X(e,t);var l=rn;if(l&&e){var a=Da(l).hoistableScripts,s=fn(e),i=a.get(s);i||(i=l.querySelector(ts(s)),i||(e=z({src:e,async:!0},t),(t=It.get(s))&&wc(e,t),i=l.createElement("script"),rt(i),yt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(s,i))}}function S0(e,t){Dl.M(e,t);var l=rn;if(l&&e){var a=Da(l).hoistableScripts,s=fn(e),i=a.get(s);i||(i=l.querySelector(ts(s)),i||(e=z({src:e,async:!0,type:"module"},t),(t=It.get(s))&&wc(e,t),i=l.createElement("script"),rt(i),yt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(s,i))}}function wf(e,t,l,a){var s=(s=ve.current)?oi(s):null;if(!s)throw Error(r(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(t=dn(l.href),l=Da(s).hoistableStyles,a=l.get(t),a||(a={type:"style",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){e=dn(l.href);var i=Da(s).hoistableStyles,u=i.get(e);if(u||(s=s.ownerDocument||s,u={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},i.set(e,u),(i=s.querySelector(es(e)))&&!i._p&&(u.instance=i,u.state.loading=5),It.has(e)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},It.set(e,l),i||N0(s,e,l,u.state))),t&&a===null)throw Error(r(528,""));return u}if(t&&a!==null)throw Error(r(529,""));return null;case"script":return t=l.async,l=l.src,typeof l=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=fn(l),l=Da(s).hoistableScripts,a=l.get(t),a||(a={type:"script",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(r(444,e))}}function dn(e){return'href="'+Xt(e)+'"'}function es(e){return'link[rel="stylesheet"]['+e+"]"}function Hf(e){return z({},e,{"data-precedence":e.precedence,precedence:null})}function N0(e,t,l,a){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?a.loading=1:(t=e.createElement("link"),a.preload=t,t.addEventListener("load",function(){return a.loading|=1}),t.addEventListener("error",function(){return a.loading|=2}),yt(t,"link",l),rt(t),e.head.appendChild(t))}function fn(e){return'[src="'+Xt(e)+'"]'}function ts(e){return"script[async]"+e}function Bf(e,t,l){if(t.count++,t.instance===null)switch(t.type){case"style":var a=e.querySelector('style[data-href~="'+Xt(l.href)+'"]');if(a)return t.instance=a,rt(a),a;var s=z({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(e.ownerDocument||e).createElement("style"),rt(a),yt(a,"style",s),ri(a,l.precedence,e),t.instance=a;case"stylesheet":s=dn(l.href);var i=e.querySelector(es(s));if(i)return t.state.loading|=4,t.instance=i,rt(i),i;a=Hf(l),(s=It.get(s))&&Rc(a,s),i=(e.ownerDocument||e).createElement("link"),rt(i);var u=i;return u._p=new Promise(function(o,f){u.onload=o,u.onerror=f}),yt(i,"link",a),t.state.loading|=4,ri(i,l.precedence,e),t.instance=i;case"script":return i=fn(l.src),(s=e.querySelector(ts(i)))?(t.instance=s,rt(s),s):(a=l,(s=It.get(i))&&(a=z({},l),wc(a,s)),e=e.ownerDocument||e,s=e.createElement("script"),rt(s),yt(s,"link",a),e.head.appendChild(s),t.instance=s);case"void":return null;default:throw Error(r(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(a=t.instance,t.state.loading|=4,ri(a,l.precedence,e));return t.instance}function ri(e,t,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),s=a.length?a[a.length-1]:null,i=s,u=0;u title"):null)}function A0(e,t,l){if(l===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(e=t.disabled,typeof t.precedence=="string"&&e==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Yf(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function C0(e,t,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var s=dn(a.href),i=t.querySelector(es(s));if(i){t=i._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=fi.bind(e),t.then(e,e)),l.state.loading|=4,l.instance=i,rt(i);return}i=t.ownerDocument||t,a=Hf(a),(s=It.get(s))&&Rc(a,s),i=i.createElement("link"),rt(i);var u=i;u._p=new Promise(function(o,f){u.onload=o,u.onerror=f}),yt(i,"link",a),l.instance=i}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(l,t),(t=l.state.preload)&&(l.state.loading&3)===0&&(e.count++,l=fi.bind(e),t.addEventListener("load",l),t.addEventListener("error",l))}}var Hc=0;function T0(e,t){return e.stylesheets&&e.count===0&&hi(e,e.stylesheets),0Hc?50:800)+t);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(s)}}:null}function fi(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)hi(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var mi=null;function hi(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,mi=new Map,t.forEach(E0,e),mi=null,fi.call(e))}function E0(e,t){if(!(t.state.loading&4)){var l=mi.get(e);if(l)var a=l.get(null);else{l=new Map,mi.set(e,l);for(var s=e.querySelectorAll("link[data-precedence],style[data-precedence]"),i=0;i"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(c)}catch(m){console.error(m)}}return c(),Kc.exports=K0(),Kc.exports}var V0=Z0();function be(c){return Array.isArray(c)?c:[]}function pm(c){const m=new Set;return c.map(h=>h.trim()).filter(h=>{const r=h.toLowerCase();return!h||m.has(r)?!1:(m.add(r),!0)})}function sl(c){const m=Ni.some(h=>h.value===c.streamMode)?c.streamMode:"auto";return{...c,streamMode:m,models:be(c.models),allowedGroupIds:be(c.allowedGroupIds),openaiAccounts:be(c.openaiAccounts),kiroAccounts:be(c.kiroAccounts)}}function cs(c){return{...c,aliases:be(c.aliases)}}function J0(c){return{...c,apiKeys:be(c.apiKeys),logs:be(c.logs)}}class Ci extends Error{status;payload;constructor(m,h,r){super(h),this.status=m,this.payload=r}}const $0={home:"M3 10.5 12 3l9 7.5V21a1 1 0 0 1-1 1h-5v-7H9v7H4a1 1 0 0 1-1-1z",users:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75",key:"M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.78 7.78 5.5 5.5 0 0 1 7.78-7.78ZM14 8l7-7M21 8h-5V3",models:"M12 2 4 6v12l8 4 8-4V6zM4 6l8 4 8-4M12 10v12",image:"M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2ZM8.5 11a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5ZM21 16l-5-5L5 21",route:"M4 19a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM20 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM7 16h3a4 4 0 0 0 4-4V8h3",logs:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8zM14 2v6h6M8 13h8M8 17h6",settings:"M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7ZM19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 8.92 4a1.65 1.65 0 0 0 1-1.51V2a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9c.14.31.39.57.71.71.23.1.49.18.8.2H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z",search:"M21 21l-4.35-4.35M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z",copy:"M8 8h11a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1ZM4 16H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h11a1 1 0 0 1 1 1v1",ban:"M4.93 4.93 19.07 19.07M22 12A10 10 0 1 1 2 12a10 10 0 0 1 20 0Z",check:"M20 6 9 17l-5-5",moon:"M21 12.8A8.5 8.5 0 1 1 11.2 3 6.5 6.5 0 0 0 21 12.8Z",sun:"M12 4V2M12 22v-2M4.93 4.93 3.52 3.52M20.48 20.48l-1.41-1.41M4 12H2M22 12h-2M4.93 19.07l-1.41 1.41M20.48 3.52l-1.41 1.41M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z",plus:"M12 5v14M5 12h14"};function Ot({name:c}){return n.jsx("svg",{viewBox:"0 0 24 24","aria-hidden":"true",className:"icon",children:n.jsx("path",{d:$0[c]})})}async function pe(c,m){const h=new Headers(m?.headers);h.set("Content-Type","application/json");const r=window.sessionStorage.getItem("capi-admin-token");r&&h.set("Authorization",`Bearer ${r}`);const A=await fetch(c,{credentials:"include",...m,headers:h});if(!A.ok){const E=await A.json().catch(()=>null);throw new Ci(A.status,E?.error?.message||`Request failed: ${A.status}`,E)}return A.json()}async function W0(c,m){const h=new Headers,r=window.sessionStorage.getItem("capi-admin-token");r&&h.set("Authorization",`Bearer ${r}`);const A=await fetch(c,{credentials:"include",method:"POST",headers:h,body:m});if(!A.ok){const E=await A.json().catch(()=>null);throw new Ci(A.status,E?.error?.message||`Request failed: ${A.status}`,E)}return A.json()}const rm=[{id:"overview",label:"概览",icon:"home"},{id:"users",label:"用户",icon:"users"},{id:"groups",label:"分组",icon:"users"},{id:"keys",label:"密钥",icon:"key"},{id:"models",label:"模型",icon:"models"},{id:"drawing",label:"绘图",icon:"image"},{id:"channels",label:"渠道",icon:"route"},{id:"logs",label:"日志",icon:"logs"},{id:"settings",label:"设置",icon:"settings"}],eo=[{value:"kiro",label:"Kiro / Amazon Q"},{value:"codex",label:"Codex / ChatGPT OAuth"},{value:"cpa",label:"CPA / CLIProxyAPI"},{value:"openai",label:"OpenAI"},{value:"anthropic",label:"Anthropic / Claude"},{value:"google",label:"Google Gemini"},{value:"deepseek",label:"DeepSeek"},{value:"openrouter",label:"OpenRouter"},{value:"groq",label:"Groq"},{value:"siliconflow",label:"SiliconFlow"},{value:"moonshot",label:"Moonshot"},{value:"compatible",label:"OpenAI 兼容接口"}],vm="https://api.openai.com/v1",Ti="https://chatgpt.com/backend-api",ym="http://localhost:8317/v1",gm="https://codewhisperer.us-east-1.amazonaws.com",bm="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2, gpt-image-1",F0="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2",I0="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, claude-sonnet-4, gemini-3.1-pro",P0="claude-sonnet-4.5, claude-sonnet-4, claude-haiku-4.5, claude-opus-4.5",Fc=[{provider:"kiro",label:"Kiro / Amazon Q",name:"Kiro 账号池",baseUrl:gm,models:P0.split(",").map(c=>c.trim())},{provider:"openai",label:"OpenAI",name:"OpenAI 主线路",baseUrl:vm,models:F0.split(",").map(c=>c.trim())},{provider:"codex",label:"Codex 账号池",name:"Codex 账号池",baseUrl:Ti,models:bm.split(",").map(c=>c.trim())},{provider:"cpa",label:"CPA / CLIProxyAPI",name:"CPA 本地代理",baseUrl:ym,models:I0.split(",").map(c=>c.trim())},{provider:"compatible",label:"OpenAI 兼容接口",name:"兼容渠道",baseUrl:"",models:[]},{provider:"openrouter",label:"OpenRouter",name:"OpenRouter",baseUrl:"https://openrouter.ai/api/v1",models:[]},{provider:"google",label:"Google Gemini",name:"Gemini",baseUrl:"",models:[]},{provider:"anthropic",label:"Anthropic / Claude",name:"Claude",baseUrl:"",models:[]}];function Ta(c){return Fc.find(m=>m.provider===c)||Fc[2]}function xm(c){const m=Ta(c);return{name:m.name,provider:m.provider,baseUrl:m.baseUrl,models:[...m.models],streamMode:"auto"}}function ep(c){const m=c?.trim().toLowerCase();return m&&({free:"Free",plus:"Plus",pro:"Pro",team:"Team",enterprise:"Enterprise"}[m]||c)||"套餐未知"}function dm(c){return c?{upstream_token_invalidated:"Token 已失效",upstream_invalid_api_key:"API Key 无效",upstream_account_error:"账号错误",upstream_accounts_unavailable:"账号池不可用",upstream_error:"上游错误"}[c]||c:""}function Ei(c){return c==="openai"?vm:c==="codex"?Ti:c==="cpa"||c==="cliproxyapi"?ym:c==="kiro"?gm:""}function Ic(c){return pm(c.split(/[\s,;,;]+/))}function tp(c){return pm(c.split(/[\n,;,;]+/).map(m=>m.trim()))}function jm(c){const m=tp(c);return m.length===0?{}:m.length===1?{upstreamApiKey:m[0]}:{upstreamApiKeys:m}}const Ni=[{value:"auto",label:"自动",description:"按请求参数处理"},{value:"real",label:"真流",description:"直连上游 SSE"},{value:"fake",label:"假流",description:"非流转 SSE"},{value:"disabled",label:"禁用流",description:"流式请求跳过"}];function el(c){if(!c)return"未使用";const m=new Date(c);return Number.isNaN(m.getTime())?"-":new Intl.DateTimeFormat("zh-CN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}).format(m)}function fm(c){if(!c)return"";const m=new Date(c);if(Number.isNaN(m.getTime()))return"";const h=m.getTimezoneOffset()*6e4;return new Date(m.getTime()-h).toISOString().slice(0,16)}function lp(c){if(!c)return"";const m=new Date(c);return Number.isNaN(m.getTime())?"":m.toISOString()}function ap(c){if(!c)return"-";const m=new Date(c);return Number.isNaN(m.getTime())?"-":new Intl.DateTimeFormat("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(m)}function _t(c){return{active:"正常",disabled:"禁用",limited:"受限",overdue:"欠费",healthy:"正常",standby:"备用",available:"Available",success:"成功",failed:"失败"}[c]||c}function St(c,m=2){const h=Number(c||0);return new Intl.NumberFormat("zh-CN",{minimumFractionDigits:m,maximumFractionDigits:m}).format(h)}function ml(c){return new Intl.NumberFormat("zh-CN").format(Math.max(0,Math.round(Number(c||0))))}function to(c){return c.model?c.model:c.errorCode==="invalid_api_key"?"密钥无效":c.errorCode==="model_not_available"?"模型不可用":c.errorCode==="insufficient_quota"?"额度不足":c.errorCode==="rate_limit_exceeded"?"请求过快":c.errorCode||"请求失败"}function np(c){return c.model||(c.errorCode?`错误:${c.errorCode}`:"-")}function sp(c){return c.channel||(c.apiKeyPrefix?`Key ${c.apiKeyPrefix}`:"-")}function ip(c){const m=be(c);if(m.length===0)return"未绑定模型";const h=m.slice(0,2).join(", ");return m.length>2?`${h} · 其余 ${m.length-2} 个`:h}function il(c){return c==="cliproxyapi"||c==="cli-proxy-api"?"CPA / CLIProxyAPI":eo.find(m=>m.value===c)?.label||c||"Custom"}function $c(c){const m=`${c.vendor} ${c.id} ${c.name}`.toLowerCase();return m.includes("cliproxyapi")||/\bcpa\b/.test(m)?"cpa":m.includes("openai")||/\bgpt[-_/]/.test(m)||m.includes("o1-")||m.includes("o3-")?"openai":m.includes("anthropic")||m.includes("claude")?"anthropic":m.includes("google")||m.includes("gemini")||m.includes("gcli-")?"google":m.includes("deepseek")?"deepseek":m.includes("openrouter")?"openrouter":m.includes("groq")?"groq":m.includes("siliconflow")?"siliconflow":m.includes("moonshot")||m.includes("kimi")?"moonshot":c.vendor&&c.vendor.toLowerCase()!=="custom"?c.vendor.toLowerCase():"compatible"}function mm({provider:c}){if(c==="deepseek")return n.jsx("span",{className:"provider-icon provider-icon-deepseek","aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("path",{transform:"translate(2.4 4.4)",d:"M26.517 3.395c-.282-.138-.403.125-.568.258-.057.044-.105.1-.152.152-.413.44-.895.73-1.524.695-.92-.052-1.705.237-2.4.941-.147-.868-.638-1.386-1.384-1.718-.39-.173-.786-.346-1.06-.721-.19-.268-.243-.566-.338-.86-.061-.176-.121-.357-.325-.388-.222-.034-.309.151-.396.307-.347.635-.481 1.334-.468 2.042.03 1.594.703 2.863 2.04 3.765.152.104.191.207.143.359-.091.31-.2.613-.295.924-.06.198-.151.242-.364.155-.734-.306-1.367-.76-1.927-1.308-.951-.92-1.81-1.934-2.882-2.729-.252-.185-.504-.358-.764-.522-1.094-1.062.143-1.935.43-2.038.3-.108.104-.48-.864-.475-.968.004-1.853.328-2.982.76-.165.065-.339.112-.516.151-1.024-.194-2.088-.237-3.199-.112-2.092.233-3.763 1.222-4.991 2.91C.254 7.972-.093 10.278.332 12.682c.446 2.535 1.74 4.633 3.728 6.274 2.062 1.7 4.436 2.534 7.145 2.375 1.645-.095 3.476-.316 5.542-2.064.521.259 1.068.363 1.975.44.699.065 1.371-.034 1.892-.142.816-.173.76-.929.465-1.067-2.392-1.114-1.866-.661-2.344-1.027 1.215-1.438 3.071-3.993 3.644-7.473.056-.384.128-.925.12-1.236-.005-.19.038-.263.255-.285.6-.069 1.18-.233 1.715-.527 1.55-.846 2.175-2.237 2.322-3.903.022-.255-.005-.518-.274-.652ZM13.014 18.395c-2.318-1.823-3.442-2.423-3.906-2.397-.434.026-.356.523-.26.847.1.32.23.54.412.82.126.186.213.462-.126.67-.746.461-2.044-.156-2.105-.186-1.51-.89-2.773-2.064-3.664-3.67-.86-1.545-1.358-3.204-1.44-4.974-.022-.427.104-.578.529-.656.56-.103 1.137-.125 1.697-.043 2.366.346 4.379 1.403 6.068 3.079.963.954 1.692 2.094 2.443 3.208.799 1.183 1.658 2.31 2.752 3.234.387.324.695.57.99.751-.89.1-2.374.121-3.39-.683Zm1.111-7.146c0-.19.152-.341.343-.341.043 0 .082.009.117.021.048.018.092.044.126.083.061.06.096.146.096.237a.341.341 0 0 1-.343.341.34.34 0 0 1-.339-.341Zm3.451 1.77c-.222.09-.443.168-.656.177-.33.017-.69-.117-.885-.281-.304-.255-.521-.397-.612-.842-.039-.19-.017-.483.017-.652.078-.362-.009-.595-.265-.807-.208-.172-.473-.22-.764-.22-.108 0-.208-.048-.282-.086-.121-.061-.221-.212-.126-.398.031-.06.178-.207.213-.233.395-.225.85-.151 1.272.018.39.16.686.453 1.111.867.434.501.512.639.759 1.015.196.294.373.596.495.942.073.215-.022.392-.277.5Z"})]})});if(c==="openai")return n.jsx("span",{className:"provider-icon provider-icon-openai","aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("g",{transform:"translate(7 7.5) scale(0.065)",fill:"currentColor",stroke:"none",children:n.jsx("path",{d:"M267.06 111.34a71.78 71.78 0 0 0-6.17-58.91c-14.5-25.15-43.55-38.09-71.9-32.03A71.78 71.78 0 0 0 135.1.5C106 .43 80.21 19.16 71.29 46.85a71.79 71.79 0 0 0-47.98 34.8c-14.6 25.1-11.28 56.75 8.22 78.3a71.78 71.78 0 0 0 6.16 58.9c14.5 25.16 43.56 38.1 71.91 32.04a71.76 71.76 0 0 0 53.89 24.02c29.12.02 54.92-18.72 63.84-46.44a71.79 71.79 0 0 0 47.98-34.8c14.58-25.1 11.25-56.72-8.24-78.27zm-107.9 150.77a53.15 53.15 0 0 1-34.15-12.35c.43-.24 1.2-.66 1.7-.96l56.68-32.73a9.22 9.22 0 0 0 4.66-8.06v-79.9l23.95 13.83a.85.85 0 0 1 .47.66v66.16a53.42 53.42 0 0 1-53.3 53.35zM44.6 213.16a53.13 53.13 0 0 1-6.36-35.75c.42.25 1.15.7 1.68 1l56.68 32.73a9.24 9.24 0 0 0 9.31 0l69.2-39.95v27.66a.87.87 0 0 1-.34.74l-57.29 33.07a53.42 53.42 0 0 1-72.88-19.5zM29.7 90.05a53.1 53.1 0 0 1 27.76-23.36c0 .49-.03 1.36-.03 1.96v65.46a9.22 9.22 0 0 0 4.65 8.05l69.2 39.95-23.95 13.83a.86.86 0 0 1-.81.07L49.2 162.9A53.42 53.42 0 0 1 29.7 90.05zm196.8 45.8L157.3 95.9l23.95-13.82a.86.86 0 0 1 .81-.07l57.3 33.08a53.37 53.37 0 0 1-8.24 96.29v-65.46a9.2 9.2 0 0 0-4.62-8.06zm23.84-35.89c-.42-.26-1.15-.7-1.68-1.01l-56.68-32.73a9.25 9.25 0 0 0-9.31 0l-69.2 39.95V78.5a.87.87 0 0 1 .35-.74l57.28-33.05a53.35 53.35 0 0 1 79.24 55.25zM100.11 149.24l-23.96-13.83a.85.85 0 0 1-.46-.66V68.6a53.37 53.37 0 0 1 87.52-40.95c-.42.24-1.19.66-1.7.96l-56.68 32.73a9.22 9.22 0 0 0-4.66 8.06l-.04 79.85zm13.01-28.05L144 103.3l30.88 17.83v35.68L144 174.63l-30.88-17.82v-35.62z"})})]})});const m=c==="codex"?"C":c==="cpa"||c==="cliproxyapi"?"CPA":c==="anthropic"?"A":c==="google"?"✦":c==="openrouter"?"↗":c==="groq"?"G":c==="siliconflow"?"S":c==="moonshot"?"M":"◇";return n.jsx("span",{className:`provider-icon provider-icon-${c}`,"aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("text",{x:"16",y:"21",textAnchor:"middle",children:m})]})})}async function Ai(c){if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(c);return}const m=document.createElement("textarea");m.value=c,m.setAttribute("readonly","true"),m.style.position="fixed",m.style.opacity="0",document.body.appendChild(m),m.select(),document.execCommand("copy"),document.body.removeChild(m)}function Ul(){return window.location.origin}function up(){return`${Ul()}/api/auth/discord/callback`}function cp(){return`${Ul()}/`}function Wc(c){return{...c,redirectUri:c.redirectUri&&!c.redirectUri.includes("localhost")?c.redirectUri:up(),authSuccessUrl:c.authSuccessUrl&&!c.authSuccessUrl.includes("localhost")?c.authSuccessUrl:cp(),blockedGuildIds:be(c.blockedGuildIds),sessionTtlHours:c.sessionTtlHours||168}}function Mi(c){return c==="email"||c==="discord"?c:"username"}function op(c){const h=(c.split("@")[0]||"user").toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^[-_]+|[-_]+$/g,"");return(h.length>=3?h:"user").slice(0,24)}function rp(){const[c,m]=g.useState("home"),[h,r]=g.useState("login"),[A,E]=g.useState(null),[L,$]=g.useState("overview"),[C,y]=g.useState(()=>{const w=window.localStorage.getItem("capi-theme");return w==="light"||w==="dark"?w:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}),[R,z]=g.useState("comfortable"),[P,ee]=g.useState(null),[de,ne]=g.useState([]),[le,ie]=g.useState([]),[xe,Y]=g.useState([]),[ge,F]=g.useState([]),[me,D]=g.useState([]),[ae,fe]=g.useState(""),[Ae,Te]=g.useState(""),[ue,Z]=g.useState(null),[re,J]=g.useState(""),[T,k]=g.useState(""),[B,Q]=g.useState(!1),O=g.useMemo(()=>{const w=ae.trim().toLowerCase();return w?de.filter(K=>`${K.id} ${K.name} ${K.email}`.toLowerCase().includes(w)):de},[ae,de]);async function d(){const w=new Date().getTimezoneOffset(),[K,te,W,ye,qe,Ze]=await Promise.all([pe(`/api/overview?timezoneOffset=${w}`),pe("/api/users"),pe("/api/channels"),pe("/api/models"),pe("/api/logs"),pe("/api/groups")]),Ut=be(te.users),Rl=be(W.channels).map(sl),ca=be(ye.models).map(cs),Ea=be(qe.logs),Ma=be(Ze.groups);ee(K),ne(Ut),ie(Rl),Y(Ma),F(ca),D(Ea),Te(wl=>wl&&Ut.some(hl=>hl.id===wl)?wl:Ut[0]?.id||""),Ut.length===0&&Z(null),Q(!0)}async function x(w){const K=await pe(`/api/users/${w}`);Z(J0(K))}async function G(w,K){const te=await pe(`/api/users/${w}`,{method:"PATCH",body:JSON.stringify(K)});ne(W=>W.map(ye=>ye.id===w?te.user:ye)),Z(W=>W?.user.id===w?{...W,user:te.user}:W),J("已更新用户"),window.setTimeout(()=>J(""),1800)}async function X(w,K,te={}){const W=await pe("/api/users/bulk",{method:"POST",body:JSON.stringify({userIds:w,action:K,...te})}),ye=new Map(be(W.users).map(qe=>[qe.id,qe]));ne(qe=>qe.map(Ze=>ye.get(Ze.id)||Ze)),Z(qe=>{if(!qe)return qe;const Ze=ye.get(qe.user.id);return Ze?{...qe,user:Ze}:qe}),J(`已处理 ${W.updated} 个用户`),window.setTimeout(()=>J(""),1800)}async function se(w){const K=await pe(`/api/users/${w}/api-keys`,{method:"POST",body:JSON.stringify({name:"Console Key"})});ue?.user.id===w&&Z({...ue,apiKeys:[...ue.apiKeys,K.apiKey]}),k(K.secret),await Ai(K.secret),J("新 Key 已创建并复制,请立即保存"),window.setTimeout(()=>J(""),2400)}async function ve(w){window.confirm("删除这个 Key?删除后使用它的请求会立即失效。")&&(await pe(`/api/api-keys/${w}`,{method:"DELETE"}),Z(K=>K&&{...K,apiKeys:K.apiKeys.filter(te=>te.id!==w)}),J("Key 已删除"),window.setTimeout(()=>J(""),1800))}async function N(w,K){const te=await pe(`/api/api-keys/${w}`,{method:"PATCH",body:JSON.stringify(K)});Z(W=>W&&{...W,apiKeys:W.apiKeys.map(ye=>ye.id===w?te.apiKey:ye)}),J("Key 已更新"),window.setTimeout(()=>J(""),1800)}async function Ne(w,K){const te=await pe(`/api/channels/${w}`,{method:"PATCH",body:JSON.stringify(K)});ie(W=>W.map(ye=>ye.id===w?sl(te.channel):ye)),Pe(te.removedModels),J("渠道已更新"),window.setTimeout(()=>J(""),1800)}async function Se(w){const K=le.find(W=>W.id===w);if(!window.confirm(`删除渠道「${K?.name||w}」?`))return;const te=await pe(`/api/channels/${w}`,{method:"DELETE"});ie(W=>W.filter(ye=>ye.id!==w)),Pe(te.removedModels),J("渠道已删除"),window.setTimeout(()=>J(""),1800)}async function bt(w){const K=await pe("/api/groups",{method:"POST",body:JSON.stringify(w)});Y(te=>[...te,K.group]),J("分组已创建"),window.setTimeout(()=>J(""),1800)}async function I(w,K){const te=await pe(`/api/groups/${w}`,{method:"PATCH",body:JSON.stringify(K)});Y(W=>W.map(ye=>ye.id===w?te.group:ye)),J("分组已更新"),window.setTimeout(()=>J(""),1800)}async function Ke(w){const K=xe.find(te=>te.id===w);window.confirm(`删除分组「${K?.name||w}」?删除后渠道的可见范围会移除该分组。`)&&(await pe(`/api/groups/${w}`,{method:"DELETE"}),Y(te=>te.filter(W=>W.id!==w)),ie(te=>te.map(W=>({...W,allowedGroupIds:W.allowedGroupIds.filter(ye=>ye!==w)}))),J("分组已删除"),window.setTimeout(()=>J(""),1800))}async function We(w,K){const te=be(K).map(Ut=>Ut.trim()).filter(Boolean),W=await pe(`/api/channels/${w}/sync-models`,{method:"POST",body:JSON.stringify(te.length?{models:te}:{})}),ye=sl(W.channel),qe=be(W.addedModels).map(cs),Ze=be(W.models);ie(Ut=>Ut.map(Rl=>Rl.id===w?ye:Rl)),qe.length>0&&F(Ut=>{const Rl=new Set(Ut.map(ca=>ca.id.toLowerCase()));return[...Ut,...qe.filter(ca=>!Rl.has(ca.id.toLowerCase()))]}),Pe(W.removedModels),J(te.length?`已保存 ${Ze.length} 个模型`:Ze.length?`已拉取 ${Ze.length} 个模型`:"上游没有返回模型"),window.setTimeout(()=>J(""),2200)}function Pe(w){const K=new Set(be(w).map(te=>te.toLowerCase()));K.size!==0&&(F(te=>te.filter(W=>!K.has(W.id.toLowerCase()))),Z(te=>te&&{...te,apiKeys:te.apiKeys.map(W=>({...W,allowedModels:W.allowedModels.filter(ye=>!K.has(ye.toLowerCase()))}))}))}async function tl(w){try{const K=await pe(`/api/channels/${w}/check`,{method:"POST",body:JSON.stringify({})});ie(te=>te.map(W=>W.id===w?sl(K.channel):W)),J(K.ok?`渠道可用,检测到 ${be(K.models).length} 个模型`:"渠道检测失败")}catch(K){const te=K instanceof Ci?K.payload?.channel:null;te&&ie(W=>W.map(ye=>ye.id===w?sl(te):ye)),J(K instanceof Error?K.message:"渠道检测失败")}window.setTimeout(()=>J(""),2400)}async function kt(w=xm("codex")){const K=await pe("/api/channels",{method:"POST",body:JSON.stringify(w)});ie(te=>[...te,sl(K.channel)]),J("渠道已创建,可继续拉取模型或检测渠道"),window.setTimeout(()=>J(""),2400)}async function cl(w,K){const te=new FormData;te.append("file",K);const W=await W0(`/api/channels/${encodeURIComponent(w)}/import-openai-accounts`,te);ie(ye=>ye.map(qe=>qe.id===W.channel.id?sl(W.channel):qe)),J(`新增 ${W.created??W.imported} 个账号${W.updated?`,更新 ${W.updated} 个已有账号`:""}${W.skipped?`,跳过 ${W.skipped} 个`:""}`),window.setTimeout(()=>J(""),2600)}async function V(w,K=!1,te=""){const W=await pe(`/api/channels/${encodeURIComponent(w)}/openai-accounts/check`,{method:"POST",body:JSON.stringify({onlyInvalid:K,accountId:te})});ie(ye=>ye.map(qe=>qe.id===W.channel.id?sl(W.channel):qe)),J(`${K?"无效账号复检":"账号测活"}完成:${W.healthy}/${W.checked} 可用${W.failed?`,无效 ${W.failed}`:""}`),window.setTimeout(()=>J(""),3e3)}async function _(w){const K=await pe(`/api/channels/${encodeURIComponent(w)}/openai-accounts/deduplicate`,{method:"POST",body:JSON.stringify({})});ie(te=>te.map(W=>W.id===K.channel.id?sl(K.channel):W)),J(K.removed?`已合并 ${K.removed} 个重复账号`:"未发现可识别的重复账号"),window.setTimeout(()=>J(""),2600)}async function Ee(w,K){const te=await pe(`/api/channels/${encodeURIComponent(w)}/openai-accounts/${encodeURIComponent(K)}`,{method:"DELETE"});ie(W=>W.map(ye=>ye.id===te.channel.id?sl(te.channel):ye)),J("账号已删除"),window.setTimeout(()=>J(""),1800)}async function et(w){return pe(`/api/channels/${encodeURIComponent(w)}/openai-oauth/start`,{method:"POST",body:JSON.stringify({})})}async function xt(w,K){const te=await pe(`/api/channels/${encodeURIComponent(w)}/openai-oauth/complete`,{method:"POST",body:JSON.stringify(K)});return ie(W=>W.map(ye=>ye.id===te.channel.id?sl(te.channel):ye)),J("已通过 OAuth 添加账号"),window.setTimeout(()=>J(""),2400),te}async function ft(w){const K=await pe("/api/models",{method:"POST",body:JSON.stringify(w)});F(te=>[...te,cs(K.model)]),J("模型已添加"),window.setTimeout(()=>J(""),1800)}async function tt(w,K){const te=await pe(`/api/models/${encodeURIComponent(w)}`,{method:"PATCH",body:JSON.stringify(K)});F(W=>W.map(ye=>ye.id===w?cs(te.model):ye)),J("模型已更新"),window.setTimeout(()=>J(""),1600)}async function zi(w){window.confirm(`删除模型 ${w}?渠道和 Key 中的引用也会一起清理。`)&&(await pe(`/api/models/${encodeURIComponent(w)}`,{method:"DELETE"}),F(K=>K.filter(te=>te.id!==w)),ie(K=>K.map(te=>({...te,models:te.models.filter(W=>W!==w)}))),Z(K=>K&&{...K,apiKeys:K.apiKeys.map(te=>({...te,allowedModels:te.allowedModels.filter(W=>W!==w)}))}),J("模型已删除"),window.setTimeout(()=>J(""),1800))}async function hn(w,K="已复制"){await Ai(w),J(K),window.setTimeout(()=>J(""),1600)}function ia(w,K){if(w instanceof Ci&&w.status===401){Q(!1),r("login"),m("auth");return}J(K)}async function ua(){try{const w=await pe("/api/auth/status");if(E(w),!w.initialized){r("setup"),m("auth");return}if(!w.authenticated){r("login"),m("auth");return}m(w.session?.role==="admin"?"console":"account")}catch(w){ia(w,"认证状态加载失败")}}async function Oi(){await pe("/api/auth/logout",{method:"POST"}),window.sessionStorage.removeItem("capi-admin-token"),E(null),m("home")}return g.useEffect(()=>{let w=!1;return pe("/api/auth/status").then(K=>{w||(E(K),K.authenticated&&K.session&&m(K.session.role==="admin"?"console":"account"))}).catch(()=>{}),()=>{w=!0}},[]),g.useEffect(()=>{c==="console"&&(Q(!1),d().catch(w=>ia(w,"加载数据失败")))},[c]),g.useEffect(()=>{c!=="console"||!B||x(Ae).catch(w=>ia(w,"加载用户详情失败"))},[Ae,c,B]),g.useEffect(()=>{window.localStorage.setItem("capi-theme",C)},[C]),g.useEffect(()=>{window.scrollTo({top:0,left:0})},[c,L]),c==="home"?n.jsx(yp,{theme:C,setTheme:y,enterConsole:ua}):c==="auth"?n.jsx(dp,{theme:C,mode:h,status:A,setTheme:y,setMode:r,goHome:()=>m("home"),onAuthenticated:w=>{E(K=>K?{...K,authenticated:!0,initialized:!0,session:w}:null),m(w.role==="admin"?"console":"account")}}):c==="account"?n.jsx(vp,{theme:C,setTheme:y,goHome:()=>m("home"),openLogin:ua}):n.jsxs("div",{className:"app-shell","data-theme":C,"data-density":R,children:[n.jsxs("aside",{className:"sidebar",children:[n.jsxs("div",{className:"ios-window-dots","aria-hidden":"true",children:[n.jsx("span",{}),n.jsx("span",{}),n.jsx("span",{})]}),n.jsxs("div",{className:"brand",children:[n.jsx("div",{className:"brand-mark",children:"C"}),n.jsxs("div",{children:[n.jsx("strong",{children:"CAPI"}),n.jsx("span",{children:"聚合网关"})]})]}),n.jsx("nav",{children:rm.map(w=>n.jsxs("button",{className:L===w.id?"nav-item active":"nav-item",onClick:()=>$(w.id),children:[n.jsx(Ot,{name:w.icon}),n.jsx("span",{className:"nav-label",children:w.label})]},w.id))}),n.jsxs("div",{className:"sidebar-footer",children:[n.jsx("span",{children:"Gateway"}),n.jsxs("strong",{children:[n.jsx("span",{className:"pulse-dot"}),"Online"]})]})]}),n.jsxs("main",{className:"content",children:[n.jsxs("header",{className:"topbar",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Admin Console"}),n.jsx("h1",{children:rm.find(w=>w.id===L)?.label})]}),n.jsxs("div",{className:"topbar-actions",children:[n.jsx(Kp,{value:R,options:[{value:"comfortable",label:"舒适"},{value:"compact",label:"紧凑"}],onChange:w=>z(w)}),n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>y(C==="dark"?"light":"dark"),children:[n.jsx(Ot,{name:C==="dark"?"sun":"moon"}),n.jsx("span",{children:C==="dark"?"浅色":"暗色"})]}),n.jsx("button",{className:"primary-button",onClick:()=>d().catch(w=>ia(w,"刷新失败")),children:"刷新"}),n.jsx("button",{className:"secondary-button home-link",onClick:()=>m("home"),children:"首页"}),n.jsx("button",{className:"secondary-button",onClick:Oi,children:"退出"})]})]}),L==="overview"&&n.jsx(gp,{overview:P,channels:le,logs:me,onNavigate:w=>{$(w),w==="channels"&&le.length===0&&J("渠道页可以创建第一个上游"),w==="logs"&&me.length===0&&J("暂无异常日志"),window.setTimeout(()=>J(""),1800)}}),L==="users"&&n.jsx(xp,{users:O,query:ae,selectedUser:ue,onQuery:fe,onSelect:Te,onUpdate:G,onBulkUpdate:X,onCreateKey:se,groups:xe,onOpenRegistration:()=>{$("settings"),J("在账号与注册里开放注册,用户即可自助创建账号"),window.setTimeout(()=>J(""),2400)}}),L==="groups"&&n.jsx(Qp,{groups:xe,onCreate:bt,onUpdate:I,onDelete:Ke}),L==="keys"&&n.jsx(jp,{selectedUser:ue,onCreateKey:se,onUpdateKey:N,onDeleteKey:ve}),L==="models"&&n.jsx(Np,{models:ge,onCopy:hn,onCreate:ft,onUpdate:tt,onDelete:zi}),L==="drawing"&&n.jsx(Tp,{channels:le,onCreate:kt,onImport:cl,onCheckAccounts:V,onDeduplicateAccounts:_,onDeleteAccount:Ee,onUpdate:Ne,onStartOAuth:et,onCompleteOAuth:xt}),L==="channels"&&n.jsx(qp,{channels:le,groups:xe,onUpdate:Ne,onCreate:kt,onImport:cl,onDelete:Se,onSyncModels:We,onCheck:tl}),L==="logs"&&n.jsx(Yp,{logs:me,onCopy:hn}),L==="settings"&&n.jsx(kp,{models:ge,channels:le,groups:xe})]}),T&&n.jsx("div",{className:"secret-dialog-backdrop",role:"presentation",children:n.jsxs("section",{className:"secret-dialog",role:"dialog","aria-modal":"true","aria-labelledby":"secret-dialog-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"One-time secret"}),n.jsx("h2",{id:"secret-dialog-title",children:"完整 API Key"})]}),n.jsx("p",{children:"完整密钥只显示这一次。列表中的星号内容只是识别前缀,不能用于 API 调用。"}),n.jsx("code",{children:T}),n.jsxs("div",{className:"secret-dialog-actions",children:[n.jsx("button",{className:"secondary-button",onClick:()=>{Ai(T),J("完整 Key 已复制"),window.setTimeout(()=>J(""),1800)},children:"复制"}),n.jsx("button",{className:"primary-button",onClick:()=>k(""),children:"完成"})]})]})}),re&&n.jsx("div",{className:"toast",children:re})]})}function dp({theme:c,mode:m,status:h,setTheme:r,setMode:A,goHome:E,onAuthenticated:L}){const[$,C]=g.useState(""),[y,R]=g.useState(""),[z,P]=g.useState(""),[ee,de]=g.useState(""),[ne,le]=g.useState(""),[ie,xe]=g.useState(""),[Y,ge]=g.useState(!1),[F,me]=g.useState("username"),[D,ae]=g.useState("0"),[fe,Ae]=g.useState(""),[Te,ue]=g.useState(!1),Z=m==="setup",re=m==="register",J=Mi(h?.registrationMode),T=re&&J==="email",k=re&&J==="discord";async function B(){if(!k){if((Z||re)&&ne!==ie){Ae("两次输入的密码不一致");return}ue(!0),Ae("");try{const Q=Z?"/api/auth/setup":re?"/api/auth/register":"/api/auth/login",O=T?op(z):$,d=m==="login"?{identifier:$,password:ne}:{username:O,password:ne,displayName:y,email:z,discordUserId:Z?ee:"",registrationEnabled:Z?Y:void 0,registrationMode:Z?F:void 0,defaultBalance:Z?Number(D||0):void 0},x=await pe(Q,{method:"POST",body:JSON.stringify(d)});L(x.session)}catch(Q){Ae(Q instanceof Error?Q.message:"操作失败")}finally{ue(!1)}}}return n.jsxs("main",{className:"auth-page","data-theme":c,children:[n.jsxs("header",{className:"auth-topbar",children:[n.jsxs("button",{className:"auth-brand",onClick:E,children:[n.jsx("span",{className:"brand-mark",children:"C"}),n.jsx("strong",{children:"CAPI"})]}),n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>r(c==="dark"?"light":"dark"),children:[n.jsx(Ot,{name:c==="dark"?"sun":"moon"}),n.jsx("span",{children:c==="dark"?"浅色":"暗色"})]})]}),n.jsxs("section",{className:"auth-stage",children:[n.jsxs("div",{className:"auth-intro",children:[n.jsx("span",{children:Z?"First Run":"Welcome Back"}),n.jsx("h1",{children:Z?"初始化 CAPI":re?"创建账号":"登录"}),n.jsx("p",{children:Z?"创建第一个管理员账号,完成后即可进入控制台。":"使用你的 CAPI 账号继续。"})]}),n.jsxs("form",{className:"auth-form",onSubmit:Q=>{Q.preventDefault(),B()},children:[k?n.jsxs("div",{className:"auth-discord-register",children:[n.jsx("strong",{children:"使用 Discord 创建账号"}),n.jsx("span",{children:"继续后会按站点设置校验服务器和身份组。"}),h?.discordEnabled?n.jsx("a",{className:"discord-login-button",href:"/api/auth/discord/start",children:"继续使用 Discord"}):n.jsx("div",{className:"auth-message",children:"管理员还没有启用 Discord 登录"})]}):n.jsxs(n.Fragment,{children:[m!=="login"&&n.jsxs("label",{children:[n.jsx("span",{children:"显示名称"}),n.jsx("input",{value:y,onChange:Q=>R(Q.target.value),autoComplete:"name",placeholder:"CAPI"})]}),!T&&n.jsxs("label",{children:[n.jsx("span",{children:m==="login"?"账号或邮箱":"账号"}),n.jsx("input",{value:$,onChange:Q=>C(Q.target.value),autoComplete:"username",placeholder:m==="login"?"输入账号或邮箱":"3-32 位字母、数字、_ 或 -"})]}),(Z||T)&&n.jsxs("label",{children:[n.jsx("span",{children:T?"邮箱":"邮箱(可选)"}),n.jsx("input",{type:"email",value:z,onChange:Q=>P(Q.target.value),autoComplete:"email",placeholder:"name@example.com"})]}),Z&&n.jsxs(n.Fragment,{children:[n.jsxs("label",{children:[n.jsx("span",{children:"Discord 用户 ID(可选)"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:ee,onChange:Q=>de(Q.target.value),placeholder:"绑定管理员 Discord 账号"})]}),n.jsxs("div",{className:"setup-options",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"开放注册"}),n.jsx("button",{type:"button",className:Y?"ios-switch is-on":"ios-switch","aria-pressed":Y,onClick:()=>ge(Q=>!Q),children:n.jsx("span",{})})]}),n.jsxs("label",{children:[n.jsx("span",{children:"注册方式"}),n.jsxs("select",{value:F,onChange:Q=>me(Mi(Q.target.value)),children:[n.jsx("option",{value:"username",children:"账号密码"}),n.jsx("option",{value:"email",children:"邮箱"}),n.jsx("option",{value:"discord",children:"Discord"})]})]}),n.jsxs("label",{children:[n.jsx("span",{children:"新用户初始额度"}),n.jsx("input",{type:"number",min:"0",step:"0.01",value:D,onChange:Q=>ae(Q.target.value)})]})]})]}),n.jsxs("label",{children:[n.jsx("span",{children:"密码"}),n.jsx("input",{type:"password",value:ne,onChange:Q=>le(Q.target.value),autoComplete:m==="login"?"current-password":"new-password",placeholder:"至少 8 个字符"})]}),m!=="login"&&n.jsxs("label",{children:[n.jsx("span",{children:"确认密码"}),n.jsx("input",{type:"password",value:ie,onChange:Q=>xe(Q.target.value),autoComplete:"new-password",placeholder:"再次输入密码"})]}),n.jsx("div",{className:"auth-message",role:"status",children:fe}),n.jsx("button",{className:"primary-button auth-submit",type:"submit",disabled:Te,children:Te?"请稍候":Z?"创建管理员":re?"注册":"登录"})]}),!Z&&!k&&h?.discordEnabled&&n.jsx("a",{className:"discord-login-button",href:"/api/auth/discord/start",children:"使用 Discord 登录"}),!Z&&n.jsx("div",{className:"auth-switch",children:m==="login"&&h?.registrationEnabled?n.jsx("button",{type:"button",onClick:()=>A("register"),children:"创建账号"}):n.jsx("button",{type:"button",onClick:()=>A("login"),children:"返回登录"})})]})]})]})}const fp=[1,1.5,2,2.5,3,4,5,6,8,10];function mp(c){if(!(c>0))return 1;const m=Math.floor(Math.log10(c)),h=Math.pow(10,m),r=c/h;return(fp.find(E=>r<=E)??10)*h}const hm=88;function hp(c){const m=c.split("-");return m.length===3?`${m[1]}/${m[2]}`:c}function pp(){const[c,m]=g.useState(14),[h,r]=g.useState(null),[A,E]=g.useState(!0),[L,$]=g.useState(!1),[C,y]=g.useState("");g.useEffect(()=>{let Y=!1;return E(!0),pe(`/api/account/usage?days=${c}&timezoneOffset=${new Date().getTimezoneOffset()}`).then(ge=>{Y||(r({...ge.usage,daily:be(ge.usage?.daily),models:be(ge.usage?.models)}),$(!1))}).catch(()=>{Y||$(!0)}).finally(()=>{Y||E(!1)}),()=>{Y=!0}},[c]);const R=h?.daily??[],z=h?.models??[],P=mp(Math.max(0,...R.map(Y=>Y.cost))),ee=Math.max(0,...z.map(Y=>Y.cost)),de=R.reduce((Y,ge)=>!Y||ge.cost>Y.cost?ge:Y,null),ne=Math.max(1,Math.ceil(R.length/5)),le=R.find(Y=>Y.day===C)||null,ie=le?R.indexOf(le):-1,xe=h?h.today.cost-h.yesterday.cost:0;return n.jsxs("section",{className:"account-section usage-section",children:[n.jsx("div",{className:"account-section-title",children:n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Usage"}),n.jsx("h2",{children:"用量概览"})]})}),!h&&A&&n.jsx("p",{className:"usage-placeholder",children:"正在统计用量…"}),!h&&!A&&L&&n.jsx("p",{className:"usage-placeholder",children:"用量加载失败,请稍后重试"}),h&&n.jsxs("div",{className:A?"usage-body is-refreshing":"usage-body",children:[n.jsxs("div",{className:"usage-kpi",children:[n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"今日消费"}),n.jsx("strong",{children:St(h.today.cost)}),n.jsxs("small",{children:["较昨日 ",xe>=0?"+":"−",St(Math.abs(xe))]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"本月消费"}),n.jsx("strong",{children:St(h.month.cost)}),n.jsxs("small",{children:[ml(h.month.requests)," 次请求"]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"今日请求"}),n.jsx("strong",{children:ml(h.today.requests)}),n.jsxs("small",{children:["成功率 ",h.today.successRate,"%"]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"累计消费"}),n.jsx("strong",{children:St(h.total.cost)}),n.jsxs("small",{children:[ml(h.total.requests)," 次请求"]})]})]}),n.jsx("div",{className:"usage-range",role:"group","aria-label":"统计范围",children:[7,14,30].map(Y=>n.jsxs("button",{type:"button",className:c===Y?"selected":"","aria-pressed":c===Y,onClick:()=>m(Y),children:["近 ",Y," 天"]},Y))}),n.jsxs("div",{className:"usage-block",children:[n.jsxs("div",{className:"usage-block-head",children:[n.jsx("strong",{children:"每日消费"}),n.jsxs("span",{children:["近 ",h.rangeDays," 天"]})]}),R.length===0||P<=0?n.jsx("p",{className:"usage-placeholder",children:"这段时间还没有消费记录"}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"usage-plot",children:[n.jsx("div",{className:"usage-grid","aria-hidden":"true",children:[1,.5,0].map(Y=>n.jsx("div",{className:"usage-gridline",style:{bottom:`${Y*hm}%`},children:n.jsx("span",{children:St(P*Y)})},Y))}),n.jsxs("div",{className:"usage-columns",children:[R.map((Y,ge)=>{const F=P>0?Y.cost/P*hm:0,me=Y.cost>0,D=me&&de!==null&&Y.day===de.day,ae=ge%ne===0||ge===R.length-1;return n.jsxs("div",{className:"usage-column",children:[n.jsxs("button",{type:"button",className:C===Y.day?"usage-column-hit is-hovered":"usage-column-hit",onMouseEnter:()=>y(Y.day),onMouseLeave:()=>y(""),onFocus:()=>y(Y.day),onBlur:()=>y(""),"aria-label":`${Y.day} 消费 ${St(Y.cost)},${Y.requests} 次请求`,children:[me&&n.jsx("span",{className:"usage-column-bar",style:{height:`${F}%`}}),D&&n.jsx("span",{className:"usage-column-peak",style:{bottom:`calc(${F}% + 6px)`},children:St(Y.cost)})]}),n.jsx("span",{className:"usage-column-tick",children:ae?hp(Y.day):""})]},Y.day)}),le&&n.jsxs("div",{className:"usage-tooltip",style:{left:`${(ie+.5)/R.length*100}%`},role:"status",children:[n.jsx("strong",{children:St(le.cost)}),n.jsx("span",{children:le.day}),n.jsxs("span",{children:[le.requests," 次请求"]})]})]})]}),n.jsxs("details",{className:"usage-table-toggle",children:[n.jsx("summary",{children:"查看数据表"}),n.jsxs("div",{className:"usage-table",children:[n.jsxs("div",{className:"usage-table-head",children:[n.jsx("span",{children:"日期"}),n.jsx("span",{children:"请求"}),n.jsx("span",{children:"消费"})]}),R.slice().reverse().map(Y=>n.jsxs("div",{className:"usage-table-row",children:[n.jsx("span",{children:Y.day}),n.jsx("span",{children:Y.requests}),n.jsx("span",{children:St(Y.cost)})]},Y.day))]})]})]})]}),n.jsxs("div",{className:"usage-block",children:[n.jsxs("div",{className:"usage-block-head",children:[n.jsx("strong",{children:"按模型拆分"}),n.jsxs("span",{children:["近 ",h.rangeDays," 天消费"]})]}),z.length===0?n.jsx("p",{className:"usage-placeholder",children:"这段时间还没有调用记录"}):n.jsx("div",{className:"usage-models",children:z.map(Y=>n.jsxs("div",{className:"usage-model-row",children:[n.jsx("span",{className:"usage-model-name",title:Y.model,children:Y.model}),n.jsx("span",{className:"usage-model-track",children:n.jsx("span",{className:"usage-model-bar",style:{width:`${ee>0?Y.cost/ee*100:0}%`}})}),n.jsx("span",{className:"usage-model-value",children:St(Y.cost)})]},Y.model))})]})]})]})}function vp({theme:c,setTheme:m,goHome:h,openLogin:r}){const[A,E]=g.useState(null),[L,$]=g.useState([]),[C,y]=g.useState(null),[R,z]=g.useState(!1),[P,ee]=g.useState(""),[de,ne]=g.useState(""),[le,ie]=g.useState("");async function xe(){try{const[D,ae,fe]=await Promise.all([pe("/api/account/me"),pe("/api/catalog/models"),pe("/api/account/check-in")]);E({...D,apiKeys:be(D.apiKeys)}),$(be(ae.models).map(cs)),y(fe.checkIn)}catch{r()}}g.useEffect(()=>{xe()},[]);async function Y(){if(!(!C?.enabled||C.claimed||R)){z(!0),ee("");try{const D=await pe("/api/account/check-in",{method:"POST",body:JSON.stringify({})});E(ae=>ae&&{...ae,user:D.user}),y(D.checkIn),ee(`签到成功,获得 ${D.reward.toFixed(2)} 额度`)}catch(D){ee(D instanceof Error?D.message:"签到失败,请稍后重试")}finally{z(!1)}}}async function ge(){try{const D=await pe("/api/account/api-keys",{method:"POST",body:JSON.stringify({name:"My API Key"})});ne(D.secret),ie("新密钥只显示这一次"),await xe()}catch(D){ie(D instanceof Error?D.message:"创建密钥失败")}}async function F(D){if(window.confirm("删除这个 API Key?使用它的请求会立即失效。"))try{await pe(`/api/account/api-keys/${D}`,{method:"DELETE"}),E(ae=>ae&&{...ae,apiKeys:ae.apiKeys.filter(fe=>fe.id!==D)}),ie("密钥已删除")}catch(ae){ie(ae instanceof Error?ae.message:"删除密钥失败")}}async function me(){await pe("/api/auth/logout",{method:"POST"}),h()}return n.jsxs("main",{className:"account-page","data-theme":c,children:[n.jsxs("header",{className:"account-topbar",children:[n.jsxs("button",{className:"auth-brand",onClick:h,children:[n.jsx("span",{className:"brand-mark",children:"C"}),n.jsx("strong",{children:"CAPI"})]}),n.jsxs("div",{className:"account-actions",children:[n.jsx("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>m(c==="dark"?"light":"dark"),children:n.jsx(Ot,{name:c==="dark"?"sun":"moon"})}),n.jsx("button",{className:"secondary-button",onClick:me,children:"退出"})]})]}),n.jsxs("section",{className:"account-content",children:[n.jsxs("div",{className:"account-heading",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"My CAPI"}),n.jsx("h1",{children:A?.user.name||"账户"})]}),n.jsxs("div",{className:"account-balance",children:[n.jsx("span",{children:"余额"}),n.jsx("strong",{children:A?A.user.balance.toFixed(2):"-"})]})]}),n.jsx(pp,{}),n.jsxs("section",{className:"account-section check-in-section",children:[n.jsxs("div",{className:"account-section-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Daily Reward"}),n.jsx("h2",{children:"每日签到"})]}),n.jsx("button",{className:"primary-button",disabled:!C?.enabled||!!C?.claimed||R,onClick:Y,children:R?"领取中":C?.claimed?"今日已签到":C?.enabled?"签到领额度":"暂未开放"})]}),n.jsxs("div",{className:"check-in-summary",children:[n.jsxs("div",{children:[n.jsx("span",{children:"今日状态"}),n.jsx("strong",{children:C?.claimed?`已领取 ${C.reward.toFixed(2)}`:C?.enabled?"等待签到":"活动关闭"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"随机奖励"}),n.jsx("strong",{children:C?`${C.minReward.toFixed(2)} - ${C.maxReward.toFixed(2)}`:"-"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"结算日期"}),n.jsx("strong",{children:C?.day||"北京时间"})]})]}),n.jsx("p",{className:"check-in-note",children:"每天按北京时间 00:00 刷新,奖励领取后直接计入账户余额。"}),P&&n.jsx("p",{className:"account-message check-in-message",role:"status",children:P})]}),n.jsxs("section",{className:"account-section",children:[n.jsxs("div",{className:"account-section-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"API Keys"}),n.jsx("h2",{children:"API 密钥"})]}),n.jsx("button",{className:"primary-button",onClick:ge,children:"创建密钥"})]}),de&&n.jsx("code",{className:"one-time-secret",children:de}),le&&n.jsx("p",{className:"account-message",children:le}),n.jsxs("div",{className:"account-key-list",children:[A?.apiKeys?.map(D=>n.jsxs("div",{className:"account-key-item",children:[n.jsx("span",{className:"account-key-mark","aria-hidden":"true",children:n.jsx(Ot,{name:"key"})}),n.jsxs("div",{className:"account-key-info",children:[n.jsx("strong",{children:D.name}),n.jsxs("code",{children:[D.prefix,"…"]})]}),n.jsx(Dt,{tone:D.status,children:_t(D.status)}),n.jsx("button",{className:"icon-button","aria-label":`删除 ${D.name}`,title:"删除密钥",onClick:()=>F(D.id),children:n.jsx(Ot,{name:"ban"})})]},D.id)),be(A?.apiKeys).length===0&&n.jsx("div",{className:"empty",children:"还没有 API 密钥"})]})]}),n.jsxs("section",{className:"account-section",children:[n.jsx("div",{className:"account-section-title",children:n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Models"}),n.jsx("h2",{children:"可用模型"})]})}),n.jsxs("div",{className:"account-model-grid",children:[L.map(D=>n.jsxs("article",{children:[n.jsx("span",{children:D.vendor}),n.jsx("strong",{children:D.name}),n.jsx("p",{children:D.description}),n.jsx("code",{children:D.id})]},D.id)),L.length===0&&n.jsx("div",{className:"account-model-empty",children:"暂无可用模型,管理员配置渠道后将在此展示"})]})]})]})]})}function yp({theme:c,setTheme:m,enterConsole:h}){return n.jsxs("main",{className:"public-home","data-theme":c,children:[n.jsxs("header",{className:"home-topbar",children:[n.jsxs("div",{className:"home-brand",children:[n.jsx("div",{className:"brand-mark",children:"C"}),n.jsxs("div",{children:[n.jsx("strong",{children:"CAPI"}),n.jsx("span",{children:"AI 聚合网关"})]})]}),n.jsxs("div",{className:"home-actions",children:[n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>m(c==="dark"?"light":"dark"),children:[n.jsx(Ot,{name:c==="dark"?"sun":"moon"}),n.jsx("span",{children:c==="dark"?"浅色":"暗色"})]}),n.jsx("button",{className:"primary-button",onClick:h,children:"控制台"})]})]}),n.jsxs("section",{className:"home-hero",children:[n.jsxs("div",{className:"home-copy",children:[n.jsx("span",{className:"home-kicker",children:"兼容 OpenAI 格式的网关"}),n.jsxs("h1",{children:["CAPI",n.jsx("span",{children:"轻量 AI 聚合网关"})]}),n.jsx("p",{children:"面向个人用户和团队的模型接入层。把 API Key、额度、模型渠道和调用日志放在一个清爽控制台里,保持轻量,也便于排障。"}),n.jsx("div",{className:"home-cta",children:n.jsx("button",{className:"primary-button",onClick:h,children:"进入控制台"})}),n.jsxs("div",{className:"integration-row","aria-label":"网关能力概览",children:[n.jsx("span",{children:"网关能力"}),n.jsxs("div",{children:[n.jsx("span",{children:"OpenAI 兼容接口"}),n.jsx("span",{children:"额度控制"}),n.jsx("span",{children:"调用审计"})]})]})]}),n.jsxs("div",{className:"gateway-terminal","aria-label":"CAPI 终端请求示意",children:[n.jsxs("div",{className:"terminal-titlebar",children:[n.jsxs("div",{className:"terminal-dots","aria-hidden":"true",children:[n.jsx("span",{}),n.jsx("span",{}),n.jsx("span",{})]}),n.jsx("strong",{children:"CAPI Terminal"}),n.jsxs("div",{className:"terminal-status",children:[n.jsx("span",{className:"pulse-dot"}),n.jsx("strong",{children:"Online"})]})]}),n.jsxs("div",{className:"terminal-endpoint",children:[n.jsx("span",{children:"POST"}),n.jsx("strong",{children:"/v1/chat/completions"})]}),n.jsxs("div",{className:"terminal-body",children:[n.jsxs("div",{className:"terminal-block",children:[n.jsx("span",{children:"REQUEST"}),n.jsx("pre",{children:`curl https://api.capi.local/v1/chat/completions \\ +`+a.stack}}var _=Object.prototype.hasOwnProperty,Ee=u.unstable_scheduleCallback,et=u.unstable_cancelCallback,xt=u.unstable_shouldYield,ft=u.unstable_requestPaint,tt=u.unstable_now,zi=u.unstable_getCurrentPriorityLevel,hn=u.unstable_ImmediatePriority,ia=u.unstable_UserBlockingPriority,ua=u.unstable_NormalPriority,Oi=u.unstable_LowPriority,w=u.unstable_IdlePriority,K=u.log,te=u.unstable_setDisableYieldValue,W=null,ye=null;function qe(e){if(typeof K=="function"&&te(e),ye&&typeof ye.setStrictMode=="function")try{ye.setStrictMode(W,e)}catch{}}var Ze=Math.clz32?Math.clz32:ca,Ut=Math.log,Rl=Math.LN2;function ca(e){return e>>>=0,e===0?32:31-(Ut(e)/Rl|0)|0}var Ea=256,Ma=262144,wl=4194304;function hl(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function os(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var s=0,i=e.suspendedLanes,c=e.pingedLanes;e=e.warmLanes;var o=a&134217727;return o!==0?(a=o&~i,a!==0?s=hl(a):(c&=o,c!==0?s=hl(c):l||(l=o&~e,l!==0&&(s=hl(l))))):(o=a&~i,o!==0?s=hl(o):c!==0?s=hl(c):l||(l=a&~e,l!==0&&(s=hl(l)))),s===0?0:t!==0&&t!==s&&(t&i)===0&&(i=s&-s,l=t&-t,i>=l||i===32&&(l&4194048)!==0)?t:s}function pn(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Am(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function ao(){var e=wl;return wl<<=1,(wl&62914560)===0&&(wl=4194304),e}function _i(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function vn(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Cm(e,t,l,a,s,i){var c=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var o=e.entanglements,f=e.expirationTimes,j=e.hiddenUpdates;for(l=c&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var _m=/[\n"\\]/g;function Xt(e){return e.replace(_m,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function Bi(e,t,l,a,s,i,c,o){e.name="",c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?e.type=c:e.removeAttribute("type"),t!=null?c==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+Qt(t)):e.value!==""+Qt(t)&&(e.value=""+Qt(t)):c!=="submit"&&c!=="reset"||e.removeAttribute("value"),t!=null?qi(e,c,Qt(t)):l!=null?qi(e,c,Qt(l)):a!=null&&e.removeAttribute("value"),s==null&&i!=null&&(e.defaultChecked=!!i),s!=null&&(e.checked=s&&typeof s!="function"&&typeof s!="symbol"),o!=null&&typeof o!="function"&&typeof o!="symbol"&&typeof o!="boolean"?e.name=""+Qt(o):e.removeAttribute("name")}function yo(e,t,l,a,s,i,c,o){if(i!=null&&typeof i!="function"&&typeof i!="symbol"&&typeof i!="boolean"&&(e.type=i),t!=null||l!=null){if(!(i!=="submit"&&i!=="reset"||t!=null)){Hi(e);return}l=l!=null?""+Qt(l):"",t=t!=null?""+Qt(t):l,o||t===e.value||(e.value=t),e.defaultValue=t}a=a??s,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=o?e.checked:!!a,e.defaultChecked=!!a,c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"&&(e.name=c),Hi(e)}function qi(e,t,l){t==="number"&&fs(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function Ra(e,t,l,a){if(e=e.options,t){t={};for(var s=0;s"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Qi=!1;if(yl)try{var xn={};Object.defineProperty(xn,"passive",{get:function(){Qi=!0}}),window.addEventListener("test",xn,xn),window.removeEventListener("test",xn,xn)}catch{Qi=!1}var Bl=null,Xi=null,hs=null;function Ao(){if(hs)return hs;var e,t=Xi,l=t.length,a,s="value"in Bl?Bl.value:Bl.textContent,i=s.length;for(e=0;e=Nn),Oo=" ",_o=!1;function Do(e,t){switch(e){case"keyup":return sh.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Uo(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var qa=!1;function uh(e,t){switch(e){case"compositionend":return Uo(t);case"keypress":return t.which!==32?null:(_o=!0,Oo);case"textInput":return e=t.data,e===Oo&&_o?null:e;default:return null}}function ch(e,t){if(qa)return e==="compositionend"||!$i&&Do(e,t)?(e=Ao(),hs=Xi=Bl=null,qa=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Lo(l)}}function Qo(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Qo(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Xo(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=fs(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=fs(e.document)}return t}function Ii(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var vh=yl&&"documentMode"in document&&11>=document.documentMode,Ga=null,Pi=null,En=null,eu=!1;function Ko(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;eu||Ga==null||Ga!==fs(a)||(a=Ga,"selectionStart"in a&&Ii(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),En&&Tn(En,a)||(En=a,a=ui(Pi,"onSelect"),0>=c,s-=c,ol=1<<32-Ze(t)+s|l<ze?(Ue=oe,oe=null):Ue=oe.sibling;var He=S(v,oe,b[ze],H);if(He===null){oe===null&&(oe=Ue);break}e&&oe&&He.alternate===null&&t(v,oe),p=i(He,p,ze),we===null?he=He:we.sibling=He,we=He,oe=Ue}if(ze===b.length)return l(v,oe),Re&&bl(v,ze),he;if(oe===null){for(;zeze?(Ue=oe,oe=null):Ue=oe.sibling;var sa=S(v,oe,He.value,H);if(sa===null){oe===null&&(oe=Ue);break}e&&oe&&sa.alternate===null&&t(v,oe),p=i(sa,p,ze),we===null?he=sa:we.sibling=sa,we=sa,oe=Ue}if(He.done)return l(v,oe),Re&&bl(v,ze),he;if(oe===null){for(;!He.done;ze++,He=b.next())He=q(v,He.value,H),He!==null&&(p=i(He,p,ze),we===null?he=He:we.sibling=He,we=He);return Re&&bl(v,ze),he}for(oe=a(oe);!He.done;ze++,He=b.next())He=M(oe,v,ze,He.value,H),He!==null&&(e&&He.alternate!==null&&oe.delete(He.key===null?ze:He.key),p=i(He,p,ze),we===null?he=He:we.sibling=He,we=He);return e&&oe.forEach(function(H0){return t(v,H0)}),Re&&bl(v,ze),he}function Qe(v,p,b,H){if(typeof b=="object"&&b!==null&&b.type===ne&&b.key===null&&(b=b.props.children),typeof b=="object"&&b!==null){switch(b.$$typeof){case ee:e:{for(var he=b.key;p!==null;){if(p.key===he){if(he=b.type,he===ne){if(p.tag===7){l(v,p.sibling),H=s(p,b.props.children),H.return=v,v=H;break e}}else if(p.elementType===he||typeof he=="object"&&he!==null&&he.$$typeof===ae&&ba(he)===p.type){l(v,p.sibling),H=s(p,b.props),Un(H,b),H.return=v,v=H;break e}l(v,p);break}else t(v,p);p=p.sibling}b.type===ne?(H=ha(b.props.children,v.mode,H,b.key),H.return=v,v=H):(H=As(b.type,b.key,b.props,null,v.mode,H),Un(H,b),H.return=v,v=H)}return c(v);case de:e:{for(he=b.key;p!==null;){if(p.key===he)if(p.tag===4&&p.stateNode.containerInfo===b.containerInfo&&p.stateNode.implementation===b.implementation){l(v,p.sibling),H=s(p,b.children||[]),H.return=v,v=H;break e}else{l(v,p);break}else t(v,p);p=p.sibling}H=uu(b,v.mode,H),H.return=v,v=H}return c(v);case ae:return b=ba(b),Qe(v,p,b,H)}if(J(b))return ce(v,p,b,H);if(ue(b)){if(he=ue(b),typeof he!="function")throw Error(r(150));return b=he.call(b),je(v,p,b,H)}if(typeof b.then=="function")return Qe(v,p,_s(b),H);if(b.$$typeof===Y)return Qe(v,p,Es(v,b),H);Ds(v,b)}return typeof b=="string"&&b!==""||typeof b=="number"||typeof b=="bigint"?(b=""+b,p!==null&&p.tag===6?(l(v,p.sibling),H=s(p,b),H.return=v,v=H):(l(v,p),H=iu(b,v.mode,H),H.return=v,v=H),c(v)):l(v,p)}return function(v,p,b,H){try{Dn=0;var he=Qe(v,p,b,H);return Wa=null,he}catch(oe){if(oe===$a||oe===zs)throw oe;var we=wt(29,oe,null,v.mode);return we.lanes=H,we.return=v,we}}}var ja=hr(!0),pr=hr(!1),kl=!1;function bu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function xu(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ql(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Xl(e,t,l){var a=e.updateQueue;if(a===null)return null;if(a=a.shared,(Be&2)!==0){var s=a.pending;return s===null?t.next=t:(t.next=s.next,s.next=t),a.pending=t,t=Ns(e),Io(e,null,l),t}return Ss(e,a,t,l),Ns(e)}function Rn(e,t,l){if(t=t.updateQueue,t!==null&&(t=t.shared,(l&4194048)!==0)){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,so(e,l)}}function ju(e,t){var l=e.updateQueue,a=e.alternate;if(a!==null&&(a=a.updateQueue,l===a)){var s=null,i=null;if(l=l.firstBaseUpdate,l!==null){do{var c={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};i===null?s=i=c:i=i.next=c,l=l.next}while(l!==null);i===null?s=i=t:i=i.next=t}else s=i=t;l={baseState:a.baseState,firstBaseUpdate:s,lastBaseUpdate:i,shared:a.shared,callbacks:a.callbacks},e.updateQueue=l;return}e=l.lastBaseUpdate,e===null?l.firstBaseUpdate=t:e.next=t,l.lastBaseUpdate=t}var Su=!1;function wn(){if(Su){var e=Ja;if(e!==null)throw e}}function Hn(e,t,l,a){Su=!1;var s=e.updateQueue;kl=!1;var i=s.firstBaseUpdate,c=s.lastBaseUpdate,o=s.shared.pending;if(o!==null){s.shared.pending=null;var f=o,j=f.next;f.next=null,c===null?i=j:c.next=j,c=f;var U=e.alternate;U!==null&&(U=U.updateQueue,o=U.lastBaseUpdate,o!==c&&(o===null?U.firstBaseUpdate=j:o.next=j,U.lastBaseUpdate=f))}if(i!==null){var q=s.baseState;c=0,U=j=f=null,o=i;do{var S=o.lane&-536870913,M=S!==o.lane;if(M?(De&S)===S:(a&S)===S){S!==0&&S===Va&&(Su=!0),U!==null&&(U=U.next={lane:0,tag:o.tag,payload:o.payload,callback:null,next:null});e:{var ce=e,je=o;S=t;var Qe=l;switch(je.tag){case 1:if(ce=je.payload,typeof ce=="function"){q=ce.call(Qe,q,S);break e}q=ce;break e;case 3:ce.flags=ce.flags&-65537|128;case 0:if(ce=je.payload,S=typeof ce=="function"?ce.call(Qe,q,S):ce,S==null)break e;q=z({},q,S);break e;case 2:kl=!0}}S=o.callback,S!==null&&(e.flags|=64,M&&(e.flags|=8192),M=s.callbacks,M===null?s.callbacks=[S]:M.push(S))}else M={lane:S,tag:o.tag,payload:o.payload,callback:o.callback,next:null},U===null?(j=U=M,f=q):U=U.next=M,c|=S;if(o=o.next,o===null){if(o=s.shared.pending,o===null)break;M=o,o=M.next,M.next=null,s.lastBaseUpdate=M,s.shared.pending=null}}while(!0);U===null&&(f=q),s.baseState=f,s.firstBaseUpdate=j,s.lastBaseUpdate=U,i===null&&(s.shared.lanes=0),$l|=c,e.lanes=c,e.memoizedState=q}}function vr(e,t){if(typeof e!="function")throw Error(r(191,e));e.call(t)}function yr(e,t){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;ei?i:8;var c=T.T,o={};T.T=o,Lu(e,!1,t,l);try{var f=s(),j=T.S;if(j!==null&&j(o,f),f!==null&&typeof f=="object"&&typeof f.then=="function"){var U=Ch(f,a);Gn(e,t,U,Yt(e))}else Gn(e,t,a,Yt(e))}catch(q){Gn(e,t,{then:function(){},status:"rejected",reason:q},Yt())}finally{k.p=i,c!==null&&o.types!==null&&(c.types=o.types),T.T=c}}function _h(){}function Gu(e,t,l,a){if(e.tag!==5)throw Error(r(476));var s=$r(e).queue;Jr(e,s,t,B,l===null?_h:function(){return Wr(e),l(a)})}function $r(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:B,baseState:B,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Nl,lastRenderedState:B},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Nl,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Wr(e){var t=$r(e);t.next===null&&(t=e.alternate.memoizedState),Gn(e,t.next.queue,{},Yt())}function Yu(){return pt(ls)}function Fr(){return at().memoizedState}function Ir(){return at().memoizedState}function Dh(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=Yt();e=Ql(l);var a=Xl(t,e,l);a!==null&&(zt(a,t,l),Rn(a,t,l)),t={cache:pu()},e.payload=t;return}t=t.return}}function Uh(e,t,l){var a=Yt();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},ks(e)?ed(t,l):(l=nu(e,t,l,a),l!==null&&(zt(l,e,a),td(l,t,a)))}function Pr(e,t,l){var a=Yt();Gn(e,t,l,a)}function Gn(e,t,l,a){var s={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(ks(e))ed(t,s);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var c=t.lastRenderedState,o=i(c,l);if(s.hasEagerState=!0,s.eagerState=o,Rt(o,c))return Ss(e,t,s,0),Xe===null&&js(),!1}catch{}if(l=nu(e,t,s,a),l!==null)return zt(l,e,a),td(l,t,a),!0}return!1}function Lu(e,t,l,a){if(a={lane:2,revertLane:bc(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},ks(e)){if(t)throw Error(r(479))}else t=nu(e,l,a,2),t!==null&&zt(t,e,2)}function ks(e){var t=e.alternate;return e===Me||t!==null&&t===Me}function ed(e,t){Ia=ws=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function td(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,so(e,l)}}var Yn={readContext:pt,use:qs,useCallback:Fe,useContext:Fe,useEffect:Fe,useImperativeHandle:Fe,useLayoutEffect:Fe,useInsertionEffect:Fe,useMemo:Fe,useReducer:Fe,useRef:Fe,useState:Fe,useDebugValue:Fe,useDeferredValue:Fe,useTransition:Fe,useSyncExternalStore:Fe,useId:Fe,useHostTransitionStatus:Fe,useFormState:Fe,useActionState:Fe,useOptimistic:Fe,useMemoCache:Fe,useCacheRefresh:Fe};Yn.useEffectEvent=Fe;var ld={readContext:pt,use:qs,useCallback:function(e,t){return jt().memoizedState=[e,t===void 0?null:t],e},useContext:pt,useEffect:Gr,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,Ys(4194308,4,Qr.bind(null,t,e),l)},useLayoutEffect:function(e,t){return Ys(4194308,4,e,t)},useInsertionEffect:function(e,t){Ys(4,2,e,t)},useMemo:function(e,t){var l=jt();t=t===void 0?null:t;var a=e();if(Sa){qe(!0);try{e()}finally{qe(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=jt();if(l!==void 0){var s=l(t);if(Sa){qe(!0);try{l(t)}finally{qe(!1)}}}else s=t;return a.memoizedState=a.baseState=s,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:s},a.queue=e,e=e.dispatch=Uh.bind(null,Me,e),[a.memoizedState,e]},useRef:function(e){var t=jt();return e={current:e},t.memoizedState=e},useState:function(e){e=Ru(e);var t=e.queue,l=Pr.bind(null,Me,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:Bu,useDeferredValue:function(e,t){var l=jt();return qu(l,e,t)},useTransition:function(){var e=Ru(!1);return e=Jr.bind(null,Me,e.queue,!0,!1),jt().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=Me,s=jt();if(Re){if(l===void 0)throw Error(r(407));l=l()}else{if(l=t(),Xe===null)throw Error(r(349));(De&127)!==0||Nr(a,t,l)}s.memoizedState=l;var i={value:l,getSnapshot:t};return s.queue=i,Gr(Cr.bind(null,a,i,e),[e]),a.flags|=2048,en(9,{destroy:void 0},Ar.bind(null,a,i,l,t),null),l},useId:function(){var e=jt(),t=Xe.identifierPrefix;if(Re){var l=rl,a=ol;l=(a&~(1<<32-Ze(a)-1)).toString(32)+l,t="_"+t+"R_"+l,l=Hs++,0<\/script>",i=i.removeChild(i.firstChild);break;case"select":i=typeof a.is=="string"?c.createElement("select",{is:a.is}):c.createElement("select"),a.multiple?i.multiple=!0:a.size&&(i.size=a.size);break;default:i=typeof a.is=="string"?c.createElement(s,{is:a.is}):c.createElement(s)}}i[mt]=t,i[Nt]=a;e:for(c=t.child;c!==null;){if(c.tag===5||c.tag===6)i.appendChild(c.stateNode);else if(c.tag!==4&&c.tag!==27&&c.child!==null){c.child.return=c,c=c.child;continue}if(c===t)break e;for(;c.sibling===null;){if(c.return===null||c.return===t)break e;c=c.return}c.sibling.return=c.return,c=c.sibling}t.stateNode=i;e:switch(yt(i,s,a),s){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break e;case"img":a=!0;break e;default:a=!1}a&&Cl(t)}}return Je(t),tc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,l),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==a&&Cl(t);else{if(typeof a!="string"&&t.stateNode===null)throw Error(r(166));if(e=ve.current,Ka(t)){if(e=t.stateNode,l=t.memoizedProps,a=null,s=ht,s!==null)switch(s.tag){case 27:case 5:a=s.memoizedProps}e[mt]=t,e=!!(e.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||Sf(e.nodeValue,l)),e||Yl(t,!0)}else e=ci(e).createTextNode(a),e[mt]=t,t.stateNode=e}return Je(t),null;case 31:if(l=t.memoizedState,e===null||e.memoizedState!==null){if(a=Ka(t),l!==null){if(e===null){if(!a)throw Error(r(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(r(557));e[mt]=t}else pa(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Je(t),e=!1}else l=du(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return t.flags&256?(Bt(t),t):(Bt(t),null);if((t.flags&128)!==0)throw Error(r(558))}return Je(t),null;case 13:if(a=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(s=Ka(t),a!==null&&a.dehydrated!==null){if(e===null){if(!s)throw Error(r(318));if(s=t.memoizedState,s=s!==null?s.dehydrated:null,!s)throw Error(r(317));s[mt]=t}else pa(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;Je(t),s=!1}else s=du(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=s),s=!0;if(!s)return t.flags&256?(Bt(t),t):(Bt(t),null)}return Bt(t),(t.flags&128)!==0?(t.lanes=l,t):(l=a!==null,e=e!==null&&e.memoizedState!==null,l&&(a=t.child,s=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(s=a.alternate.memoizedState.cachePool.pool),i=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(i=a.memoizedState.cachePool.pool),i!==s&&(a.flags|=2048)),l!==e&&l&&(t.child.flags|=8192),Vs(t,t.updateQueue),Je(t),null);case 4:return Se(),e===null&&Nc(t.stateNode.containerInfo),Je(t),null;case 10:return jl(t.type),Je(t),null;case 19:if(x(lt),a=t.memoizedState,a===null)return Je(t),null;if(s=(t.flags&128)!==0,i=a.rendering,i===null)if(s)kn(a,!1);else{if(Ie!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(i=Rs(e),i!==null){for(t.flags|=128,kn(a,!1),e=i.updateQueue,t.updateQueue=e,Vs(t,e),t.subtreeFlags=0,e=l,l=t.child;l!==null;)Po(l,e),l=l.sibling;return G(lt,lt.current&1|2),Re&&bl(t,a.treeForkCount),t.child}e=e.sibling}a.tail!==null&&tt()>Is&&(t.flags|=128,s=!0,kn(a,!1),t.lanes=4194304)}else{if(!s)if(e=Rs(i),e!==null){if(t.flags|=128,s=!0,e=e.updateQueue,t.updateQueue=e,Vs(t,e),kn(a,!0),a.tail===null&&a.tailMode==="hidden"&&!i.alternate&&!Re)return Je(t),null}else 2*tt()-a.renderingStartTime>Is&&l!==536870912&&(t.flags|=128,s=!0,kn(a,!1),t.lanes=4194304);a.isBackwards?(i.sibling=t.child,t.child=i):(e=a.last,e!==null?e.sibling=i:t.child=i,a.last=i)}return a.tail!==null?(e=a.tail,a.rendering=e,a.tail=e.sibling,a.renderingStartTime=tt(),e.sibling=null,l=lt.current,G(lt,s?l&1|2:l&1),Re&&bl(t,a.treeForkCount),e):(Je(t),null);case 22:case 23:return Bt(t),Au(),a=t.memoizedState!==null,e!==null?e.memoizedState!==null!==a&&(t.flags|=8192):a&&(t.flags|=8192),a?(l&536870912)!==0&&(t.flags&128)===0&&(Je(t),t.subtreeFlags&6&&(t.flags|=8192)):Je(t),l=t.updateQueue,l!==null&&Vs(t,l.retryQueue),l=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(l=e.memoizedState.cachePool.pool),a=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),a!==l&&(t.flags|=2048),e!==null&&x(ga),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),jl(st),Je(t),null;case 25:return null;case 30:return null}throw Error(r(156,t.tag))}function qh(e,t){switch(ou(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return jl(st),Se(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return I(t),null;case 31:if(t.memoizedState!==null){if(Bt(t),t.alternate===null)throw Error(r(340));pa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(Bt(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(r(340));pa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return x(lt),null;case 4:return Se(),null;case 10:return jl(t.type),null;case 22:case 23:return Bt(t),Au(),e!==null&&x(ga),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return jl(st),null;case 25:return null;default:return null}}function Td(e,t){switch(ou(t),t.tag){case 3:jl(st),Se();break;case 26:case 27:case 5:I(t);break;case 4:Se();break;case 31:t.memoizedState!==null&&Bt(t);break;case 13:Bt(t);break;case 19:x(lt);break;case 10:jl(t.type);break;case 22:case 23:Bt(t),Au(),e!==null&&x(ga);break;case 24:jl(st)}}function Qn(e,t){try{var l=t.updateQueue,a=l!==null?l.lastEffect:null;if(a!==null){var s=a.next;l=s;do{if((l.tag&e)===e){a=void 0;var i=l.create,c=l.inst;a=i(),c.destroy=a}l=l.next}while(l!==s)}}catch(o){Ye(t,t.return,o)}}function Vl(e,t,l){try{var a=t.updateQueue,s=a!==null?a.lastEffect:null;if(s!==null){var i=s.next;a=i;do{if((a.tag&e)===e){var c=a.inst,o=c.destroy;if(o!==void 0){c.destroy=void 0,s=t;var f=l,j=o;try{j()}catch(U){Ye(s,f,U)}}}a=a.next}while(a!==i)}}catch(U){Ye(t,t.return,U)}}function Ed(e){var t=e.updateQueue;if(t!==null){var l=e.stateNode;try{yr(t,l)}catch(a){Ye(e,e.return,a)}}}function Md(e,t,l){l.props=Na(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(a){Ye(e,t,a)}}function Xn(e,t){try{var l=e.ref;if(l!==null){switch(e.tag){case 26:case 27:case 5:var a=e.stateNode;break;case 30:a=e.stateNode;break;default:a=e.stateNode}typeof l=="function"?e.refCleanup=l(a):l.current=a}}catch(s){Ye(e,t,s)}}function dl(e,t){var l=e.ref,a=e.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(s){Ye(e,t,s)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(s){Ye(e,t,s)}else l.current=null}function zd(e){var t=e.type,l=e.memoizedProps,a=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":l.autoFocus&&a.focus();break e;case"img":l.src?a.src=l.src:l.srcSet&&(a.srcset=l.srcSet)}}catch(s){Ye(e,e.return,s)}}function lc(e,t,l){try{var a=e.stateNode;i0(a,e.type,l,t),a[Nt]=t}catch(s){Ye(e,e.return,s)}}function Od(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&ea(e.type)||e.tag===4}function ac(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Od(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&ea(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function nc(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(e,t):(t=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,t.appendChild(e),l=l._reactRootContainer,l!=null||t.onclick!==null||(t.onclick=vl));else if(a!==4&&(a===27&&ea(e.type)&&(l=e.stateNode,t=null),e=e.child,e!==null))for(nc(e,t,l),e=e.sibling;e!==null;)nc(e,t,l),e=e.sibling}function Js(e,t,l){var a=e.tag;if(a===5||a===6)e=e.stateNode,t?l.insertBefore(e,t):l.appendChild(e);else if(a!==4&&(a===27&&ea(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(Js(e,t,l),e=e.sibling;e!==null;)Js(e,t,l),e=e.sibling}function _d(e){var t=e.stateNode,l=e.memoizedProps;try{for(var a=e.type,s=t.attributes;s.length;)t.removeAttributeNode(s[0]);yt(t,a,l),t[mt]=e,t[Nt]=l}catch(i){Ye(e,e.return,i)}}var Tl=!1,ct=!1,sc=!1,Dd=typeof WeakSet=="function"?WeakSet:Set,dt=null;function Gh(e,t){if(e=e.containerInfo,Tc=pi,e=Xo(e),Ii(e)){if("selectionStart"in e)var l={start:e.selectionStart,end:e.selectionEnd};else e:{l=(l=e.ownerDocument)&&l.defaultView||window;var a=l.getSelection&&l.getSelection();if(a&&a.rangeCount!==0){l=a.anchorNode;var s=a.anchorOffset,i=a.focusNode;a=a.focusOffset;try{l.nodeType,i.nodeType}catch{l=null;break e}var c=0,o=-1,f=-1,j=0,U=0,q=e,S=null;t:for(;;){for(var M;q!==l||s!==0&&q.nodeType!==3||(o=c+s),q!==i||a!==0&&q.nodeType!==3||(f=c+a),q.nodeType===3&&(c+=q.nodeValue.length),(M=q.firstChild)!==null;)S=q,q=M;for(;;){if(q===e)break t;if(S===l&&++j===s&&(o=c),S===i&&++U===a&&(f=c),(M=q.nextSibling)!==null)break;q=S,S=q.parentNode}q=M}l=o===-1||f===-1?null:{start:o,end:f}}else l=null}l=l||{start:0,end:0}}else l=null;for(Ec={focusedElem:e,selectionRange:l},pi=!1,dt=t;dt!==null;)if(t=dt,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,dt=e;else for(;dt!==null;){switch(t=dt,i=t.alternate,e=t.flags,t.tag){case 0:if((e&4)!==0&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(l=0;l title"))),yt(i,a,l),i[mt]=e,rt(i),a=i;break e;case"link":var c=Gf("link","href",s).get(a+(l.href||""));if(c){for(var o=0;oQe&&(c=Qe,Qe=je,je=c);var v=ko(o,je),p=ko(o,Qe);if(v&&p&&(M.rangeCount!==1||M.anchorNode!==v.node||M.anchorOffset!==v.offset||M.focusNode!==p.node||M.focusOffset!==p.offset)){var b=q.createRange();b.setStart(v.node,v.offset),M.removeAllRanges(),je>Qe?(M.addRange(b),M.extend(p.node,p.offset)):(b.setEnd(p.node,p.offset),M.addRange(b))}}}}for(q=[],M=o;M=M.parentNode;)M.nodeType===1&&q.push({element:M,left:M.scrollLeft,top:M.scrollTop});for(typeof o.focus=="function"&&o.focus(),o=0;ol?32:l,T.T=null,l=fc,fc=null;var i=Fl,c=_l;if(ot=0,sn=Fl=null,_l=0,(Be&6)!==0)throw Error(r(331));var o=Be;if(Be|=4,Qd(i.current),Yd(i,i.current,c,l),Be=o,Wn(0,!1),ye&&typeof ye.onPostCommitFiberRoot=="function")try{ye.onPostCommitFiberRoot(W,i)}catch{}return!0}finally{k.p=s,T.T=a,cf(e,t)}}function rf(e,t,l){t=Zt(l,t),t=Ku(e.stateNode,t,2),e=Xl(e,t,2),e!==null&&(vn(e,2),fl(e))}function Ye(e,t,l){if(e.tag===3)rf(e,e,l);else for(;t!==null;){if(t.tag===3){rf(t,e,l);break}else if(t.tag===1){var a=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(Wl===null||!Wl.has(a))){e=Zt(l,e),l=rd(2),a=Xl(t,l,2),a!==null&&(dd(l,a,t,e),vn(a,2),fl(a));break}}t=t.return}}function vc(e,t,l){var a=e.pingCache;if(a===null){a=e.pingCache=new kh;var s=new Set;a.set(t,s)}else s=a.get(t),s===void 0&&(s=new Set,a.set(t,s));s.has(l)||(cc=!0,s.add(l),e=Vh.bind(null,e,t,l),t.then(e,e))}function Vh(e,t,l){var a=e.pingCache;a!==null&&a.delete(t),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,Xe===e&&(De&l)===l&&(Ie===4||Ie===3&&(De&62914560)===De&&300>tt()-Fs?(Be&2)===0&&un(e,0):oc|=l,nn===De&&(nn=0)),fl(e)}function df(e,t){t===0&&(t=ao()),e=ma(e,t),e!==null&&(vn(e,t),fl(e))}function Jh(e){var t=e.memoizedState,l=0;t!==null&&(l=t.retryLane),df(e,l)}function $h(e,t){var l=0;switch(e.tag){case 31:case 13:var a=e.stateNode,s=e.memoizedState;s!==null&&(l=s.retryLane);break;case 19:a=e.stateNode;break;case 22:a=e.stateNode._retryCache;break;default:throw Error(r(314))}a!==null&&a.delete(t),df(e,l)}function Wh(e,t){return Ee(e,t)}var ni=null,on=null,yc=!1,si=!1,gc=!1,Pl=0;function fl(e){e!==on&&e.next===null&&(on===null?ni=on=e:on=on.next=e),si=!0,yc||(yc=!0,Ih())}function Wn(e,t){if(!gc&&si){gc=!0;do for(var l=!1,a=ni;a!==null;){if(e!==0){var s=a.pendingLanes;if(s===0)var i=0;else{var c=a.suspendedLanes,o=a.pingedLanes;i=(1<<31-Ze(42|e)+1)-1,i&=s&~(c&~o),i=i&201326741?i&201326741|1:i?i|2:0}i!==0&&(l=!0,pf(a,i))}else i=De,i=os(a,a===Xe?i:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(i&3)===0||pn(a,i)||(l=!0,pf(a,i));a=a.next}while(l);gc=!1}}function Fh(){ff()}function ff(){si=yc=!1;var e=0;Pl!==0&&c0()&&(e=Pl);for(var t=tt(),l=null,a=ni;a!==null;){var s=a.next,i=mf(a,t);i===0?(a.next=null,l===null?ni=s:l.next=s,s===null&&(on=l)):(l=a,(e!==0||(i&3)!==0)&&(si=!0)),a=s}ot!==0&&ot!==5||Wn(e),Pl!==0&&(Pl=0)}function mf(e,t){for(var l=e.suspendedLanes,a=e.pingedLanes,s=e.expirationTimes,i=e.pendingLanes&-62914561;0o)break;var U=f.transferSize,q=f.initiatorType;U&&Nf(q)&&(f=f.responseEnd,c+=U*(f"u"?null:document;function wf(e,t,l){var a=rn;if(a&&typeof t=="string"&&t){var s=Xt(t);s='link[rel="'+e+'"][href="'+s+'"]',typeof l=="string"&&(s+='[crossorigin="'+l+'"]'),Rf.has(s)||(Rf.add(s),e={rel:e,crossOrigin:l,href:t},a.querySelector(s)===null&&(t=a.createElement("link"),yt(t,"link",e),rt(t),a.head.appendChild(t)))}}function y0(e){Dl.D(e),wf("dns-prefetch",e,null)}function g0(e,t){Dl.C(e,t),wf("preconnect",e,t)}function b0(e,t,l){Dl.L(e,t,l);var a=rn;if(a&&e&&t){var s='link[rel="preload"][as="'+Xt(t)+'"]';t==="image"&&l&&l.imageSrcSet?(s+='[imagesrcset="'+Xt(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(s+='[imagesizes="'+Xt(l.imageSizes)+'"]')):s+='[href="'+Xt(e)+'"]';var i=s;switch(t){case"style":i=dn(e);break;case"script":i=fn(e)}It.has(i)||(e=z({rel:"preload",href:t==="image"&&l&&l.imageSrcSet?void 0:e,as:t},l),It.set(i,e),a.querySelector(s)!==null||t==="style"&&a.querySelector(es(i))||t==="script"&&a.querySelector(ts(i))||(t=a.createElement("link"),yt(t,"link",e),rt(t),a.head.appendChild(t)))}}function x0(e,t){Dl.m(e,t);var l=rn;if(l&&e){var a=t&&typeof t.as=="string"?t.as:"script",s='link[rel="modulepreload"][as="'+Xt(a)+'"][href="'+Xt(e)+'"]',i=s;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":i=fn(e)}if(!It.has(i)&&(e=z({rel:"modulepreload",href:e},t),It.set(i,e),l.querySelector(s)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(ts(i)))return}a=l.createElement("link"),yt(a,"link",e),rt(a),l.head.appendChild(a)}}}function j0(e,t,l){Dl.S(e,t,l);var a=rn;if(a&&e){var s=Da(a).hoistableStyles,i=dn(e);t=t||"default";var c=s.get(i);if(!c){var o={loading:0,preload:null};if(c=a.querySelector(es(i)))o.loading=5;else{e=z({rel:"stylesheet",href:e,"data-precedence":t},l),(l=It.get(i))&&Rc(e,l);var f=c=a.createElement("link");rt(f),yt(f,"link",e),f._p=new Promise(function(j,U){f.onload=j,f.onerror=U}),f.addEventListener("load",function(){o.loading|=1}),f.addEventListener("error",function(){o.loading|=2}),o.loading|=4,ri(c,t,a)}c={type:"stylesheet",instance:c,count:1,state:o},s.set(i,c)}}}function S0(e,t){Dl.X(e,t);var l=rn;if(l&&e){var a=Da(l).hoistableScripts,s=fn(e),i=a.get(s);i||(i=l.querySelector(ts(s)),i||(e=z({src:e,async:!0},t),(t=It.get(s))&&wc(e,t),i=l.createElement("script"),rt(i),yt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(s,i))}}function N0(e,t){Dl.M(e,t);var l=rn;if(l&&e){var a=Da(l).hoistableScripts,s=fn(e),i=a.get(s);i||(i=l.querySelector(ts(s)),i||(e=z({src:e,async:!0,type:"module"},t),(t=It.get(s))&&wc(e,t),i=l.createElement("script"),rt(i),yt(i,"link",e),l.head.appendChild(i)),i={type:"script",instance:i,count:1,state:null},a.set(s,i))}}function Hf(e,t,l,a){var s=(s=ve.current)?oi(s):null;if(!s)throw Error(r(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(t=dn(l.href),l=Da(s).hoistableStyles,a=l.get(t),a||(a={type:"style",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){e=dn(l.href);var i=Da(s).hoistableStyles,c=i.get(e);if(c||(s=s.ownerDocument||s,c={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},i.set(e,c),(i=s.querySelector(es(e)))&&!i._p&&(c.instance=i,c.state.loading=5),It.has(e)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},It.set(e,l),i||A0(s,e,l,c.state))),t&&a===null)throw Error(r(528,""));return c}if(t&&a!==null)throw Error(r(529,""));return null;case"script":return t=l.async,l=l.src,typeof l=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=fn(l),l=Da(s).hoistableScripts,a=l.get(t),a||(a={type:"script",instance:null,count:0,state:null},l.set(t,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(r(444,e))}}function dn(e){return'href="'+Xt(e)+'"'}function es(e){return'link[rel="stylesheet"]['+e+"]"}function Bf(e){return z({},e,{"data-precedence":e.precedence,precedence:null})}function A0(e,t,l,a){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?a.loading=1:(t=e.createElement("link"),a.preload=t,t.addEventListener("load",function(){return a.loading|=1}),t.addEventListener("error",function(){return a.loading|=2}),yt(t,"link",l),rt(t),e.head.appendChild(t))}function fn(e){return'[src="'+Xt(e)+'"]'}function ts(e){return"script[async]"+e}function qf(e,t,l){if(t.count++,t.instance===null)switch(t.type){case"style":var a=e.querySelector('style[data-href~="'+Xt(l.href)+'"]');if(a)return t.instance=a,rt(a),a;var s=z({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(e.ownerDocument||e).createElement("style"),rt(a),yt(a,"style",s),ri(a,l.precedence,e),t.instance=a;case"stylesheet":s=dn(l.href);var i=e.querySelector(es(s));if(i)return t.state.loading|=4,t.instance=i,rt(i),i;a=Bf(l),(s=It.get(s))&&Rc(a,s),i=(e.ownerDocument||e).createElement("link"),rt(i);var c=i;return c._p=new Promise(function(o,f){c.onload=o,c.onerror=f}),yt(i,"link",a),t.state.loading|=4,ri(i,l.precedence,e),t.instance=i;case"script":return i=fn(l.src),(s=e.querySelector(ts(i)))?(t.instance=s,rt(s),s):(a=l,(s=It.get(i))&&(a=z({},l),wc(a,s)),e=e.ownerDocument||e,s=e.createElement("script"),rt(s),yt(s,"link",a),e.head.appendChild(s),t.instance=s);case"void":return null;default:throw Error(r(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(a=t.instance,t.state.loading|=4,ri(a,l.precedence,e));return t.instance}function ri(e,t,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),s=a.length?a[a.length-1]:null,i=s,c=0;c title"):null)}function C0(e,t,l){if(l===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(e=t.disabled,typeof t.precedence=="string"&&e==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Lf(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function T0(e,t,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var s=dn(a.href),i=t.querySelector(es(s));if(i){t=i._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=fi.bind(e),t.then(e,e)),l.state.loading|=4,l.instance=i,rt(i);return}i=t.ownerDocument||t,a=Bf(a),(s=It.get(s))&&Rc(a,s),i=i.createElement("link"),rt(i);var c=i;c._p=new Promise(function(o,f){c.onload=o,c.onerror=f}),yt(i,"link",a),l.instance=i}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(l,t),(t=l.state.preload)&&(l.state.loading&3)===0&&(e.count++,l=fi.bind(e),t.addEventListener("load",l),t.addEventListener("error",l))}}var Hc=0;function E0(e,t){return e.stylesheets&&e.count===0&&hi(e,e.stylesheets),0Hc?50:800)+t);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(a),clearTimeout(s)}}:null}function fi(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)hi(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var mi=null;function hi(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,mi=new Map,t.forEach(M0,e),mi=null,fi.call(e))}function M0(e,t){if(!(t.state.loading&4)){var l=mi.get(e);if(l)var a=l.get(null);else{l=new Map,mi.set(e,l);for(var s=e.querySelectorAll("link[data-precedence],style[data-precedence]"),i=0;i"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(u)}catch(m){console.error(m)}}return u(),Kc.exports=Z0(),Kc.exports}var J0=V0();function be(u){return Array.isArray(u)?u:[]}function vm(u){const m=new Set;return u.map(h=>h.trim()).filter(h=>{const r=h.toLowerCase();return!h||m.has(r)?!1:(m.add(r),!0)})}function sl(u){const m=Ni.some(h=>h.value===u.streamMode)?u.streamMode:"auto";return{...u,streamMode:m,models:be(u.models),allowedGroupIds:be(u.allowedGroupIds),openaiAccounts:be(u.openaiAccounts),kiroAccounts:be(u.kiroAccounts)}}function cs(u){return{...u,aliases:be(u.aliases)}}function $0(u){return{...u,apiKeys:be(u.apiKeys),logs:be(u.logs)}}class Ci extends Error{status;payload;constructor(m,h,r){super(h),this.status=m,this.payload=r}}const W0={home:"M3 10.5 12 3l9 7.5V21a1 1 0 0 1-1 1h-5v-7H9v7H4a1 1 0 0 1-1-1z",users:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75",key:"M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.78 7.78 5.5 5.5 0 0 1 7.78-7.78ZM14 8l7-7M21 8h-5V3",models:"M12 2 4 6v12l8 4 8-4V6zM4 6l8 4 8-4M12 10v12",image:"M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2ZM8.5 11a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5ZM21 16l-5-5L5 21",route:"M4 19a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM20 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM7 16h3a4 4 0 0 0 4-4V8h3",logs:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8zM14 2v6h6M8 13h8M8 17h6",settings:"M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7ZM19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 8.92 4a1.65 1.65 0 0 0 1-1.51V2a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9c.14.31.39.57.71.71.23.1.49.18.8.2H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z",search:"M21 21l-4.35-4.35M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z",copy:"M8 8h11a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1ZM4 16H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h11a1 1 0 0 1 1 1v1",ban:"M4.93 4.93 19.07 19.07M22 12A10 10 0 1 1 2 12a10 10 0 0 1 20 0Z",check:"M20 6 9 17l-5-5",moon:"M21 12.8A8.5 8.5 0 1 1 11.2 3 6.5 6.5 0 0 0 21 12.8Z",sun:"M12 4V2M12 22v-2M4.93 4.93 3.52 3.52M20.48 20.48l-1.41-1.41M4 12H2M22 12h-2M4.93 19.07l-1.41 1.41M20.48 3.52l-1.41 1.41M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z",plus:"M12 5v14M5 12h14"};function Ot({name:u}){return n.jsx("svg",{viewBox:"0 0 24 24","aria-hidden":"true",className:"icon",children:n.jsx("path",{d:W0[u]})})}async function pe(u,m){const h=new Headers(m?.headers);h.set("Content-Type","application/json");const r=window.sessionStorage.getItem("capi-admin-token");r&&h.set("Authorization",`Bearer ${r}`);const A=await fetch(u,{credentials:"include",...m,headers:h});if(!A.ok){const E=await A.json().catch(()=>null);throw new Ci(A.status,E?.error?.message||`Request failed: ${A.status}`,E)}return A.json()}async function F0(u,m){const h=new Headers,r=window.sessionStorage.getItem("capi-admin-token");r&&h.set("Authorization",`Bearer ${r}`);const A=await fetch(u,{credentials:"include",method:"POST",headers:h,body:m});if(!A.ok){const E=await A.json().catch(()=>null);throw new Ci(A.status,E?.error?.message||`Request failed: ${A.status}`,E)}return A.json()}const dm=[{id:"overview",label:"概览",icon:"home"},{id:"users",label:"用户",icon:"users"},{id:"groups",label:"分组",icon:"users"},{id:"keys",label:"密钥",icon:"key"},{id:"models",label:"模型",icon:"models"},{id:"drawing",label:"绘图",icon:"image"},{id:"channels",label:"渠道",icon:"route"},{id:"logs",label:"日志",icon:"logs"},{id:"settings",label:"设置",icon:"settings"}],to=[{value:"kiro",label:"Kiro / Amazon Q"},{value:"codex",label:"Codex / ChatGPT OAuth"},{value:"antigravity",label:"Antigravity / Google"},{value:"cpa",label:"CPA / CLIProxyAPI"},{value:"openai",label:"OpenAI"},{value:"anthropic",label:"Anthropic / Claude"},{value:"google",label:"Google Gemini"},{value:"deepseek",label:"DeepSeek"},{value:"openrouter",label:"OpenRouter"},{value:"groq",label:"Groq"},{value:"siliconflow",label:"SiliconFlow"},{value:"moonshot",label:"Moonshot"},{value:"compatible",label:"OpenAI 兼容接口"}],ym="https://api.openai.com/v1",Ti="https://chatgpt.com/backend-api",gm="http://localhost:8317/v1",bm="https://codewhisperer.us-east-1.amazonaws.com",xm="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2, gpt-image-1",I0="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2",P0="gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, claude-sonnet-4, gemini-3.1-pro",ep="claude-sonnet-4.5, claude-sonnet-4, claude-haiku-4.5, claude-opus-4.5",jm="https://daily-cloudcode-pa.googleapis.com",tp="claude-opus-4-6-thinking, claude-sonnet-4-6, gemini-3.8-flash-high, gemini-3.7-flash-high, gemini-3.6-flash-high, gemini-3-flash, gemini-pro-agent, gemini-3.1-pro-low, gpt-oss-120b-medium, gemini-3.1-flash-lite, gemini-3.5-flash-lite, gemini-3.1-flash-image",Fc=[{provider:"kiro",label:"Kiro / Amazon Q",name:"Kiro 账号池",baseUrl:bm,models:ep.split(",").map(u=>u.trim())},{provider:"openai",label:"OpenAI",name:"OpenAI 主线路",baseUrl:ym,models:I0.split(",").map(u=>u.trim())},{provider:"codex",label:"Codex 账号池",name:"Codex 账号池",baseUrl:Ti,models:xm.split(",").map(u=>u.trim())},{provider:"antigravity",label:"Antigravity 账号池",name:"Antigravity 账号池",baseUrl:jm,models:tp.split(",").map(u=>u.trim())},{provider:"cpa",label:"CPA / CLIProxyAPI",name:"CPA 本地代理",baseUrl:gm,models:P0.split(",").map(u=>u.trim())},{provider:"compatible",label:"OpenAI 兼容接口",name:"兼容渠道",baseUrl:"",models:[]},{provider:"openrouter",label:"OpenRouter",name:"OpenRouter",baseUrl:"https://openrouter.ai/api/v1",models:[]},{provider:"google",label:"Google Gemini",name:"Gemini",baseUrl:"",models:[]},{provider:"anthropic",label:"Anthropic / Claude",name:"Claude",baseUrl:"",models:[]}];function Ta(u){return Fc.find(m=>m.provider===u)||Fc[2]}function Ic(u){const m=Ta(u);return{name:m.name,provider:m.provider,baseUrl:m.baseUrl,models:[...m.models],streamMode:"auto"}}function lp(u){const m=u?.trim().toLowerCase();return m&&({free:"Free",plus:"Plus",pro:"Pro",team:"Team",enterprise:"Enterprise"}[m]||u)||"套餐未知"}function fm(u){return u?{upstream_token_invalidated:"Token 已失效",upstream_invalid_api_key:"API Key 无效",upstream_account_error:"账号错误",upstream_accounts_unavailable:"账号池不可用",upstream_error:"上游错误"}[u]||u:""}function Ei(u){return u==="openai"?ym:u==="codex"?Ti:u==="antigravity"?jm:u==="cpa"||u==="cliproxyapi"?gm:u==="kiro"?bm:""}function Pc(u){return vm(u.split(/[\s,;,;]+/))}function ap(u){return vm(u.split(/[\n,;,;]+/).map(m=>m.trim()))}function Sm(u){const m=ap(u);return m.length===0?{}:m.length===1?{upstreamApiKey:m[0]}:{upstreamApiKeys:m}}const Ni=[{value:"auto",label:"自动",description:"按请求参数处理"},{value:"real",label:"真流",description:"直连上游 SSE"},{value:"fake",label:"假流",description:"非流转 SSE"},{value:"disabled",label:"禁用流",description:"流式请求跳过"}];function el(u){if(!u)return"未使用";const m=new Date(u);return Number.isNaN(m.getTime())?"-":new Intl.DateTimeFormat("zh-CN",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}).format(m)}function mm(u){if(!u)return"";const m=new Date(u);if(Number.isNaN(m.getTime()))return"";const h=m.getTimezoneOffset()*6e4;return new Date(m.getTime()-h).toISOString().slice(0,16)}function np(u){if(!u)return"";const m=new Date(u);return Number.isNaN(m.getTime())?"":m.toISOString()}function sp(u){if(!u)return"-";const m=new Date(u);return Number.isNaN(m.getTime())?"-":new Intl.DateTimeFormat("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}).format(m)}function _t(u){return{active:"正常",disabled:"禁用",limited:"受限",overdue:"欠费",healthy:"正常",standby:"备用",available:"Available",success:"成功",failed:"失败"}[u]||u}function St(u,m=2){const h=Number(u||0);return new Intl.NumberFormat("zh-CN",{minimumFractionDigits:m,maximumFractionDigits:m}).format(h)}function ml(u){return new Intl.NumberFormat("zh-CN").format(Math.max(0,Math.round(Number(u||0))))}function lo(u){return u.model?u.model:u.errorCode==="invalid_api_key"?"密钥无效":u.errorCode==="model_not_available"?"模型不可用":u.errorCode==="insufficient_quota"?"额度不足":u.errorCode==="rate_limit_exceeded"?"请求过快":u.errorCode||"请求失败"}function ip(u){return u.model||(u.errorCode?`错误:${u.errorCode}`:"-")}function up(u){return u.channel||(u.apiKeyPrefix?`Key ${u.apiKeyPrefix}`:"-")}function cp(u){const m=be(u);if(m.length===0)return"未绑定模型";const h=m.slice(0,2).join(", ");return m.length>2?`${h} · 其余 ${m.length-2} 个`:h}function il(u){return u==="cliproxyapi"||u==="cli-proxy-api"?"CPA / CLIProxyAPI":to.find(m=>m.value===u)?.label||u||"Custom"}function $c(u){const m=`${u.vendor} ${u.id} ${u.name}`.toLowerCase();return m.includes("cliproxyapi")||/\bcpa\b/.test(m)?"cpa":m.includes("openai")||/\bgpt[-_/]/.test(m)||m.includes("o1-")||m.includes("o3-")?"openai":m.includes("anthropic")||m.includes("claude")?"anthropic":m.includes("google")||m.includes("gemini")||m.includes("gcli-")?"google":m.includes("deepseek")?"deepseek":m.includes("openrouter")?"openrouter":m.includes("groq")?"groq":m.includes("siliconflow")?"siliconflow":m.includes("moonshot")||m.includes("kimi")?"moonshot":u.vendor&&u.vendor.toLowerCase()!=="custom"?u.vendor.toLowerCase():"compatible"}function hm({provider:u}){if(u==="deepseek")return n.jsx("span",{className:"provider-icon provider-icon-deepseek","aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("path",{transform:"translate(2.4 4.4)",d:"M26.517 3.395c-.282-.138-.403.125-.568.258-.057.044-.105.1-.152.152-.413.44-.895.73-1.524.695-.92-.052-1.705.237-2.4.941-.147-.868-.638-1.386-1.384-1.718-.39-.173-.786-.346-1.06-.721-.19-.268-.243-.566-.338-.86-.061-.176-.121-.357-.325-.388-.222-.034-.309.151-.396.307-.347.635-.481 1.334-.468 2.042.03 1.594.703 2.863 2.04 3.765.152.104.191.207.143.359-.091.31-.2.613-.295.924-.06.198-.151.242-.364.155-.734-.306-1.367-.76-1.927-1.308-.951-.92-1.81-1.934-2.882-2.729-.252-.185-.504-.358-.764-.522-1.094-1.062.143-1.935.43-2.038.3-.108.104-.48-.864-.475-.968.004-1.853.328-2.982.76-.165.065-.339.112-.516.151-1.024-.194-2.088-.237-3.199-.112-2.092.233-3.763 1.222-4.991 2.91C.254 7.972-.093 10.278.332 12.682c.446 2.535 1.74 4.633 3.728 6.274 2.062 1.7 4.436 2.534 7.145 2.375 1.645-.095 3.476-.316 5.542-2.064.521.259 1.068.363 1.975.44.699.065 1.371-.034 1.892-.142.816-.173.76-.929.465-1.067-2.392-1.114-1.866-.661-2.344-1.027 1.215-1.438 3.071-3.993 3.644-7.473.056-.384.128-.925.12-1.236-.005-.19.038-.263.255-.285.6-.069 1.18-.233 1.715-.527 1.55-.846 2.175-2.237 2.322-3.903.022-.255-.005-.518-.274-.652ZM13.014 18.395c-2.318-1.823-3.442-2.423-3.906-2.397-.434.026-.356.523-.26.847.1.32.23.54.412.82.126.186.213.462-.126.67-.746.461-2.044-.156-2.105-.186-1.51-.89-2.773-2.064-3.664-3.67-.86-1.545-1.358-3.204-1.44-4.974-.022-.427.104-.578.529-.656.56-.103 1.137-.125 1.697-.043 2.366.346 4.379 1.403 6.068 3.079.963.954 1.692 2.094 2.443 3.208.799 1.183 1.658 2.31 2.752 3.234.387.324.695.57.99.751-.89.1-2.374.121-3.39-.683Zm1.111-7.146c0-.19.152-.341.343-.341.043 0 .082.009.117.021.048.018.092.044.126.083.061.06.096.146.096.237a.341.341 0 0 1-.343.341.34.34 0 0 1-.339-.341Zm3.451 1.77c-.222.09-.443.168-.656.177-.33.017-.69-.117-.885-.281-.304-.255-.521-.397-.612-.842-.039-.19-.017-.483.017-.652.078-.362-.009-.595-.265-.807-.208-.172-.473-.22-.764-.22-.108 0-.208-.048-.282-.086-.121-.061-.221-.212-.126-.398.031-.06.178-.207.213-.233.395-.225.85-.151 1.272.018.39.16.686.453 1.111.867.434.501.512.639.759 1.015.196.294.373.596.495.942.073.215-.022.392-.277.5Z"})]})});if(u==="openai")return n.jsx("span",{className:"provider-icon provider-icon-openai","aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("g",{transform:"translate(7 7.5) scale(0.065)",fill:"currentColor",stroke:"none",children:n.jsx("path",{d:"M267.06 111.34a71.78 71.78 0 0 0-6.17-58.91c-14.5-25.15-43.55-38.09-71.9-32.03A71.78 71.78 0 0 0 135.1.5C106 .43 80.21 19.16 71.29 46.85a71.79 71.79 0 0 0-47.98 34.8c-14.6 25.1-11.28 56.75 8.22 78.3a71.78 71.78 0 0 0 6.16 58.9c14.5 25.16 43.56 38.1 71.91 32.04a71.76 71.76 0 0 0 53.89 24.02c29.12.02 54.92-18.72 63.84-46.44a71.79 71.79 0 0 0 47.98-34.8c14.58-25.1 11.25-56.72-8.24-78.27zm-107.9 150.77a53.15 53.15 0 0 1-34.15-12.35c.43-.24 1.2-.66 1.7-.96l56.68-32.73a9.22 9.22 0 0 0 4.66-8.06v-79.9l23.95 13.83a.85.85 0 0 1 .47.66v66.16a53.42 53.42 0 0 1-53.3 53.35zM44.6 213.16a53.13 53.13 0 0 1-6.36-35.75c.42.25 1.15.7 1.68 1l56.68 32.73a9.24 9.24 0 0 0 9.31 0l69.2-39.95v27.66a.87.87 0 0 1-.34.74l-57.29 33.07a53.42 53.42 0 0 1-72.88-19.5zM29.7 90.05a53.1 53.1 0 0 1 27.76-23.36c0 .49-.03 1.36-.03 1.96v65.46a9.22 9.22 0 0 0 4.65 8.05l69.2 39.95-23.95 13.83a.86.86 0 0 1-.81.07L49.2 162.9A53.42 53.42 0 0 1 29.7 90.05zm196.8 45.8L157.3 95.9l23.95-13.82a.86.86 0 0 1 .81-.07l57.3 33.08a53.37 53.37 0 0 1-8.24 96.29v-65.46a9.2 9.2 0 0 0-4.62-8.06zm23.84-35.89c-.42-.26-1.15-.7-1.68-1.01l-56.68-32.73a9.25 9.25 0 0 0-9.31 0l-69.2 39.95V78.5a.87.87 0 0 1 .35-.74l57.28-33.05a53.35 53.35 0 0 1 79.24 55.25zM100.11 149.24l-23.96-13.83a.85.85 0 0 1-.46-.66V68.6a53.37 53.37 0 0 1 87.52-40.95c-.42.24-1.19.66-1.7.96l-56.68 32.73a9.22 9.22 0 0 0-4.66 8.06l-.04 79.85zm13.01-28.05L144 103.3l30.88 17.83v35.68L144 174.63l-30.88-17.82v-35.62z"})})]})});const m=u==="codex"?"C":u==="antigravity"?"G":u==="cpa"||u==="cliproxyapi"?"CPA":u==="anthropic"?"A":u==="google"?"✦":u==="openrouter"?"↗":u==="groq"?"G":u==="siliconflow"?"S":u==="moonshot"?"M":"◇";return n.jsx("span",{className:`provider-icon provider-icon-${u}`,"aria-hidden":"true",children:n.jsxs("svg",{viewBox:"0 0 32 32",role:"img",children:[n.jsx("rect",{x:"1",y:"1",width:"30",height:"30",rx:"8"}),n.jsx("text",{x:"16",y:"21",textAnchor:"middle",children:m})]})})}async function Ai(u){if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(u);return}const m=document.createElement("textarea");m.value=u,m.setAttribute("readonly","true"),m.style.position="fixed",m.style.opacity="0",document.body.appendChild(m),m.select(),document.execCommand("copy"),document.body.removeChild(m)}function Ul(){return window.location.origin}function op(){return`${Ul()}/api/auth/discord/callback`}function rp(){return`${Ul()}/`}function Wc(u){return{...u,redirectUri:u.redirectUri&&!u.redirectUri.includes("localhost")?u.redirectUri:op(),authSuccessUrl:u.authSuccessUrl&&!u.authSuccessUrl.includes("localhost")?u.authSuccessUrl:rp(),blockedGuildIds:be(u.blockedGuildIds),sessionTtlHours:u.sessionTtlHours||168}}function Mi(u){return u==="email"||u==="discord"?u:"username"}function dp(u){const h=(u.split("@")[0]||"user").toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^[-_]+|[-_]+$/g,"");return(h.length>=3?h:"user").slice(0,24)}function fp(){const[u,m]=g.useState("home"),[h,r]=g.useState("login"),[A,E]=g.useState(null),[L,$]=g.useState("overview"),[C,y]=g.useState(()=>{const w=window.localStorage.getItem("capi-theme");return w==="light"||w==="dark"?w:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}),[R,z]=g.useState("comfortable"),[P,ee]=g.useState(null),[de,ne]=g.useState([]),[le,ie]=g.useState([]),[xe,Y]=g.useState([]),[ge,F]=g.useState([]),[me,D]=g.useState([]),[ae,fe]=g.useState(""),[Ae,Te]=g.useState(""),[ue,Z]=g.useState(null),[re,J]=g.useState(""),[T,k]=g.useState(""),[B,Q]=g.useState(!1),O=g.useMemo(()=>{const w=ae.trim().toLowerCase();return w?de.filter(K=>`${K.id} ${K.name} ${K.email}`.toLowerCase().includes(w)):de},[ae,de]);async function d(){const w=new Date().getTimezoneOffset(),[K,te,W,ye,qe,Ze]=await Promise.all([pe(`/api/overview?timezoneOffset=${w}`),pe("/api/users"),pe("/api/channels"),pe("/api/models"),pe("/api/logs"),pe("/api/groups")]),Ut=be(te.users),Rl=be(W.channels).map(sl),ca=be(ye.models).map(cs),Ea=be(qe.logs),Ma=be(Ze.groups);ee(K),ne(Ut),ie(Rl),Y(Ma),F(ca),D(Ea),Te(wl=>wl&&Ut.some(hl=>hl.id===wl)?wl:Ut[0]?.id||""),Ut.length===0&&Z(null),Q(!0)}async function x(w){const K=await pe(`/api/users/${w}`);Z($0(K))}async function G(w,K){const te=await pe(`/api/users/${w}`,{method:"PATCH",body:JSON.stringify(K)});ne(W=>W.map(ye=>ye.id===w?te.user:ye)),Z(W=>W?.user.id===w?{...W,user:te.user}:W),J("已更新用户"),window.setTimeout(()=>J(""),1800)}async function X(w,K,te={}){const W=await pe("/api/users/bulk",{method:"POST",body:JSON.stringify({userIds:w,action:K,...te})}),ye=new Map(be(W.users).map(qe=>[qe.id,qe]));ne(qe=>qe.map(Ze=>ye.get(Ze.id)||Ze)),Z(qe=>{if(!qe)return qe;const Ze=ye.get(qe.user.id);return Ze?{...qe,user:Ze}:qe}),J(`已处理 ${W.updated} 个用户`),window.setTimeout(()=>J(""),1800)}async function se(w){const K=await pe(`/api/users/${w}/api-keys`,{method:"POST",body:JSON.stringify({name:"Console Key"})});ue?.user.id===w&&Z({...ue,apiKeys:[...ue.apiKeys,K.apiKey]}),k(K.secret),await Ai(K.secret),J("新 Key 已创建并复制,请立即保存"),window.setTimeout(()=>J(""),2400)}async function ve(w){window.confirm("删除这个 Key?删除后使用它的请求会立即失效。")&&(await pe(`/api/api-keys/${w}`,{method:"DELETE"}),Z(K=>K&&{...K,apiKeys:K.apiKeys.filter(te=>te.id!==w)}),J("Key 已删除"),window.setTimeout(()=>J(""),1800))}async function N(w,K){const te=await pe(`/api/api-keys/${w}`,{method:"PATCH",body:JSON.stringify(K)});Z(W=>W&&{...W,apiKeys:W.apiKeys.map(ye=>ye.id===w?te.apiKey:ye)}),J("Key 已更新"),window.setTimeout(()=>J(""),1800)}async function Ne(w,K){const te=await pe(`/api/channels/${w}`,{method:"PATCH",body:JSON.stringify(K)});ie(W=>W.map(ye=>ye.id===w?sl(te.channel):ye)),Pe(te.removedModels),J("渠道已更新"),window.setTimeout(()=>J(""),1800)}async function Se(w){const K=le.find(W=>W.id===w);if(!window.confirm(`删除渠道「${K?.name||w}」?`))return;const te=await pe(`/api/channels/${w}`,{method:"DELETE"});ie(W=>W.filter(ye=>ye.id!==w)),Pe(te.removedModels),J("渠道已删除"),window.setTimeout(()=>J(""),1800)}async function bt(w){const K=await pe("/api/groups",{method:"POST",body:JSON.stringify(w)});Y(te=>[...te,K.group]),J("分组已创建"),window.setTimeout(()=>J(""),1800)}async function I(w,K){const te=await pe(`/api/groups/${w}`,{method:"PATCH",body:JSON.stringify(K)});Y(W=>W.map(ye=>ye.id===w?te.group:ye)),J("分组已更新"),window.setTimeout(()=>J(""),1800)}async function Ke(w){const K=xe.find(te=>te.id===w);window.confirm(`删除分组「${K?.name||w}」?删除后渠道的可见范围会移除该分组。`)&&(await pe(`/api/groups/${w}`,{method:"DELETE"}),Y(te=>te.filter(W=>W.id!==w)),ie(te=>te.map(W=>({...W,allowedGroupIds:W.allowedGroupIds.filter(ye=>ye!==w)}))),J("分组已删除"),window.setTimeout(()=>J(""),1800))}async function We(w,K){const te=be(K).map(Ut=>Ut.trim()).filter(Boolean),W=await pe(`/api/channels/${w}/sync-models`,{method:"POST",body:JSON.stringify(te.length?{models:te}:{})}),ye=sl(W.channel),qe=be(W.addedModels).map(cs),Ze=be(W.models);ie(Ut=>Ut.map(Rl=>Rl.id===w?ye:Rl)),qe.length>0&&F(Ut=>{const Rl=new Set(Ut.map(ca=>ca.id.toLowerCase()));return[...Ut,...qe.filter(ca=>!Rl.has(ca.id.toLowerCase()))]}),Pe(W.removedModels),J(te.length?`已保存 ${Ze.length} 个模型`:Ze.length?`已拉取 ${Ze.length} 个模型`:"上游没有返回模型"),window.setTimeout(()=>J(""),2200)}function Pe(w){const K=new Set(be(w).map(te=>te.toLowerCase()));K.size!==0&&(F(te=>te.filter(W=>!K.has(W.id.toLowerCase()))),Z(te=>te&&{...te,apiKeys:te.apiKeys.map(W=>({...W,allowedModels:W.allowedModels.filter(ye=>!K.has(ye.toLowerCase()))}))}))}async function tl(w){try{const K=await pe(`/api/channels/${w}/check`,{method:"POST",body:JSON.stringify({})});ie(te=>te.map(W=>W.id===w?sl(K.channel):W)),J(K.ok?`渠道可用,检测到 ${be(K.models).length} 个模型`:"渠道检测失败")}catch(K){const te=K instanceof Ci?K.payload?.channel:null;te&&ie(W=>W.map(ye=>ye.id===w?sl(te):ye)),J(K instanceof Error?K.message:"渠道检测失败")}window.setTimeout(()=>J(""),2400)}async function kt(w=Ic("codex")){const K=await pe("/api/channels",{method:"POST",body:JSON.stringify(w)});ie(te=>[...te,sl(K.channel)]),J("渠道已创建,可继续拉取模型或检测渠道"),window.setTimeout(()=>J(""),2400)}async function cl(w,K){const te=new FormData;te.append("file",K);const W=await F0(`/api/channels/${encodeURIComponent(w)}/import-openai-accounts`,te);ie(ye=>ye.map(qe=>qe.id===W.channel.id?sl(W.channel):qe)),J(`新增 ${W.created??W.imported} 个账号${W.updated?`,更新 ${W.updated} 个已有账号`:""}${W.skipped?`,跳过 ${W.skipped} 个`:""}`),window.setTimeout(()=>J(""),2600)}async function V(w,K=!1,te=""){const W=await pe(`/api/channels/${encodeURIComponent(w)}/openai-accounts/check`,{method:"POST",body:JSON.stringify({onlyInvalid:K,accountId:te})});ie(ye=>ye.map(qe=>qe.id===W.channel.id?sl(W.channel):qe)),J(`${K?"无效账号复检":"账号测活"}完成:${W.healthy}/${W.checked} 可用${W.failed?`,无效 ${W.failed}`:""}`),window.setTimeout(()=>J(""),3e3)}async function _(w){const K=await pe(`/api/channels/${encodeURIComponent(w)}/openai-accounts/deduplicate`,{method:"POST",body:JSON.stringify({})});ie(te=>te.map(W=>W.id===K.channel.id?sl(K.channel):W)),J(K.removed?`已合并 ${K.removed} 个重复账号`:"未发现可识别的重复账号"),window.setTimeout(()=>J(""),2600)}async function Ee(w,K){const te=await pe(`/api/channels/${encodeURIComponent(w)}/openai-accounts/${encodeURIComponent(K)}`,{method:"DELETE"});ie(W=>W.map(ye=>ye.id===te.channel.id?sl(te.channel):ye)),J("账号已删除"),window.setTimeout(()=>J(""),1800)}async function et(w){return pe(`/api/channels/${encodeURIComponent(w)}/openai-oauth/start`,{method:"POST",body:JSON.stringify({})})}async function xt(w,K){const te=await pe(`/api/channels/${encodeURIComponent(w)}/openai-oauth/complete`,{method:"POST",body:JSON.stringify(K)});return ie(W=>W.map(ye=>ye.id===te.channel.id?sl(te.channel):ye)),J("已通过 OAuth 添加账号"),window.setTimeout(()=>J(""),2400),te}async function ft(w){const K=await pe("/api/models",{method:"POST",body:JSON.stringify(w)});F(te=>[...te,cs(K.model)]),J("模型已添加"),window.setTimeout(()=>J(""),1800)}async function tt(w,K){const te=await pe(`/api/models/${encodeURIComponent(w)}`,{method:"PATCH",body:JSON.stringify(K)});F(W=>W.map(ye=>ye.id===w?cs(te.model):ye)),J("模型已更新"),window.setTimeout(()=>J(""),1600)}async function zi(w){window.confirm(`删除模型 ${w}?渠道和 Key 中的引用也会一起清理。`)&&(await pe(`/api/models/${encodeURIComponent(w)}`,{method:"DELETE"}),F(K=>K.filter(te=>te.id!==w)),ie(K=>K.map(te=>({...te,models:te.models.filter(W=>W!==w)}))),Z(K=>K&&{...K,apiKeys:K.apiKeys.map(te=>({...te,allowedModels:te.allowedModels.filter(W=>W!==w)}))}),J("模型已删除"),window.setTimeout(()=>J(""),1800))}async function hn(w,K="已复制"){await Ai(w),J(K),window.setTimeout(()=>J(""),1600)}function ia(w,K){if(w instanceof Ci&&w.status===401){Q(!1),r("login"),m("auth");return}J(K)}async function ua(){try{const w=await pe("/api/auth/status");if(E(w),!w.initialized){r("setup"),m("auth");return}if(!w.authenticated){r("login"),m("auth");return}m(w.session?.role==="admin"?"console":"account")}catch(w){ia(w,"认证状态加载失败")}}async function Oi(){await pe("/api/auth/logout",{method:"POST"}),window.sessionStorage.removeItem("capi-admin-token"),E(null),m("home")}return g.useEffect(()=>{let w=!1;return pe("/api/auth/status").then(K=>{w||(E(K),K.authenticated&&K.session&&m(K.session.role==="admin"?"console":"account"))}).catch(()=>{}),()=>{w=!0}},[]),g.useEffect(()=>{u==="console"&&(Q(!1),d().catch(w=>ia(w,"加载数据失败")))},[u]),g.useEffect(()=>{u!=="console"||!B||x(Ae).catch(w=>ia(w,"加载用户详情失败"))},[Ae,u,B]),g.useEffect(()=>{window.localStorage.setItem("capi-theme",C)},[C]),g.useEffect(()=>{window.scrollTo({top:0,left:0})},[u,L]),u==="home"?n.jsx(bp,{theme:C,setTheme:y,enterConsole:ua}):u==="auth"?n.jsx(mp,{theme:C,mode:h,status:A,setTheme:y,setMode:r,goHome:()=>m("home"),onAuthenticated:w=>{E(K=>K?{...K,authenticated:!0,initialized:!0,session:w}:null),m(w.role==="admin"?"console":"account")}}):u==="account"?n.jsx(gp,{theme:C,setTheme:y,goHome:()=>m("home"),openLogin:ua}):n.jsxs("div",{className:"app-shell","data-theme":C,"data-density":R,children:[n.jsxs("aside",{className:"sidebar",children:[n.jsxs("div",{className:"ios-window-dots","aria-hidden":"true",children:[n.jsx("span",{}),n.jsx("span",{}),n.jsx("span",{})]}),n.jsxs("div",{className:"brand",children:[n.jsx("div",{className:"brand-mark",children:"C"}),n.jsxs("div",{children:[n.jsx("strong",{children:"CAPI"}),n.jsx("span",{children:"聚合网关"})]})]}),n.jsx("nav",{children:dm.map(w=>n.jsxs("button",{className:L===w.id?"nav-item active":"nav-item",onClick:()=>$(w.id),children:[n.jsx(Ot,{name:w.icon}),n.jsx("span",{className:"nav-label",children:w.label})]},w.id))}),n.jsxs("div",{className:"sidebar-footer",children:[n.jsx("span",{children:"Gateway"}),n.jsxs("strong",{children:[n.jsx("span",{className:"pulse-dot"}),"Online"]})]})]}),n.jsxs("main",{className:"content",children:[n.jsxs("header",{className:"topbar",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Admin Console"}),n.jsx("h1",{children:dm.find(w=>w.id===L)?.label})]}),n.jsxs("div",{className:"topbar-actions",children:[n.jsx(Vp,{value:R,options:[{value:"comfortable",label:"舒适"},{value:"compact",label:"紧凑"}],onChange:w=>z(w)}),n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>y(C==="dark"?"light":"dark"),children:[n.jsx(Ot,{name:C==="dark"?"sun":"moon"}),n.jsx("span",{children:C==="dark"?"浅色":"暗色"})]}),n.jsx("button",{className:"primary-button",onClick:()=>d().catch(w=>ia(w,"刷新失败")),children:"刷新"}),n.jsx("button",{className:"secondary-button home-link",onClick:()=>m("home"),children:"首页"}),n.jsx("button",{className:"secondary-button",onClick:Oi,children:"退出"})]})]}),L==="overview"&&n.jsx(xp,{overview:P,channels:le,logs:me,onNavigate:w=>{$(w),w==="channels"&&le.length===0&&J("渠道页可以创建第一个上游"),w==="logs"&&me.length===0&&J("暂无异常日志"),window.setTimeout(()=>J(""),1800)}}),L==="users"&&n.jsx(Sp,{users:O,query:ae,selectedUser:ue,onQuery:fe,onSelect:Te,onUpdate:G,onBulkUpdate:X,onCreateKey:se,groups:xe,onOpenRegistration:()=>{$("settings"),J("在账号与注册里开放注册,用户即可自助创建账号"),window.setTimeout(()=>J(""),2400)}}),L==="groups"&&n.jsx(Kp,{groups:xe,onCreate:bt,onUpdate:I,onDelete:Ke}),L==="keys"&&n.jsx(Np,{selectedUser:ue,onCreateKey:se,onUpdateKey:N,onDeleteKey:ve}),L==="models"&&n.jsx(Cp,{models:ge,onCopy:hn,onCreate:ft,onUpdate:tt,onDelete:zi}),L==="drawing"&&n.jsx(Mp,{channels:le,onCreate:kt,onImport:cl,onCheckAccounts:V,onDeduplicateAccounts:_,onDeleteAccount:Ee,onUpdate:Ne,onStartOAuth:et,onCompleteOAuth:xt}),L==="channels"&&n.jsx(Yp,{channels:le,groups:xe,onUpdate:Ne,onCreate:kt,onImport:cl,onDelete:Se,onSyncModels:We,onCheck:tl}),L==="logs"&&n.jsx(kp,{logs:me,onCopy:hn}),L==="settings"&&n.jsx(Xp,{models:ge,channels:le,groups:xe})]}),T&&n.jsx("div",{className:"secret-dialog-backdrop",role:"presentation",children:n.jsxs("section",{className:"secret-dialog",role:"dialog","aria-modal":"true","aria-labelledby":"secret-dialog-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"One-time secret"}),n.jsx("h2",{id:"secret-dialog-title",children:"完整 API Key"})]}),n.jsx("p",{children:"完整密钥只显示这一次。列表中的星号内容只是识别前缀,不能用于 API 调用。"}),n.jsx("code",{children:T}),n.jsxs("div",{className:"secret-dialog-actions",children:[n.jsx("button",{className:"secondary-button",onClick:()=>{Ai(T),J("完整 Key 已复制"),window.setTimeout(()=>J(""),1800)},children:"复制"}),n.jsx("button",{className:"primary-button",onClick:()=>k(""),children:"完成"})]})]})}),re&&n.jsx("div",{className:"toast",children:re})]})}function mp({theme:u,mode:m,status:h,setTheme:r,setMode:A,goHome:E,onAuthenticated:L}){const[$,C]=g.useState(""),[y,R]=g.useState(""),[z,P]=g.useState(""),[ee,de]=g.useState(""),[ne,le]=g.useState(""),[ie,xe]=g.useState(""),[Y,ge]=g.useState(!1),[F,me]=g.useState("username"),[D,ae]=g.useState("0"),[fe,Ae]=g.useState(""),[Te,ue]=g.useState(!1),Z=m==="setup",re=m==="register",J=Mi(h?.registrationMode),T=re&&J==="email",k=re&&J==="discord";async function B(){if(!k){if((Z||re)&&ne!==ie){Ae("两次输入的密码不一致");return}ue(!0),Ae("");try{const Q=Z?"/api/auth/setup":re?"/api/auth/register":"/api/auth/login",O=T?dp(z):$,d=m==="login"?{identifier:$,password:ne}:{username:O,password:ne,displayName:y,email:z,discordUserId:Z?ee:"",registrationEnabled:Z?Y:void 0,registrationMode:Z?F:void 0,defaultBalance:Z?Number(D||0):void 0},x=await pe(Q,{method:"POST",body:JSON.stringify(d)});L(x.session)}catch(Q){Ae(Q instanceof Error?Q.message:"操作失败")}finally{ue(!1)}}}return n.jsxs("main",{className:"auth-page","data-theme":u,children:[n.jsxs("header",{className:"auth-topbar",children:[n.jsxs("button",{className:"auth-brand",onClick:E,children:[n.jsx("span",{className:"brand-mark",children:"C"}),n.jsx("strong",{children:"CAPI"})]}),n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>r(u==="dark"?"light":"dark"),children:[n.jsx(Ot,{name:u==="dark"?"sun":"moon"}),n.jsx("span",{children:u==="dark"?"浅色":"暗色"})]})]}),n.jsxs("section",{className:"auth-stage",children:[n.jsxs("div",{className:"auth-intro",children:[n.jsx("span",{children:Z?"First Run":"Welcome Back"}),n.jsx("h1",{children:Z?"初始化 CAPI":re?"创建账号":"登录"}),n.jsx("p",{children:Z?"创建第一个管理员账号,完成后即可进入控制台。":"使用你的 CAPI 账号继续。"})]}),n.jsxs("form",{className:"auth-form",onSubmit:Q=>{Q.preventDefault(),B()},children:[k?n.jsxs("div",{className:"auth-discord-register",children:[n.jsx("strong",{children:"使用 Discord 创建账号"}),n.jsx("span",{children:"继续后会按站点设置校验服务器和身份组。"}),h?.discordEnabled?n.jsx("a",{className:"discord-login-button",href:"/api/auth/discord/start",children:"继续使用 Discord"}):n.jsx("div",{className:"auth-message",children:"管理员还没有启用 Discord 登录"})]}):n.jsxs(n.Fragment,{children:[m!=="login"&&n.jsxs("label",{children:[n.jsx("span",{children:"显示名称"}),n.jsx("input",{value:y,onChange:Q=>R(Q.target.value),autoComplete:"name",placeholder:"CAPI"})]}),!T&&n.jsxs("label",{children:[n.jsx("span",{children:m==="login"?"账号或邮箱":"账号"}),n.jsx("input",{value:$,onChange:Q=>C(Q.target.value),autoComplete:"username",placeholder:m==="login"?"输入账号或邮箱":"3-32 位字母、数字、_ 或 -"})]}),(Z||T)&&n.jsxs("label",{children:[n.jsx("span",{children:T?"邮箱":"邮箱(可选)"}),n.jsx("input",{type:"email",value:z,onChange:Q=>P(Q.target.value),autoComplete:"email",placeholder:"name@example.com"})]}),Z&&n.jsxs(n.Fragment,{children:[n.jsxs("label",{children:[n.jsx("span",{children:"Discord 用户 ID(可选)"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:ee,onChange:Q=>de(Q.target.value),placeholder:"绑定管理员 Discord 账号"})]}),n.jsxs("div",{className:"setup-options",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"开放注册"}),n.jsx("button",{type:"button",className:Y?"ios-switch is-on":"ios-switch","aria-pressed":Y,onClick:()=>ge(Q=>!Q),children:n.jsx("span",{})})]}),n.jsxs("label",{children:[n.jsx("span",{children:"注册方式"}),n.jsxs("select",{value:F,onChange:Q=>me(Mi(Q.target.value)),children:[n.jsx("option",{value:"username",children:"账号密码"}),n.jsx("option",{value:"email",children:"邮箱"}),n.jsx("option",{value:"discord",children:"Discord"})]})]}),n.jsxs("label",{children:[n.jsx("span",{children:"新用户初始额度"}),n.jsx("input",{type:"number",min:"0",step:"0.01",value:D,onChange:Q=>ae(Q.target.value)})]})]})]}),n.jsxs("label",{children:[n.jsx("span",{children:"密码"}),n.jsx("input",{type:"password",value:ne,onChange:Q=>le(Q.target.value),autoComplete:m==="login"?"current-password":"new-password",placeholder:"至少 8 个字符"})]}),m!=="login"&&n.jsxs("label",{children:[n.jsx("span",{children:"确认密码"}),n.jsx("input",{type:"password",value:ie,onChange:Q=>xe(Q.target.value),autoComplete:"new-password",placeholder:"再次输入密码"})]}),n.jsx("div",{className:"auth-message",role:"status",children:fe}),n.jsx("button",{className:"primary-button auth-submit",type:"submit",disabled:Te,children:Te?"请稍候":Z?"创建管理员":re?"注册":"登录"})]}),!Z&&!k&&h?.discordEnabled&&n.jsx("a",{className:"discord-login-button",href:"/api/auth/discord/start",children:"使用 Discord 登录"}),!Z&&n.jsx("div",{className:"auth-switch",children:m==="login"&&h?.registrationEnabled?n.jsx("button",{type:"button",onClick:()=>A("register"),children:"创建账号"}):n.jsx("button",{type:"button",onClick:()=>A("login"),children:"返回登录"})})]})]})]})}const hp=[1,1.5,2,2.5,3,4,5,6,8,10];function pp(u){if(!(u>0))return 1;const m=Math.floor(Math.log10(u)),h=Math.pow(10,m),r=u/h;return(hp.find(E=>r<=E)??10)*h}const pm=88;function vp(u){const m=u.split("-");return m.length===3?`${m[1]}/${m[2]}`:u}function yp(){const[u,m]=g.useState(14),[h,r]=g.useState(null),[A,E]=g.useState(!0),[L,$]=g.useState(!1),[C,y]=g.useState("");g.useEffect(()=>{let Y=!1;return E(!0),pe(`/api/account/usage?days=${u}&timezoneOffset=${new Date().getTimezoneOffset()}`).then(ge=>{Y||(r({...ge.usage,daily:be(ge.usage?.daily),models:be(ge.usage?.models)}),$(!1))}).catch(()=>{Y||$(!0)}).finally(()=>{Y||E(!1)}),()=>{Y=!0}},[u]);const R=h?.daily??[],z=h?.models??[],P=pp(Math.max(0,...R.map(Y=>Y.cost))),ee=Math.max(0,...z.map(Y=>Y.cost)),de=R.reduce((Y,ge)=>!Y||ge.cost>Y.cost?ge:Y,null),ne=Math.max(1,Math.ceil(R.length/5)),le=R.find(Y=>Y.day===C)||null,ie=le?R.indexOf(le):-1,xe=h?h.today.cost-h.yesterday.cost:0;return n.jsxs("section",{className:"account-section usage-section",children:[n.jsx("div",{className:"account-section-title",children:n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Usage"}),n.jsx("h2",{children:"用量概览"})]})}),!h&&A&&n.jsx("p",{className:"usage-placeholder",children:"正在统计用量…"}),!h&&!A&&L&&n.jsx("p",{className:"usage-placeholder",children:"用量加载失败,请稍后重试"}),h&&n.jsxs("div",{className:A?"usage-body is-refreshing":"usage-body",children:[n.jsxs("div",{className:"usage-kpi",children:[n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"今日消费"}),n.jsx("strong",{children:St(h.today.cost)}),n.jsxs("small",{children:["较昨日 ",xe>=0?"+":"−",St(Math.abs(xe))]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"本月消费"}),n.jsx("strong",{children:St(h.month.cost)}),n.jsxs("small",{children:[ml(h.month.requests)," 次请求"]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"今日请求"}),n.jsx("strong",{children:ml(h.today.requests)}),n.jsxs("small",{children:["成功率 ",h.today.successRate,"%"]})]}),n.jsxs("div",{className:"usage-tile",children:[n.jsx("span",{children:"累计消费"}),n.jsx("strong",{children:St(h.total.cost)}),n.jsxs("small",{children:[ml(h.total.requests)," 次请求"]})]})]}),n.jsx("div",{className:"usage-range",role:"group","aria-label":"统计范围",children:[7,14,30].map(Y=>n.jsxs("button",{type:"button",className:u===Y?"selected":"","aria-pressed":u===Y,onClick:()=>m(Y),children:["近 ",Y," 天"]},Y))}),n.jsxs("div",{className:"usage-block",children:[n.jsxs("div",{className:"usage-block-head",children:[n.jsx("strong",{children:"每日消费"}),n.jsxs("span",{children:["近 ",h.rangeDays," 天"]})]}),R.length===0||P<=0?n.jsx("p",{className:"usage-placeholder",children:"这段时间还没有消费记录"}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"usage-plot",children:[n.jsx("div",{className:"usage-grid","aria-hidden":"true",children:[1,.5,0].map(Y=>n.jsx("div",{className:"usage-gridline",style:{bottom:`${Y*pm}%`},children:n.jsx("span",{children:St(P*Y)})},Y))}),n.jsxs("div",{className:"usage-columns",children:[R.map((Y,ge)=>{const F=P>0?Y.cost/P*pm:0,me=Y.cost>0,D=me&&de!==null&&Y.day===de.day,ae=ge%ne===0||ge===R.length-1;return n.jsxs("div",{className:"usage-column",children:[n.jsxs("button",{type:"button",className:C===Y.day?"usage-column-hit is-hovered":"usage-column-hit",onMouseEnter:()=>y(Y.day),onMouseLeave:()=>y(""),onFocus:()=>y(Y.day),onBlur:()=>y(""),"aria-label":`${Y.day} 消费 ${St(Y.cost)},${Y.requests} 次请求`,children:[me&&n.jsx("span",{className:"usage-column-bar",style:{height:`${F}%`}}),D&&n.jsx("span",{className:"usage-column-peak",style:{bottom:`calc(${F}% + 6px)`},children:St(Y.cost)})]}),n.jsx("span",{className:"usage-column-tick",children:ae?vp(Y.day):""})]},Y.day)}),le&&n.jsxs("div",{className:"usage-tooltip",style:{left:`${(ie+.5)/R.length*100}%`},role:"status",children:[n.jsx("strong",{children:St(le.cost)}),n.jsx("span",{children:le.day}),n.jsxs("span",{children:[le.requests," 次请求"]})]})]})]}),n.jsxs("details",{className:"usage-table-toggle",children:[n.jsx("summary",{children:"查看数据表"}),n.jsxs("div",{className:"usage-table",children:[n.jsxs("div",{className:"usage-table-head",children:[n.jsx("span",{children:"日期"}),n.jsx("span",{children:"请求"}),n.jsx("span",{children:"消费"})]}),R.slice().reverse().map(Y=>n.jsxs("div",{className:"usage-table-row",children:[n.jsx("span",{children:Y.day}),n.jsx("span",{children:Y.requests}),n.jsx("span",{children:St(Y.cost)})]},Y.day))]})]})]})]}),n.jsxs("div",{className:"usage-block",children:[n.jsxs("div",{className:"usage-block-head",children:[n.jsx("strong",{children:"按模型拆分"}),n.jsxs("span",{children:["近 ",h.rangeDays," 天消费"]})]}),z.length===0?n.jsx("p",{className:"usage-placeholder",children:"这段时间还没有调用记录"}):n.jsx("div",{className:"usage-models",children:z.map(Y=>n.jsxs("div",{className:"usage-model-row",children:[n.jsx("span",{className:"usage-model-name",title:Y.model,children:Y.model}),n.jsx("span",{className:"usage-model-track",children:n.jsx("span",{className:"usage-model-bar",style:{width:`${ee>0?Y.cost/ee*100:0}%`}})}),n.jsx("span",{className:"usage-model-value",children:St(Y.cost)})]},Y.model))})]})]})]})}function gp({theme:u,setTheme:m,goHome:h,openLogin:r}){const[A,E]=g.useState(null),[L,$]=g.useState([]),[C,y]=g.useState(null),[R,z]=g.useState(!1),[P,ee]=g.useState(""),[de,ne]=g.useState(""),[le,ie]=g.useState("");async function xe(){try{const[D,ae,fe]=await Promise.all([pe("/api/account/me"),pe("/api/catalog/models"),pe("/api/account/check-in")]);E({...D,apiKeys:be(D.apiKeys)}),$(be(ae.models).map(cs)),y(fe.checkIn)}catch{r()}}g.useEffect(()=>{xe()},[]);async function Y(){if(!(!C?.enabled||C.claimed||R)){z(!0),ee("");try{const D=await pe("/api/account/check-in",{method:"POST",body:JSON.stringify({})});E(ae=>ae&&{...ae,user:D.user}),y(D.checkIn),ee(`签到成功,获得 ${D.reward.toFixed(2)} 额度`)}catch(D){ee(D instanceof Error?D.message:"签到失败,请稍后重试")}finally{z(!1)}}}async function ge(){try{const D=await pe("/api/account/api-keys",{method:"POST",body:JSON.stringify({name:"My API Key"})});ne(D.secret),ie("新密钥只显示这一次"),await xe()}catch(D){ie(D instanceof Error?D.message:"创建密钥失败")}}async function F(D){if(window.confirm("删除这个 API Key?使用它的请求会立即失效。"))try{await pe(`/api/account/api-keys/${D}`,{method:"DELETE"}),E(ae=>ae&&{...ae,apiKeys:ae.apiKeys.filter(fe=>fe.id!==D)}),ie("密钥已删除")}catch(ae){ie(ae instanceof Error?ae.message:"删除密钥失败")}}async function me(){await pe("/api/auth/logout",{method:"POST"}),h()}return n.jsxs("main",{className:"account-page","data-theme":u,children:[n.jsxs("header",{className:"account-topbar",children:[n.jsxs("button",{className:"auth-brand",onClick:h,children:[n.jsx("span",{className:"brand-mark",children:"C"}),n.jsx("strong",{children:"CAPI"})]}),n.jsxs("div",{className:"account-actions",children:[n.jsx("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>m(u==="dark"?"light":"dark"),children:n.jsx(Ot,{name:u==="dark"?"sun":"moon"})}),n.jsx("button",{className:"secondary-button",onClick:me,children:"退出"})]})]}),n.jsxs("section",{className:"account-content",children:[n.jsxs("div",{className:"account-heading",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"My CAPI"}),n.jsx("h1",{children:A?.user.name||"账户"})]}),n.jsxs("div",{className:"account-balance",children:[n.jsx("span",{children:"余额"}),n.jsx("strong",{children:A?A.user.balance.toFixed(2):"-"})]})]}),n.jsx(yp,{}),n.jsxs("section",{className:"account-section check-in-section",children:[n.jsxs("div",{className:"account-section-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Daily Reward"}),n.jsx("h2",{children:"每日签到"})]}),n.jsx("button",{className:"primary-button",disabled:!C?.enabled||!!C?.claimed||R,onClick:Y,children:R?"领取中":C?.claimed?"今日已签到":C?.enabled?"签到领额度":"暂未开放"})]}),n.jsxs("div",{className:"check-in-summary",children:[n.jsxs("div",{children:[n.jsx("span",{children:"今日状态"}),n.jsx("strong",{children:C?.claimed?`已领取 ${C.reward.toFixed(2)}`:C?.enabled?"等待签到":"活动关闭"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"随机奖励"}),n.jsx("strong",{children:C?`${C.minReward.toFixed(2)} - ${C.maxReward.toFixed(2)}`:"-"})]}),n.jsxs("div",{children:[n.jsx("span",{children:"结算日期"}),n.jsx("strong",{children:C?.day||"北京时间"})]})]}),n.jsx("p",{className:"check-in-note",children:"每天按北京时间 00:00 刷新,奖励领取后直接计入账户余额。"}),P&&n.jsx("p",{className:"account-message check-in-message",role:"status",children:P})]}),n.jsxs("section",{className:"account-section",children:[n.jsxs("div",{className:"account-section-title",children:[n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"API Keys"}),n.jsx("h2",{children:"API 密钥"})]}),n.jsx("button",{className:"primary-button",onClick:ge,children:"创建密钥"})]}),de&&n.jsx("code",{className:"one-time-secret",children:de}),le&&n.jsx("p",{className:"account-message",children:le}),n.jsxs("div",{className:"account-key-list",children:[A?.apiKeys?.map(D=>n.jsxs("div",{className:"account-key-item",children:[n.jsx("span",{className:"account-key-mark","aria-hidden":"true",children:n.jsx(Ot,{name:"key"})}),n.jsxs("div",{className:"account-key-info",children:[n.jsx("strong",{children:D.name}),n.jsxs("code",{children:[D.prefix,"…"]})]}),n.jsx(Dt,{tone:D.status,children:_t(D.status)}),n.jsx("button",{className:"icon-button","aria-label":`删除 ${D.name}`,title:"删除密钥",onClick:()=>F(D.id),children:n.jsx(Ot,{name:"ban"})})]},D.id)),be(A?.apiKeys).length===0&&n.jsx("div",{className:"empty",children:"还没有 API 密钥"})]})]}),n.jsxs("section",{className:"account-section",children:[n.jsx("div",{className:"account-section-title",children:n.jsxs("div",{children:[n.jsx("p",{className:"eyebrow",children:"Models"}),n.jsx("h2",{children:"可用模型"})]})}),n.jsxs("div",{className:"account-model-grid",children:[L.map(D=>n.jsxs("article",{children:[n.jsx("span",{children:D.vendor}),n.jsx("strong",{children:D.name}),n.jsx("p",{children:D.description}),n.jsx("code",{children:D.id})]},D.id)),L.length===0&&n.jsx("div",{className:"account-model-empty",children:"暂无可用模型,管理员配置渠道后将在此展示"})]})]})]})]})}function bp({theme:u,setTheme:m,enterConsole:h}){return n.jsxs("main",{className:"public-home","data-theme":u,children:[n.jsxs("header",{className:"home-topbar",children:[n.jsxs("div",{className:"home-brand",children:[n.jsx("div",{className:"brand-mark",children:"C"}),n.jsxs("div",{children:[n.jsx("strong",{children:"CAPI"}),n.jsx("span",{children:"AI 聚合网关"})]})]}),n.jsxs("div",{className:"home-actions",children:[n.jsxs("button",{className:"theme-toggle","aria-label":"切换暗色模式",onClick:()=>m(u==="dark"?"light":"dark"),children:[n.jsx(Ot,{name:u==="dark"?"sun":"moon"}),n.jsx("span",{children:u==="dark"?"浅色":"暗色"})]}),n.jsx("button",{className:"primary-button",onClick:h,children:"控制台"})]})]}),n.jsxs("section",{className:"home-hero",children:[n.jsxs("div",{className:"home-copy",children:[n.jsx("span",{className:"home-kicker",children:"兼容 OpenAI 格式的网关"}),n.jsxs("h1",{children:["CAPI",n.jsx("span",{children:"轻量 AI 聚合网关"})]}),n.jsx("p",{children:"面向个人用户和团队的模型接入层。把 API Key、额度、模型渠道和调用日志放在一个清爽控制台里,保持轻量,也便于排障。"}),n.jsx("div",{className:"home-cta",children:n.jsx("button",{className:"primary-button",onClick:h,children:"进入控制台"})}),n.jsxs("div",{className:"integration-row","aria-label":"网关能力概览",children:[n.jsx("span",{children:"网关能力"}),n.jsxs("div",{children:[n.jsx("span",{children:"OpenAI 兼容接口"}),n.jsx("span",{children:"额度控制"}),n.jsx("span",{children:"调用审计"})]})]})]}),n.jsxs("div",{className:"gateway-terminal","aria-label":"CAPI 终端请求示意",children:[n.jsxs("div",{className:"terminal-titlebar",children:[n.jsxs("div",{className:"terminal-dots","aria-hidden":"true",children:[n.jsx("span",{}),n.jsx("span",{}),n.jsx("span",{})]}),n.jsx("strong",{children:"CAPI Terminal"}),n.jsxs("div",{className:"terminal-status",children:[n.jsx("span",{className:"pulse-dot"}),n.jsx("strong",{children:"Online"})]})]}),n.jsxs("div",{className:"terminal-endpoint",children:[n.jsx("span",{children:"POST"}),n.jsx("strong",{children:"/v1/chat/completions"})]}),n.jsxs("div",{className:"terminal-body",children:[n.jsxs("div",{className:"terminal-block",children:[n.jsx("span",{children:"REQUEST"}),n.jsx("pre",{children:`curl https://api.capi.local/v1/chat/completions \\ -H "Authorization: Bearer cat_..." \\ -d '{ "model": "capi-fast", @@ -16,10 +16,10 @@ Error generating stack: `+a.message+` "model": "capi-fast", "usage": { "total_tokens": 27 }, "message": "request routed" -}`,n.jsx("span",{className:"terminal-caret","aria-hidden":"true"})]})]})]})]})]})]})}function gp({overview:c,channels:m,logs:h,onNavigate:r}){const A=h.filter(E=>E.status!=="success");return n.jsxs("section",{className:"page-stack",children:[n.jsxs("div",{className:"hero-strip",children:[n.jsxs("div",{children:[n.jsx("span",{children:"Live Gateway"}),n.jsxs("strong",{children:["CAPI 网关正在服务 ",c?.activeUsers??"-"," 个活跃用户"]}),n.jsx("p",{children:"请求进入 CAPI 后,会按额度、模型和渠道状态自动选择最合适的上游。"})]}),n.jsxs("div",{className:"live-island",children:[n.jsx("div",{className:"pulse-dot"}),n.jsx("span",{children:"在线"})]})]}),n.jsxs("div",{className:"quick-actions","aria-label":"快捷操作",children:[n.jsx(Si,{icon:"key",label:"创建 Key",onClick:()=>r("keys")}),n.jsx(Si,{icon:"route",label:"配置渠道",onClick:()=>r("channels")}),n.jsx(Si,{icon:"users",label:"调整额度",onClick:()=>r("users")}),n.jsx(Si,{icon:"logs",label:"查看异常",onClick:()=>r("logs")})]}),n.jsxs("div",{className:"metrics-grid",children:[n.jsx(ul,{label:"活跃用户",value:c?ml(c.activeUsers):"-"}),n.jsx(ul,{label:"今日请求",value:c?ml(c.requestsToday):"-"}),n.jsx(ul,{label:"今日输入",value:c?ml(c.todayInputTokens):"-"}),n.jsx(ul,{label:"今日输出",value:c?ml(c.todayOutputTokens):"-"}),n.jsx(ul,{label:"今日扣费",value:c?St(c.todayCost,4):"-"}),n.jsx(ul,{label:"账户余额",value:c?St(c.totalBalance):"-"}),n.jsx(ul,{label:"成功率",value:c?`${c.successRate}%`:"-"})]}),n.jsx(bp,{}),n.jsxs("div",{className:"split-grid",children:[n.jsx(nt,{title:"渠道状态",children:m.length?m.map(E=>n.jsxs("div",{className:"list-row overview-channel-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:E.name}),n.jsx("span",{title:be(E.models).join(", "),children:ip(E.models)})]}),n.jsx(Dt,{tone:E.status,children:_t(E.status)})]},E.id)):n.jsx(Lt,{text:"暂无渠道"})}),n.jsx(nt,{title:"最近请求",children:h.length?h.slice(0,4).map(E=>n.jsxs("div",{className:"list-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:to(E)}),n.jsxs("span",{children:[E.id," · ",E.errorCode||el(E.createdAt)]})]}),n.jsx(Dt,{tone:E.status,children:_t(E.status)})]},E.id)):n.jsx(Lt,{text:A.length?"暂无最近请求":"暂无请求"})})]})]})}function Si({icon:c,label:m,onClick:h}){return n.jsxs("button",{className:"quick-action",onClick:h,children:[n.jsx(Ot,{name:c}),n.jsx("span",{children:m})]})}function bp(){const c=[{label:"认证",detail:"校验 API Key"},{label:"额度",detail:"检查余额"},{label:"路由",detail:"选择渠道"},{label:"响应",detail:"返回结果"}];return n.jsxs("section",{className:"flow-panel","aria-label":"网关流转",children:[n.jsxs("div",{className:"flow-copy",children:[n.jsx("span",{children:"Request Flow"}),n.jsx("strong",{children:"请求处理流程"})]}),n.jsx("div",{className:"flow-steps",children:c.map((m,h)=>n.jsxs("div",{className:"flow-step",children:[n.jsx("div",{className:"flow-index",children:h+1}),n.jsx("strong",{children:m.label}),n.jsx("span",{children:m.detail})]},m.label))})]})}function xp({users:c,query:m,selectedUser:h,onQuery:r,onSelect:A,onUpdate:E,onBulkUpdate:L,onCreateKey:$,groups:C,onOpenRegistration:y}){const[z,P]=g.useState(1),[ee,de]=g.useState("all"),[ne,le]=g.useState(new Set),[ie,xe]=g.useState("10"),[Y,ge]=g.useState(""),[F,me]=g.useState(""),[D,ae]=g.useState(!1),[fe,Ae]=g.useState("10"),[Te,ue]=g.useState(""),[Z,re]=g.useState(""),[J,T]=g.useState(!1),k=ee==="all"?c:c.filter(N=>N.status===ee),B=k.filter(N=>N.role!=="admin"),Q=Math.max(1,Math.ceil(k.length/25)),O=Math.min(z,Q),d=k.slice((O-1)*25,O*25),x=B.length>0&&B.every(N=>ne.has(N.id));g.useEffect(()=>{P(1)},[m,ee]),g.useEffect(()=>{const N=new Set(c.map(Ne=>Ne.id));le(Ne=>new Set([...Ne].filter(Se=>N.has(Se))))},[c]),g.useEffect(()=>{Ae("10"),ue(""),re("")},[h?.user.id]);function G(N){le(Ne=>{const Se=new Set(Ne);return Se.has(N)?Se.delete(N):Se.add(N),Se})}function X(){le(N=>{const Ne=new Set(N);return x?B.forEach(Se=>Ne.delete(Se.id)):B.forEach(Se=>Ne.add(Se.id)),Ne})}async function se(N,Ne){if(ne.size!==0){ae(!0);try{await L([...ne],N,Ne),le(new Set),ge("")}finally{ae(!1)}}}async function ve(N){if(!h)return;const Ne=Math.abs(Number(fe));if(!Number.isFinite(Ne)||Ne<=0){re("请输入大于 0 的金额");return}T(!0),re("");try{await L([h.user.id],"adjust_balance",{amount:Number((Ne*N).toFixed(4)),reason:Te.trim()||(N>0?"管理员增加额度":"管理员扣减额度")}),re(N>0?"额度已增加":"额度已扣减"),ue("")}catch(Se){re(Se instanceof Error?Se.message:"额度调整失败")}finally{T(!1)}}return n.jsxs("section",{className:"users-layout",children:[n.jsxs(nt,{title:"用户管理",children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsxs("div",{className:"search-box",children:[n.jsx(Ot,{name:"search"}),n.jsx("input",{value:m,onChange:N=>r(N.target.value),placeholder:"搜索 ID、姓名或邮箱"})]}),n.jsx("button",{className:"icon-button",title:"开放注册",onClick:y,children:n.jsx(Ot,{name:"plus"})})]}),n.jsxs("div",{className:"user-summary-strip",children:[n.jsxs("span",{children:[n.jsx("strong",{children:c.length})," 匹配用户"]}),n.jsxs("span",{children:[n.jsx("strong",{children:c.filter(N=>N.status==="active").length})," 正常"]}),n.jsxs("span",{children:[n.jsx("strong",{children:c.filter(N=>N.status==="disabled").length})," 禁用"]}),n.jsxs("span",{children:[n.jsx("strong",{children:c.reduce((N,Ne)=>N+Ne.requestsToday,0)})," 今日请求"]})]}),n.jsx("div",{className:"user-filter-row",role:"group","aria-label":"用户状态筛选",children:[{value:"all",label:"全部"},{value:"active",label:"正常"},{value:"limited",label:"受限"},{value:"disabled",label:"禁用"}].map(N=>n.jsx("button",{type:"button",className:ee===N.value?"selected":"",onClick:()=>de(N.value),children:N.label},N.value))}),n.jsx("button",{type:"button",className:"secondary-button mobile-bulk-select",onClick:X,children:x?"取消全选":`全选结果(${B.length})`}),ne.size>0&&n.jsxs("div",{className:"bulk-action-bar",children:[n.jsxs("strong",{children:["已选 ",ne.size," 人"]}),n.jsx("input",{type:"number",step:"0.01",value:ie,onChange:N=>xe(N.target.value),"aria-label":"额度调整值"}),n.jsx("input",{value:Y,onChange:N=>ge(N.target.value),placeholder:"原因,例如:活动赠送","aria-label":"调整原因"}),n.jsx("button",{type:"button",className:"secondary-button",disabled:D||!Number(ie),onClick:()=>se("adjust_balance",{amount:Number(ie),reason:Y}),children:"调整额度"}),n.jsx("button",{type:"button",className:"secondary-button",disabled:D,onClick:()=>se("set_status",{value:"active"}),children:"启用"}),n.jsx("button",{type:"button",className:"danger-button",disabled:D,onClick:()=>se("set_status",{value:"disabled"}),children:"禁用"}),n.jsxs("select",{className:"bulk-group-select",value:F,disabled:D,"aria-label":"批量设置分组",onChange:N=>me(N.target.value),children:[n.jsx("option",{value:"",children:"未分组"}),C.map(N=>n.jsx("option",{value:N.id,children:N.name},N.id))]}),n.jsx("button",{type:"button",className:"secondary-button",disabled:D,onClick:()=>se("set_group",{value:F}),children:"设为分组"})]}),n.jsxs("div",{className:"table",children:[n.jsxs("div",{className:"table-head users-table",children:[n.jsx("input",{type:"checkbox",checked:x,onChange:X,"aria-label":"选择当前筛选结果"}),n.jsx("span",{children:"用户"}),n.jsx("span",{children:"状态"}),n.jsx("span",{children:"余额"}),n.jsx("span",{children:"今日"})]}),d.map(N=>n.jsxs("div",{className:h?.user.id===N.id?"table-row users-table selected":"table-row users-table",role:"button",tabIndex:0,onClick:()=>A(N.id),onKeyDown:Ne=>{(Ne.key==="Enter"||Ne.key===" ")&&A(N.id)},children:[n.jsx("input",{type:"checkbox",checked:ne.has(N.id),disabled:N.role==="admin",onChange:()=>G(N.id),onClick:Ne=>Ne.stopPropagation(),"aria-label":N.role==="admin"?`${N.name} 是管理员,不参与批量操作`:`选择 ${N.name}`}),n.jsxs("span",{children:[n.jsx("strong",{children:N.name}),n.jsxs("small",{children:[N.id," · ",N.email||"未绑定邮箱"]})]}),n.jsx(Dt,{tone:N.status,children:_t(N.status)}),n.jsx("span",{children:St(N.balance)}),n.jsx("span",{children:N.requestsToday})]},N.id)),k.length===0&&n.jsx(Lt,{text:"暂无匹配用户"})]}),k.length>25&&n.jsxs("div",{className:"pagination-bar",children:[n.jsx("button",{className:"secondary-button",disabled:O<=1,onClick:()=>P(N=>Math.max(1,N-1)),children:"上一页"}),n.jsxs("span",{children:[O," / ",Q]}),n.jsx("button",{className:"secondary-button",disabled:O>=Q,onClick:()=>P(N=>Math.min(Q,N+1)),children:"下一页"})]})]}),n.jsx(nt,{title:"用户详情",children:h?n.jsxs("div",{className:"detail-stack",children:[n.jsxs("div",{className:"user-hero",children:[n.jsx("div",{className:"avatar",children:h.user.name.slice(0,1)}),n.jsxs("div",{children:[n.jsx("h2",{children:h.user.name}),n.jsx("p",{children:h.user.email})]}),n.jsx(Dt,{tone:h.user.status,children:_t(h.user.status)})]}),n.jsxs("div",{className:"settings-group",children:[n.jsx(Pt,{label:"角色",value:h.user.role==="admin"?"管理员":"用户"}),n.jsx(Pt,{label:"余额",value:St(h.user.balance)}),n.jsx(Pt,{label:"总请求",value:String(h.user.totalRequests)}),n.jsx(Pt,{label:"最后登录",value:el(h.user.lastLoginAt)}),n.jsx(Pt,{label:"API 调用",value:h.user.status==="disabled"?"关闭":"允许",switchOn:h.user.status!=="disabled"})]}),n.jsxs("div",{className:"group-assign-row",children:[n.jsxs("label",{children:[n.jsx("span",{children:"所属分组"}),n.jsxs("select",{value:h.user.groupId||"",onChange:N=>E(h.user.id,{groupId:N.target.value}),children:[n.jsx("option",{value:"",children:"未分组"}),C.map(N=>n.jsx("option",{value:N.id,children:N.name},N.id))]})]}),n.jsx("small",{children:"分组决定该用户可路由到哪些渠道;未分组用户只能使用未限制分组的渠道。"})]}),n.jsxs("div",{className:"balance-adjuster",children:[n.jsxs("div",{className:"balance-adjuster-title",children:[n.jsx("strong",{children:"调整余额"}),n.jsxs("span",{children:["当前 ",St(h.user.balance)]})]}),n.jsxs("div",{className:"balance-adjuster-fields",children:[n.jsxs("label",{children:[n.jsx("span",{children:"金额"}),n.jsx("input",{type:"number",min:"0.0001",step:"0.01",value:fe,onChange:N=>Ae(N.target.value)})]}),n.jsxs("label",{children:[n.jsx("span",{children:"备注"}),n.jsx("input",{value:Te,onChange:N=>ue(N.target.value),placeholder:"可选,会记录到流水"})]})]}),n.jsxs("div",{className:"balance-adjuster-actions",children:[n.jsx("button",{className:"secondary-button",disabled:J,onClick:()=>ve(1),children:"增加"}),n.jsx("button",{className:"danger-button",disabled:J,onClick:()=>ve(-1),children:"扣减"}),n.jsx("span",{role:"status",children:Z})]})]}),n.jsxs("div",{className:"action-row",children:[n.jsx("button",{className:"secondary-button",onClick:()=>$(h.user.id),children:"创建 Key"}),n.jsx("button",{className:"secondary-button",disabled:h.user.role==="admin",onClick:()=>E(h.user.id,{status:h.user.status==="disabled"?"active":"disabled"}),children:h.user.role==="admin"?"管理员保护":h.user.status==="disabled"?"解封":"禁用"})]}),n.jsxs("div",{children:[n.jsx("h3",{children:"API Key"}),h.apiKeys.map(N=>n.jsxs("div",{className:"list-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:N.name}),n.jsxs("span",{children:[N.prefix,"*** · ",N.requestCount," 次"]})]}),n.jsx(Dt,{tone:N.status,children:_t(N.status)})]},N.id)),h.apiKeys.length===0&&n.jsx(Lt,{text:"暂无 API Key"})]})]}):n.jsx(Lt,{text:"请选择一个用户"})})]})}function jp({selectedUser:c,onCreateKey:m,onUpdateKey:h,onDeleteKey:r}){return n.jsx(nt,{title:"密钥管理",children:c?n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsxs("span",{className:"muted-inline",children:[c.user.name," · 完整 Key 只在创建时显示,丢失请重新创建"]}),n.jsx("button",{className:"primary-button",onClick:()=>m(c.user.id),children:"创建 Key"})]}),c.apiKeys.length?c.apiKeys.map(A=>n.jsx(Sp,{apiKey:A,onSave:h,onDelete:r},A.id)):n.jsx(Lt,{text:"暂无密钥"})]}):n.jsx(Lt,{text:"请选择一个用户"})})}function Sp({apiKey:c,onSave:m,onDelete:h}){const[r,A]=g.useState(c.name),[E,L]=g.useState(be(c.allowedModels).join(", ")),[$,C]=g.useState(fm(c.expiresAt||"")),[y,R]=g.useState(String(c.rateLimitPerMinute||"")),[z,P]=g.useState(!1),ee=be(c.allowedModels).length?be(c.allowedModels).join(", "):"全部模型";g.useEffect(()=>{A(c.name),L(be(c.allowedModels).join(", ")),C(fm(c.expiresAt||"")),R(String(c.rateLimitPerMinute||""))},[c]);async function de(){P(!0);try{await m(c.id,{name:r.trim()||"API Key",allowedModels:Ic(E),expiresAt:lp($),rateLimitPerMinute:Number(y||0)})}finally{P(!1)}}return n.jsxs("details",{className:"key-editor key-editor-collapsible",children:[n.jsxs("summary",{className:"key-editor-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:c.name}),n.jsxs("span",{children:[c.prefix,"*** · ",ee," · 最后使用 ",el(c.lastUsedAt)]})]}),n.jsxs("div",{className:"row-actions",children:[n.jsx(Dt,{tone:c.status,children:_t(c.status)}),n.jsx("span",{className:"key-expand-hint",children:"管理"})]})]}),n.jsxs("div",{className:"key-editor-body",children:[n.jsxs("div",{className:"key-editor-grid",children:[n.jsxs("label",{children:["名称",n.jsx("input",{value:r,onChange:ne=>A(ne.target.value)})]}),n.jsxs("label",{children:["允许模型",n.jsx("input",{value:E,onChange:ne=>L(ne.target.value),placeholder:"留空表示全部模型,多个用逗号分隔"})]}),n.jsxs("label",{children:["过期时间",n.jsx("input",{type:"datetime-local",value:$,onChange:ne=>C(ne.target.value)})]}),n.jsxs("label",{children:["每分钟限制",n.jsx("input",{type:"number",min:"0",value:y,onChange:ne=>R(ne.target.value),placeholder:"0 使用全局限制"})]})]}),n.jsxs("div",{className:"key-editor-actions",children:[n.jsx("button",{className:"secondary-button",onClick:()=>m(c.id,{status:c.status==="active"?"disabled":"active"}),children:c.status==="active"?"停用密钥":"启用密钥"}),n.jsx("button",{className:"danger-button",onClick:()=>h(c.id),children:"删除密钥"}),n.jsx("button",{className:"primary-button",disabled:z,onClick:de,children:z?"保存中":"保存设置"})]})]})]})}function Np({models:c,onCopy:m,onCreate:h,onUpdate:r,onDelete:A}){const E=c.filter(B=>B.recommended),[L,$]=g.useState(""),[C,y]=g.useState("all"),[R,z]=g.useState("all"),[P,ee]=g.useState(1),[de,ne]=g.useState(""),[le,ie]=g.useState(""),[xe,Y]=g.useState(""),[ge,F]=g.useState(""),[me,D]=g.useState(""),[ae,fe]=g.useState(""),Ae=60,Te=g.useMemo(()=>{const B=new Map;return c.forEach(Q=>{const O=$c(Q);B.set(O,(B.get(O)||0)+1)}),Array.from(B.entries()).sort((Q,O)=>O[1]-Q[1]||il(Q[0]).localeCompare(il(O[0]))).map(([Q,O])=>({provider:Q,count:O}))},[c]),ue=g.useMemo(()=>{const B=L.trim().toLowerCase();return c.filter(Q=>C!=="all"&&$c(Q)!==C||R!=="all"&&Q.status!==R?!1:B?[Q.id,Q.name,Q.vendor,Q.category,Q.description,...be(Q.aliases)].join(" ").toLowerCase().includes(B):!0)},[c,L,C,R]),Z=g.useMemo(()=>{const B=new Map;ue.forEach(G=>{const X=$c(G);B.set(X,[...B.get(X)||[],G])});const Q=[];let O=[],d=0;const x=Array.from(B.entries()).sort((G,X)=>il(G[0]).localeCompare(il(X[0])));for(const G of x)O.length>0&&d+G[1].length>Ae&&(Q.push(O),O=[],d=0),O.push(G),d+=G[1].length;return O.length>0&&Q.push(O),Q},[ue]),re=Math.max(1,Z.length),J=Math.min(P,re),T=Z[J-1]||[];g.useEffect(()=>{ee(1)},[L,C,R,c.length]);async function k(B){B.preventDefault();const Q=de.trim();if(Q){fe("");try{await h({id:Q,name:le.trim()||Q,vendor:xe.trim()||"Custom",aliases:ge.split(",").map(O=>O.trim()).filter(Boolean),category:"通用",description:me.trim(),price:"自定义",context:"未配置上下文"}),ne(""),ie(""),Y(""),F(""),D("")}catch(O){fe(O instanceof Error?O.message:"模型添加失败")}}}return n.jsxs("section",{className:"models-page",children:[n.jsx("div",{className:"model-hero",children:n.jsxs("div",{children:[n.jsx("span",{children:"Model Catalog"}),n.jsx("strong",{children:"Models"})]})}),n.jsx(nt,{title:"新增模型",children:n.jsxs("form",{className:"model-create-form",onSubmit:k,children:[n.jsx("input",{value:de,onChange:B=>ne(B.target.value),placeholder:"模型 ID,例如 openai/gpt-4.1"}),n.jsx("input",{value:le,onChange:B=>ie(B.target.value),placeholder:"显示名称(可选)"}),n.jsx("input",{value:xe,onChange:B=>Y(B.target.value),placeholder:"供应商(可选)"}),n.jsx("input",{value:ge,onChange:B=>F(B.target.value),placeholder:"代称,多个用逗号分隔(可选)"}),n.jsx("input",{className:"model-create-wide",value:me,onChange:B=>D(B.target.value),placeholder:"描述(可选)"}),n.jsx("button",{className:"primary-button",type:"submit",children:"新增模型"}),n.jsx("div",{className:"model-create-message",role:"status",children:ae})]})}),E.length>0&&n.jsx(nt,{title:"推荐模型",children:n.jsx("div",{className:"model-grid",children:E.map(B=>n.jsx(Cp,{model:B,featured:!0,onCopy:m,onUpdate:r},B.id))})}),n.jsxs(nt,{title:"全部模型",children:[n.jsxs("div",{className:"panel-toolbar model-list-toolbar",children:[n.jsx("input",{value:L,onChange:B=>$(B.target.value),placeholder:"搜索模型 ID、名称、供应商或代称"}),n.jsx("div",{className:"model-filter-actions",children:[{value:"all",label:"全部"},{value:"available",label:"可用"},{value:"disabled",label:"禁用"}].map(B=>n.jsx("button",{type:"button",className:R===B.value?"selected":"",onClick:()=>z(B.value),children:B.label},B.value))})]}),n.jsxs("div",{className:"model-provider-filter","aria-label":"按供应商筛选模型",children:[n.jsxs("button",{type:"button",className:C==="all"?"selected":"",onClick:()=>y("all"),children:[n.jsx("span",{className:"provider-icon provider-icon-all","aria-hidden":"true",children:"All"}),n.jsx("strong",{children:"全部"}),n.jsx("small",{children:c.length})]}),Te.map(B=>n.jsxs("button",{type:"button",className:C===B.provider?"selected":"",onClick:()=>y(B.provider),children:[n.jsx(mm,{provider:B.provider}),n.jsx("strong",{children:il(B.provider)}),n.jsx("small",{children:B.count})]},B.provider))]}),n.jsxs("div",{className:"model-list-summary",children:[n.jsx("span",{children:C==="all"?"全部供应商":il(C)}),n.jsx("strong",{children:ue.length}),n.jsx("span",{children:"个模型"})]}),ue.length>0?n.jsxs(n.Fragment,{children:[n.jsx("div",{className:"model-provider-groups",children:T.map(([B,Q])=>n.jsxs("section",{className:"model-provider-group",children:[n.jsxs("header",{children:[n.jsx(mm,{provider:B}),n.jsxs("div",{children:[n.jsx("strong",{children:il(B)}),n.jsxs("span",{children:[Q.length," 个模型"]})]})]}),n.jsx("div",{className:"model-compact-grid",children:Q.map(O=>n.jsx(Ap,{model:O,onCopy:m,onUpdate:r,onDelete:A},O.id))})]},B))}),re>1&&n.jsxs("div",{className:"pager",children:[n.jsx("button",{className:"secondary-button compact-button",onClick:()=>ee(B=>Math.max(1,B-1)),disabled:J<=1,children:"上一页"}),n.jsxs("span",{children:[J," / ",re]}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>ee(B=>Math.min(re,B+1)),disabled:J>=re,children:"下一页"})]})]}):n.jsx(Lt,{text:c.length?"没有匹配的模型":"暂无模型,请先添加你要开放给用户调用的模型 ID"})]})]})}function Ap({model:c,onCopy:m,onUpdate:h,onDelete:r}){const A=be(c.aliases).slice(0,3),E=c.status==="disabled";return n.jsxs("article",{className:"model-compact-row",children:[n.jsxs("div",{className:"model-compact-main",children:[n.jsx("strong",{children:c.name}),n.jsx("small",{children:c.id}),A.length>0&&n.jsx("span",{children:A.map(L=>n.jsx("em",{children:L},L))})]}),n.jsxs("div",{className:"model-row-actions",children:[n.jsx(Dt,{tone:c.status,children:_t(c.status)}),c.recommended&&n.jsx("span",{className:"model-recommended-mark",children:"推荐"}),n.jsx("button",{className:"icon-button",title:"复制模型 ID",onClick:()=>m(c.id,"模型 ID 已复制"),children:n.jsx(Ot,{name:"copy"})}),n.jsxs("details",{className:"model-row-menu",children:[n.jsx("summary",{"aria-label":"模型操作",children:"•••"}),n.jsxs("div",{children:[n.jsx("button",{type:"button",onClick:()=>h(c.id,{recommended:!c.recommended}),children:c.recommended?"取消推荐":"设为推荐"}),n.jsx("button",{type:"button",onClick:()=>h(c.id,{status:E?"available":"disabled"}),children:E?"启用模型":"停用模型"}),n.jsx("button",{className:"is-danger",type:"button",onClick:()=>r(c.id),children:"删除模型"})]})]})]})]})}function Cp({model:c,featured:m=!1,onCopy:h,onUpdate:r}){return n.jsxs("article",{className:m?"model-card featured":"model-card",children:[n.jsxs("div",{className:"model-card-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:c.name}),n.jsxs("span",{children:[c.vendor," · ",c.category]})]}),n.jsx(Dt,{tone:c.status,children:_t(c.status)})]}),n.jsx("p",{children:c.description}),n.jsx("div",{className:"alias-row",children:be(c.aliases).map(A=>n.jsx("span",{children:A},A))}),n.jsxs("div",{className:"model-meta",children:[n.jsxs("span",{children:["价格:",c.price]}),n.jsx("span",{children:c.context})]}),n.jsxs("div",{className:"model-id",children:[n.jsx("code",{children:c.id}),n.jsx("button",{className:"icon-button",title:"复制模型 ID",onClick:()=>h(c.id,"模型 ID 已复制"),children:n.jsx(Ot,{name:"copy"})})]}),r&&n.jsxs("div",{className:"model-card-actions",children:[n.jsx("button",{className:"secondary-button compact-button",type:"button",onClick:()=>r(c.id,{recommended:!1}),children:"取消推荐"}),n.jsx("button",{className:"secondary-button compact-button",type:"button",onClick:()=>r(c.id,{status:c.status==="disabled"?"available":"disabled"}),children:c.status==="disabled"?"启用":"停用"})]})]})}function Tp({channels:c,onCreate:m,onImport:h,onCheckAccounts:r,onDeduplicateAccounts:A,onDeleteAccount:E,onUpdate:L,onStartOAuth:$,onCompleteOAuth:C}){const y=c.filter(O=>O.provider==="codex"||O.provider==="openai"||be(O.models).some(d=>d.includes("image"))),[R,z]=g.useState(""),[P,ee]=g.useState({}),[de,ne]=g.useState({}),[le,ie]=g.useState({}),[xe,Y]=g.useState({}),[ge,F]=g.useState(""),[me,D]=g.useState(""),[ae,fe]=g.useState(""),[Ae,Te]=g.useState(""),ue=24,Z=48;async function re(O,d){z(`import:${O}`);try{await h(O,d)}finally{z("")}}async function J(O,d=!1,x=""){z(x?`check-account:${x}`:`${d?"retry":"check"}:${O}`);try{await r(O,d,x)}finally{z("")}}async function T(O){z(`dedupe:${O}`);try{await A(O)}finally{z("")}}function k(O){const d=be(O.openaiAccounts).map(N=>[N.email||N.name||N.accountId||N.id,N.accountId||"",N.status||"unchecked",N.credentialMode||"access-token",N.planType||"",N.expiresAt||"",N.lastCheckedAt||"",N.lastUsedAt||"",String(N.requestCount||0),N.lastErrorCode||"",N.lastError||""]),x=N=>`"${N.replace(/"/g,'""')}"`,G=[["账号","Account ID","状态","凭据方式","套餐","到期时间","最近检测","最近调用","调用次数","错误码","最后错误"],...d].map(N=>N.map(x).join(",")).join(`\r -`),X=new Blob(["\uFEFF"+G],{type:"text/csv;charset=utf-8"}),se=URL.createObjectURL(X),ve=document.createElement("a");ve.href=se,ve.download=`${O.name||"account-pool"}-health-report.csv`,ve.click(),URL.revokeObjectURL(se)}async function B(O){z(`status:${O.id}`);try{await L(O.id,{status:O.status==="disabled"?"healthy":"disabled",baseUrl:O.baseUrl||Ei(O.provider)||Ti,provider:O.provider||"codex",models:be(O.models).length?O.models:bm.split(",").map(d=>d.trim())})}finally{z("")}}async function Q(O,d){const x=d.email||d.name||d.accountId||d.id;if(window.confirm(`删除账号「${x}」?`)){z(`delete-account:${d.id}`);try{await E(O.id,d.id)}finally{z("")}}}return n.jsxs(nt,{title:"账号池",children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsx("span",{className:"muted-inline",children:"账号有两种来源,任选其一即可。"}),n.jsx("button",{className:"primary-button",onClick:()=>m(xm("codex")),children:"新增账号池渠道"})]}),n.jsxs("div",{className:"source-guide",children:[n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"网页会话(推荐)"}),n.jsx("span",{children:"支持完整 auth/session JSON 或浏览器 Session Cookie,并在调用前重新获取 accessToken。"})]}),n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"批量导入"}),n.jsx("span",{children:"支持 JSON、ZIP、TXT;TXT 可使用 JSONL 或每行一个 access token。"})]})]}),n.jsxs("div",{className:"channels-stack",children:[y.map(O=>{const d=be(O.openaiAccounts),x=d.filter(V=>V.status==="healthy").length,G=d.filter(V=>V.status==="invalid").length,X=d.filter(V=>!!V.lastErrorCode).length,se=Math.max(0,d.length-x-G),ve=d.filter(V=>V.credentialMode==="refreshable").length,N=d.filter(V=>V.credentialMode==="browser-session").length,Ne=Math.max(0,d.length-ve-N),Se=de[O.id]||"all",bt=(le[O.id]||"").trim().toLowerCase(),I=d.filter(V=>{const _=Se==="all"||Se==="attention"&&Bp(V)||Se==="invalid"&&V.status==="invalid"||Se==="error"&&!!V.lastErrorCode||Se==="refreshable"&&V.credentialMode==="refreshable",Ee=`${V.email||""} ${V.name||""} ${V.accountId||""} ${V.userId||""} ${V.lastError||""}`.toLowerCase();return _&&(!bt||Ee.includes(bt))}),Ke=xe[O.id]||"pool",We=[...I].sort((V,_)=>{if(Ke==="pool")return 0;const Ee=Ke==="expiry"?V.expiresAt||"9999-12-31":V.lastUsedAt||"",et=Ke==="expiry"?_.expiresAt||"9999-12-31":_.lastUsedAt||"";return Ke==="recent"?et.localeCompare(Ee):Ee.localeCompare(et)}),Pe=Math.min(We.length,P[O.id]||ue),tl=We.slice(0,Pe),kt=Math.max(0,We.length-tl.length),cl=kt===0;return n.jsxs("div",{className:"channel-card",children:[n.jsxs("div",{className:"channel-card-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:O.name}),n.jsx("span",{children:O.baseUrl||Ei(O.provider)||Ti}),n.jsxs("small",{children:["账号 ",d.length," 个,可用 ",x,",无效 ",G,",未验证 ",se]}),n.jsxs("small",{children:["可续期 ",ve," · 网页会话 ",N," · 仅 Token ",Ne]}),n.jsxs("small",{children:["自动检测 ",O.lastCheckedAt?el(O.lastCheckedAt):"等待首次检测"]})]}),n.jsxs("div",{className:"channel-card-head-actions",children:[n.jsx(Dt,{tone:O.status,children:_t(O.status)}),n.jsx("button",{className:"primary-button compact-button",onClick:()=>Te(O.id),disabled:R!=="",children:"添加账号"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>J(O.id),disabled:R!==""||d.length===0,children:R===`check:${O.id}`?"检测中":"批量检测"}),G>0&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>J(O.id,!0),disabled:R!=="",children:R===`retry:${O.id}`?"复检中":`复检无效 ${G}`}),d.length>1&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>T(O.id),disabled:R!=="",children:R===`dedupe:${O.id}`?"去重中":"账号去重"}),d.length>0&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>k(O),disabled:R!=="",children:"导出报告"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>B(O),disabled:R!=="",children:O.status==="disabled"?"启用渠道":"停用渠道"})]})]}),n.jsxs("div",{className:"account-filter-bar",role:"group","aria-label":"账号筛选",children:[n.jsx("input",{value:le[O.id]||"",onChange:V=>ie(_=>({..._,[O.id]:V.target.value})),placeholder:"搜索账号或错误","aria-label":"搜索账号"}),n.jsxs("select",{value:Ke,onChange:V=>Y(_=>({..._,[O.id]:V.target.value})),"aria-label":"账号排序",children:[n.jsx("option",{value:"pool",children:"账号池顺序"}),n.jsx("option",{value:"oldest",children:"最久未用优先"}),n.jsx("option",{value:"recent",children:"最近使用优先"}),n.jsx("option",{value:"expiry",children:"最早到期优先"})]}),[["all",`全部 ${d.length}`],["attention","需关注"],["invalid",`无效 ${G}`],["error",`有错误 ${X}`],["refreshable",`可续期 ${ve}`]].map(([V,_])=>n.jsx("button",{type:"button",className:Se===V?"selected":"",onClick:()=>ne(Ee=>({...Ee,[O.id]:V})),children:_},V))]}),n.jsxs("div",{className:"metrics-grid",children:[n.jsx(ul,{label:"账号总数",value:d.length}),n.jsx(ul,{label:"可用账号",value:x}),n.jsx(ul,{label:"无效账号",value:G}),n.jsx(ul,{label:"未验证账号",value:se})]}),n.jsx("div",{className:"drawing-channel-models",children:be(O.models).length?be(O.models).map(V=>n.jsx("span",{children:V},V)):n.jsx("span",{children:"未绑定绘图模型"})}),d.length>0&&n.jsxs("div",{className:"account-pool-list",children:[tl.map(V=>n.jsxs("div",{className:"account-pool-row",children:[n.jsxs("div",{className:"account-pool-main",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"account-pool-title",children:[n.jsx("strong",{title:V.email||V.name||V.accountId||V.id,children:V.email||V.name||V.accountId||V.id}),n.jsx("span",{className:`source-tag source-tag-${V.source==="web-login"?"web":"manual"}`,children:V.source==="web-login"?"网页登录":V.source==="web-oauth"?"网页 OAuth":V.source==="oauth"?"Codex OAuth":V.source==="antigravity"||V.source==="agy"||V.source==="google-antigravity"?"Antigravity":"导入"})]}),n.jsx("span",{children:V.lastError?`${dm(V.lastErrorCode)}${dm(V.lastErrorCode)?" · ":""}${V.lastError}`:V.lastCheckedAt?`上次检测 ${el(V.lastCheckedAt)}`:"未检测"}),n.jsxs("span",{children:[V.credentialMode==="refreshable"?"可自动续期":V.credentialMode==="browser-session"?"依赖网页会话":"仅 access token",V.expiresAt?` · 到期 ${el(V.expiresAt)}`:""]}),n.jsxs("span",{children:["套餐 ",ep(V.planType)]}),V.lastUsedAt&&n.jsxs("span",{children:["最近调用 ",el(V.lastUsedAt)," · ",V.requestCount||0," 次"]})]}),n.jsx(Up,{limits:V.quotaLimits})]}),n.jsxs("div",{className:"account-pool-meta",children:[n.jsx(Dt,{tone:V.status==="healthy"?"healthy":V.status==="invalid"?"disabled":"standby",children:V.status==="healthy"?"可用":V.status==="invalid"?"无效":"未验证"}),n.jsx("button",{type:"button",className:"secondary-button compact-button",disabled:R!=="",onClick:()=>J(O.id,!1,V.id),children:R===`check-account:${V.id}`?"检测中":"检测"}),n.jsx("button",{type:"button",className:"danger-button compact-button",disabled:R!=="",onClick:()=>Q(O,V),children:R===`delete-account:${V.id}`?"删除中":"删除"})]})]},V.id)),I.length===0&&n.jsx(Lt,{text:"没有匹配的账号"}),We.length>ue&&n.jsxs("div",{className:"account-pool-more",children:[n.jsx("span",{className:"muted-inline",children:cl?`已显示全部 ${We.length} 个账号`:`已显示 ${tl.length} 个,还有 ${kt} 个`}),n.jsxs("div",{className:"account-pool-more-actions",children:[!cl&&n.jsxs("button",{type:"button",className:"secondary-button compact-button",onClick:()=>ee(V=>({...V,[O.id]:Math.min(We.length,Pe+Z)})),children:["再显示 ",Math.min(Z,kt)," 个"]}),!cl&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>ee(V=>({...V,[O.id]:We.length})),children:"全部显示"}),Pe>ue&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>ee(V=>({...V,[O.id]:ue})),children:"收起"})]})]})]})]},O.id)}),y.length===0&&n.jsx(Lt,{text:"暂无绘图渠道,先新增一个 OpenAI 账号池渠道"})]}),ge&&n.jsx(Dp,{channelId:ge,onStart:$,onComplete:C,onClose:()=>F("")}),Ae&&n.jsx(Ep,{busy:R!=="",onAuthSession:()=>{D(Ae),Te("")},onAntigravity:()=>{fe(Ae),Te("")},onImport:async O=>{await re(Ae,O),Te("")},onClose:()=>Te("")}),me&&n.jsx(zp,{onImport:async O=>{await re(me,new File([JSON.stringify(Mp(O))],"authsession.json",{type:"application/json"}))},onClose:()=>D("")}),ae&&n.jsx(_p,{onImport:async O=>{await re(ae,new File([JSON.stringify(Op(O))],"antigravity.json",{type:"application/json"}))},onClose:()=>fe("")})]})}function Ep({busy:c,onAuthSession:m,onAntigravity:h,onImport:r,onClose:A}){return n.jsx("div",{className:"modal-backdrop",onClick:A,children:n.jsxs("div",{className:"modal-card account-add-modal",onClick:E=>E.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"添加账号"}),n.jsx("span",{children:"选择一种账号接入方式"})]}),n.jsx("button",{type:"button",className:"icon-button",onClick:A,children:"×"})]}),n.jsxs("div",{className:"account-add-options",children:[n.jsxs("button",{type:"button",className:"account-add-option recommended",onClick:m,disabled:c,children:[n.jsx("span",{className:"account-add-icon",children:"A"}),n.jsx("strong",{children:"导入网页会话"}),n.jsx("small",{children:"粘贴完整 authsession JSON,保留 sessionToken"})]}),n.jsxs("button",{type:"button",className:"account-add-option",onClick:h,disabled:c,children:[n.jsx("span",{className:"account-add-icon",children:"G"}),n.jsx("strong",{children:"导入 Antigravity"}),n.jsx("small",{children:"粘贴 Google OAuth JSON 或 refresh token"})]}),n.jsxs("label",{className:`account-add-option${c?" disabled":""}`,children:[n.jsx("span",{className:"account-add-icon",children:"J"}),n.jsx("strong",{children:c?"导入中":"导入 JSON / ZIP / TXT"}),n.jsx("small",{children:"批量导入已有账号文件"}),n.jsx("input",{type:"file",accept:"application/json,application/zip,text/plain,.json,.zip,.txt",disabled:c,onChange:E=>{const L=E.target.files?.[0];L&&r(L),E.target.value=""}})]})]}),n.jsx("div",{className:"modal-actions",children:n.jsx("button",{type:"button",className:"secondary-button",onClick:A,children:"取消"})})]})})}function Mp(c){const m=c.trim(),h=m.match(/(?:^|[;\s])(__Secure-(?:next-auth|authjs)\.session-token)=([^;\s]+)/);if(h)return{sessionToken:h[2],source:"web-login"};try{const r=JSON.parse(m),A=r.tokens&&typeof r.tokens=="object"?r.tokens:{},E=R=>typeof r[R]=="string"?r[R]:typeof A[R]=="string"?A[R]:"",L=E("accessToken")||E("access_token"),$=E("refreshToken")||E("refresh_token"),C=E("sessionToken")||E("session_token"),y=r.user&&typeof r.user=="object"?r.user:{};if(L||$||C)return{accessToken:L||void 0,refreshToken:$||void 0,sessionToken:C||void 0,email:typeof y.email=="string"?y.email:void 0,name:typeof y.name=="string"?y.name:void 0,source:"web-login"}}catch{}return{sessionToken:m,source:"web-login"}}function zp({onImport:c,onClose:m}){const[h,r]=g.useState(""),[A,E]=g.useState(!1),[L,$]=g.useState(""),[C,y]=g.useState("");async function R(){if(!h.trim()){$("请粘贴 authsession");return}E(!0),$(""),y("");try{await c(h.trim()),r(""),y("已导入,继续粘贴下一条即可")}catch(z){$(z instanceof Error?z.message:"导入失败")}finally{E(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:m,children:n.jsxs("div",{className:"modal-card",onClick:z=>z.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"添加网页会话"}),n.jsx("button",{type:"button",className:"icon-button",onClick:m,children:"×"})]}),n.jsxs("p",{className:"muted-inline",children:["可直接粘贴 chatgpt.com/api/auth/session 的完整 JSON;也支持浏览器 ",n.jsx("code",{children:"__Secure-next-auth.session-token"})," 的值或完整 Cookie 字符串。"]}),n.jsxs("label",{className:"authsession-field",children:[n.jsx("span",{children:"authsession"}),n.jsx("textarea",{autoFocus:!0,value:h,onChange:z=>r(z.target.value),placeholder:"eyJhbGci..."})]}),L&&n.jsx("div",{className:"form-error",children:L}),C&&n.jsx("div",{className:"form-success",children:C}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:m,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:A,onClick:R,children:A?"导入中":"导入账号"})]})]})})}function Op(c){const m=c.trim();try{const h=JSON.parse(m),r=h.tokens&&typeof h.tokens=="object"?h.tokens:{},A=(...y)=>{for(const R of y){if(typeof h[R]=="string"&&h[R])return h[R];if(typeof r[R]=="string"&&r[R])return r[R]}return""},E=A("access_token","accessToken"),L=A("refresh_token","refreshToken"),$=A("email"),C=A("expired","expires_at","expiresAt","expiry");if(E||L)return{accessToken:E||void 0,refreshToken:L||void 0,email:$||void 0,expired:C||void 0,source:"antigravity"}}catch{}return{refreshToken:m,source:"antigravity"}}function _p({onImport:c,onClose:m}){const[h,r]=g.useState(""),[A,E]=g.useState(!1),[L,$]=g.useState(""),[C,y]=g.useState("");async function R(){if(!h.trim()){$("请粘贴 Antigravity OAuth JSON 或 refresh token");return}E(!0),$(""),y("");try{await c(h.trim()),r(""),y("已导入,继续粘贴下一条即可")}catch(z){$(z instanceof Error?z.message:"导入失败")}finally{E(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:m,children:n.jsxs("div",{className:"modal-card",onClick:z=>z.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"导入 Antigravity 账号"}),n.jsx("button",{type:"button",className:"icon-button",onClick:m,children:"×"})]}),n.jsxs("p",{className:"muted-inline",children:["粘贴 Antigravity 的 Google OAuth 凭证 JSON(含 ",n.jsx("code",{children:"access_token"})," / ",n.jsx("code",{children:"refresh_token"}),"),或直接粘贴 refresh token。导入后会自动刷新并加入账号池。"]}),n.jsxs("label",{className:"authsession-field",children:[n.jsx("span",{children:"OAuth JSON / refresh token"}),n.jsx("textarea",{autoFocus:!0,value:h,onChange:z=>r(z.target.value),placeholder:'{"access_token":"ya29...","refresh_token":"1//..."}'})]}),L&&n.jsx("div",{className:"form-error",children:L}),C&&n.jsx("div",{className:"form-success",children:C}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:m,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:A,onClick:R,children:A?"导入中":"导入账号"})]})]})})}function Dp({channelId:c,onStart:m,onComplete:h,onClose:r}){const[A,E]=g.useState(""),[L,$]=g.useState(""),[C,y]=g.useState(""),[R,z]=g.useState(!1),[P,ee]=g.useState("");async function de(){z(!0),ee("");try{const le=await m(c);E(le.authorizeUrl),$(le.state),window.open(le.authorizeUrl,"_blank","noopener")}catch(le){ee(le instanceof Error?le.message:"发起授权失败")}finally{z(!1)}}async function ne(){if(!C.trim()){ee("请粘贴授权完成后浏览器跳转的回调地址");return}z(!0),ee("");try{await h(c,{callbackUrl:C.trim(),state:L}),r()}catch(le){ee(le instanceof Error?le.message:"完成授权失败")}finally{z(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:r,children:n.jsxs("div",{className:"modal-card",onClick:le=>le.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"OAuth 授权添加网页账号"}),n.jsx("button",{type:"button",className:"icon-button",onClick:r,children:"×"})]}),n.jsx("p",{className:"muted-inline",children:"使用 ChatGPT 网页兼容的 OAuth 客户端获取 refresh_token,只调用网页 backend-api,不会走 Codex 接口。"}),n.jsxs("ol",{className:"oauth-steps",children:[n.jsxs("li",{children:[n.jsx("button",{type:"button",className:"primary-button",onClick:de,disabled:R,children:A?"重新生成授权链接":"① 生成授权链接并打开"}),A&&n.jsxs("div",{className:"oauth-link",children:[n.jsx("input",{readOnly:!0,value:A,onFocus:le=>le.target.select()}),n.jsx("span",{className:"muted-inline",children:"若未自动打开,复制到浏览器手动访问,用要添加的 ChatGPT 账号登录授权。"})]})]}),n.jsxs("li",{children:[n.jsx("label",{children:"② 粘贴授权后浏览器跳转的完整回调地址"}),n.jsx("input",{value:C,placeholder:"https://platform.openai.com/auth/callback?code=...&state=...",onChange:le=>y(le.target.value),disabled:!A||R})]})]}),P&&n.jsx("p",{className:"form-error",children:P}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:r,disabled:R,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",onClick:ne,disabled:!A||R,children:R?"处理中":"完成授权"})]})]})})}function Up({limits:c}){const m=be(c).filter(h=>h.label||h.name).slice(0,3);return m.length?n.jsx("div",{className:"quota-bars",children:m.map(h=>{const r=Rp(h);return n.jsxs("div",{className:"quota-bar",children:[n.jsxs("div",{className:"quota-bar-label",children:[n.jsx("strong",{children:h.label||h.name}),n.jsx("span",{children:wp(h,r)})]}),n.jsx("div",{className:"quota-bar-track",children:n.jsx("span",{style:{width:`${r}%`}})})]},`${h.label||h.name}-${h.resetAt||""}`)})}):null}function Rp(c){return typeof c.percentRemaining=="number"&&Number.isFinite(c.percentRemaining)?Math.max(0,Math.min(100,c.percentRemaining)):typeof c.remaining=="number"&&typeof c.limit=="number"&&c.limit>0?Math.max(0,Math.min(100,c.remaining/c.limit*100)):typeof c.used=="number"&&typeof c.limit=="number"&&c.limit>0?Math.max(0,Math.min(100,(c.limit-c.used)/c.limit*100)):0}function wp(c,m){const h=c.resetAt?` · ${el(c.resetAt)}`:"";return typeof c.remaining=="number"?`${Math.round(m)}% 剩余${h}`:`${Math.round(m)}%${h}`}function Hp(c){const m=be(c.models).join(" ").toLowerCase(),h=["对话"];c.streamMode!=="disabled"&&h.push("流式"),/(image|dall-e|gpt-image)/.test(m)&&h.push("图片"),(c.openaiAccountCount??c.openaiAccounts?.length??0)>0&&h.push("账号池");const r=c.upstreamKeyCount??0;return r>1&&h.push(`${r} Key 轮询`),h}function Bp(c){if(c.status==="invalid"||c.credentialMode==="browser-session")return!0;if(!c.expiresAt)return!1;const m=new Date(c.expiresAt).getTime();return Number.isFinite(m)&&m-Date.now()<=1440*60*1e3}function qp({channels:c,groups:m,onUpdate:h,onCreate:r,onImport:A,onDelete:E,onSyncModels:L,onCheck:$}){const C=Ta("openai"),[y,R]=g.useState(!1),[z,P]=g.useState(C.provider),[ee,de]=g.useState(C.name),[ne,le]=g.useState(C.baseUrl),[ie,xe]=g.useState(C.models.join(", ")),[Y,ge]=g.useState(""),[F,me]=g.useState(""),[D,ae]=g.useState(!1),[fe,Ae]=g.useState(!1);function Te(Z){const re=Ta(Z);P(re.provider),de(re.name),le(re.baseUrl),xe(re.models.join(", ")),me("")}async function ue(Z){Z.preventDefault(),ae(!0),me("");try{await r({name:ee.trim()||Ta(z).name,provider:z,baseUrl:ne.trim(),...jm(Y),models:Ic(ie),streamMode:"auto"}),R(!1),ge(""),Te(z)}catch(re){me(re instanceof Error?re.message:"渠道创建失败")}finally{ae(!1)}}return n.jsxs(nt,{title:"渠道",children:[n.jsxs("div",{className:"channel-page-intro",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"管理上游服务"}),n.jsx("span",{children:"每个渠道对应一个 API 上游。先添加渠道,再检测连通性并同步可用模型。"})]}),n.jsxs("div",{className:"channel-page-summary",children:[n.jsxs("span",{children:[n.jsx("b",{children:c.length})," 个渠道"]}),n.jsxs("span",{children:[n.jsx("b",{children:c.filter(Z=>Z.status!=="disabled").length})," 个已启用"]})]})]}),n.jsxs("div",{className:"panel-toolbar channel-toolbar",children:[n.jsx("span",{className:"muted-inline",children:"列表显示当前状态;点击任一渠道可修改连接、模型和计费设置。"}),n.jsx("button",{className:"primary-button",onClick:()=>R(Z=>!Z),children:y?"取消新增":"+ 新增渠道"})]}),y&&n.jsxs("form",{className:"channel-card channel-create-form",onSubmit:ue,children:[n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"选择渠道类型"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:Ta(z).label}),n.jsx("small",{children:"选择后自动填入建议配置"})]}),n.jsx("div",{role:"listbox","aria-label":"选择渠道类型",children:Fc.map(Z=>n.jsxs("button",{type:"button",className:z===Z.provider?"selected":"",onClick:re=>{Te(Z.provider),re.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:Z.label}),n.jsx("span",{children:"使用推荐的名称和地址"})]},Z.provider))})]})]}),n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"渠道名称"}),n.jsx("input",{value:ee,onChange:Z=>de(Z.target.value),placeholder:"例如 OpenAI 主线路"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"供应商"}),n.jsx("input",{value:il(z),readOnly:!0})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"Base URL"}),n.jsx("input",{value:ne,onChange:Z=>le(Z.target.value),placeholder:"https://provider.example/v1"})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"上游 Key"}),n.jsx("textarea",{className:"channel-key-input",value:Y,onChange:Z=>ge(Z.target.value),placeholder:z==="codex"?"账号池导入后使用":z==="cpa"?"填写 CPA 的 API key,多个每行一个":"每行一个 Key;填多个会自动轮询分发",autoComplete:"off",rows:3})]}),n.jsxs("div",{className:"channel-form-wide channel-model-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"模型"}),n.jsx("button",{type:"button",className:"model-pull-button",onClick:()=>{if(z!=="codex"&&!ne.trim()){me("请先填写 Base URL 再获取模型");return}me(""),Ae(!0)},children:"从上游获取模型"})]}),n.jsx("textarea",{value:ie,onChange:Z=>xe(Z.target.value),placeholder:"多个模型用逗号分隔,或点上方『从上游获取模型』拉取后多选"})]})]}),n.jsxs("div",{className:"channel-card-actions",children:[n.jsx("span",{className:"model-create-message",role:"status",children:F}),n.jsx("button",{className:"secondary-button",type:"button",onClick:()=>Te(z),disabled:D,children:"填入模板"}),n.jsx("button",{className:"primary-button",type:"submit",disabled:D,children:D?"创建中":"创建渠道"})]})]}),y&&fe&&n.jsx(Sm,{subtitle:`${ee.trim()||Ta(z).name} · 勾选需要接入的模型`,current:Ic(ie),loadModels:async()=>{const Z=await pe("/api/channel-model-preview",{method:"POST",body:JSON.stringify({provider:z,baseUrl:ne.trim(),upstreamApiKey:Y})});return be(Z.models)},onConfirm:async Z=>{xe(Z.join(", "))},onClose:()=>Ae(!1)}),n.jsxs("div",{className:"channels-stack",children:[c.map(Z=>n.jsx(Gp,{channel:Z,groups:m,onUpdate:h,onImport:A,onDelete:E,onSyncModels:L,onCheck:$},Z.id)),c.length===0&&n.jsx(Lt,{text:"暂无渠道,先在后端添加渠道接口或导入配置"})]})]})}function Gp({channel:c,groups:m,onUpdate:h,onImport:r,onDelete:A,onSyncModels:E,onCheck:L}){const[$,C]=g.useState(c.name),[y,R]=g.useState(c.provider),[z,P]=g.useState(c.streamMode||"auto"),[ee,de]=g.useState(c.baseUrl),[ne,le]=g.useState(be(c.allowedGroupIds)),[ie,xe]=g.useState(be(c.models).join(", ")),[Y,ge]=g.useState("saved"),[F,me]=g.useState(String(c.inputPricePer1K||0)),[D,ae]=g.useState(String(c.outputPricePer1K||0)),[fe,Ae]=g.useState(!!c.webEndpoint),[Te,ue]=g.useState(""),[Z,re]=g.useState(""),[J,T]=g.useState(!1),k=c.openaiAccountCount??c.openaiAccounts?.length??0,B=be(c.models).length,Q=Hp(c),O=c.status==="disabled",d={saved:"已保存",template:"模板",manual:"手动",synced:"上游同步"}[Y],x=Ni.find(I=>I.value===z)||Ni[0],G={auto:"自动处理(推荐)",real:"强制流式",fake:"兼容流式",disabled:"关闭流式"};g.useEffect(()=>{C(c.name),R(c.provider),P(c.streamMode||"auto"),de(c.baseUrl),le(be(c.allowedGroupIds)),xe(be(c.models).join(", ")),ge("saved"),me(String(c.inputPricePer1K||0)),ae(String(c.outputPricePer1K||0)),Ae(!!c.webEndpoint),ue("")},[c.id,c.name,c.provider,c.streamMode,c.baseUrl,c.models,c.inputPricePer1K,c.outputPricePer1K,c.webEndpoint]);async function X(){const I=se();re("save");try{await h(c.id,I),ue("")}finally{re("")}}function se(){const I=Ei(y),Ke=!/^https?:\/\//i.test(ee.trim())&&I?I:ee,We={name:$.trim()||c.name,provider:y,streamMode:z,baseUrl:Ke,inputPricePer1K:Number(F)||0,outputPricePer1K:Number(D)||0,webEndpoint:fe,models:ie.split(",").map(Pe=>Pe.trim()).filter(Boolean),allowedGroupIds:ne};return Object.assign(We,jm(Te)),We}async function ve(){const I=c.status==="disabled"?"healthy":"disabled";re("status");try{await h(c.id,{...se(),status:I}),ue("")}finally{re("")}}async function N(){re("sync");try{await h(c.id,se()),ue(""),T(!0)}finally{re("")}}function Ne(){const I=Ta(y);xe(I.models.join(", ")),ge("template"),I.baseUrl&&!/^https?:\/\//i.test(ee.trim())&&de(I.baseUrl)}async function Se(){re("check");try{await X(),await L(c.id)}finally{re("")}}async function bt(I){re("import");try{await r(c.id,I)}finally{re("")}}return n.jsxs(n.Fragment,{children:[n.jsxs("details",{className:"channel-card channel-card-collapsible",children:[n.jsxs("summary",{className:"channel-card-head channel-list-row",children:[n.jsxs("div",{className:"channel-identity",children:[n.jsx("strong",{children:c.name}),n.jsx("span",{children:il(y)}),n.jsx("small",{children:c.baseUrl||"尚未配置上游地址"}),n.jsx("div",{className:"channel-capability-tags",children:Q.map(I=>n.jsx("span",{children:I},I))})]}),n.jsxs("div",{className:"channel-list-meta",children:[n.jsxs("span",{children:[n.jsx("b",{children:B})," 个模型"]}),k>0&&n.jsxs("span",{children:[n.jsx("b",{children:k})," 个账号"]})]}),n.jsxs("div",{className:"channel-check-result",children:[n.jsx("span",{children:"连通性"}),n.jsx("b",{className:c.lastError?"is-error":c.lastCheckedAt?"is-ok":"",children:c.lastError?"检测失败":c.lastCheckedAt?`已检测 ${el(c.lastCheckedAt)}`:"尚未检测"})]}),n.jsxs("div",{className:"channel-list-status",children:[n.jsx(Dt,{tone:c.status,children:O?"已停用":_t(c.status)}),n.jsx("span",{className:"channel-expand-hint",children:"配置"})]})]}),n.jsxs("div",{className:"channel-editor-controls",children:[n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"供应商"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:il(y)}),n.jsx("small",{children:"修改上游协议类型"})]}),n.jsx("div",{role:"listbox","aria-label":"供应商",children:eo.map(I=>n.jsxs("button",{type:"button",className:y===I.value?"selected":"",onClick:Ke=>{R(I.value);const We=Ei(I.value);We&&!/^https?:\/\//i.test(ee.trim())&&de(We),Ke.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:I.label}),n.jsx("span",{children:I.value==="compatible"?"适用于兼容 OpenAI 格式的服务":"选择对应的上游协议"})]},I.value))})]})]}),n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"响应方式"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:G[x.value]}),n.jsx("small",{children:x.description})]}),n.jsx("div",{role:"listbox","aria-label":"响应方式",children:Ni.map(I=>n.jsxs("button",{type:"button",className:z===I.value?"selected":"",onClick:Ke=>{P(I.value),Ke.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:G[I.value]}),n.jsx("span",{children:I.description})]},I.value))})]})]})]}),(y==="codex"||k>0)&&n.jsxs("div",{className:"setting",children:[n.jsxs("div",{children:[n.jsx("span",{children:"网页对话接口"}),n.jsx("small",{children:"开启后走 ChatGPT 网页对话接口,把 Plus 订阅账号包装成 API"})]}),n.jsx("div",{className:"setting-value",children:n.jsx("button",{type:"button",className:fe?"ios-switch is-on":"ios-switch","aria-label":fe?"关闭网页对话接口":"开启网页对话接口","aria-pressed":fe,onClick:()=>Ae(I=>!I),children:n.jsx("span",{})})})]}),n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"渠道名称"}),n.jsx("input",{value:$,onChange:I=>C(I.target.value),placeholder:"例如 Gemini 主线路"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"供应商"}),n.jsx("input",{value:il(y),readOnly:!0})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"Base URL"}),n.jsx("input",{value:ee,onChange:I=>de(I.target.value),placeholder:"https://provider.example/v1"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"优先级"}),n.jsx("input",{value:c.priority,readOnly:!0})]}),n.jsxs("div",{className:"channel-form-wide channel-model-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"模型"}),n.jsxs("small",{children:["来源:",d]})]}),n.jsx("textarea",{value:ie,onChange:I=>{xe(I.target.value),ge("manual")},placeholder:"优先拉取上游模型,也可以手动补充,多个用逗号分隔"}),n.jsxs("div",{className:"channel-model-actions",children:[n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:Ne,disabled:Z!=="",children:"填入模板"}),n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:N,disabled:Z!=="",children:Z==="sync"?"拉取中":"获取上游模型"})]})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsxs("span",{children:["上游 Key",(c.upstreamKeyCount??0)>0?` (已配置 ${c.upstreamKeyCount} 个)`:c.upstreamKeySet?" (已配置)":""]}),n.jsx("textarea",{className:"channel-key-input",value:Te,onChange:I=>ue(I.target.value),placeholder:y==="codex"?"Codex 账号池不需要上游 Key":y==="cpa"?"填写 CPA 的 API key,多个每行一个":"每行一个 Key;填多个会自动轮询分发;留空不修改",autoComplete:"off",rows:3})]}),n.jsxs("label",{children:[n.jsx("span",{children:"输入单价 / 1K Token"}),n.jsx("input",{type:"number",min:"0",step:"0.0001",value:F,onChange:I=>me(I.target.value)})]}),n.jsxs("label",{children:[n.jsx("span",{children:"输出单价 / 1K Token"}),n.jsx("input",{type:"number",min:"0",step:"0.0001",value:D,onChange:I=>ae(I.target.value)})]}),n.jsx("span",{className:"channel-billing-note",children:"定价可先留空;接入是否可用优先看渠道检测和模型同步结果。"})]}),n.jsxs("div",{className:"channel-group-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"可见分组"}),n.jsx("small",{children:ne.length?`已选择 ${ne.length} 个分组`:"全部用户可用"})]}),m.length===0?n.jsx("p",{className:"channel-group-empty",children:"还没有用户分组。去「分组」页创建后,可在这里把渠道限制为只对特定分组开放。"}):n.jsx("div",{className:"channel-group-options",children:m.map(I=>{const Ke=ne.includes(I.id);return n.jsxs("button",{type:"button",className:Ke?"selected":"","aria-pressed":Ke,onClick:()=>le(We=>Ke?We.filter(Pe=>Pe!==I.id):[...We,I.id]),children:[n.jsx("span",{children:I.name}),I.description&&n.jsx("small",{children:I.description})]},I.id)})})]}),n.jsxs("div",{className:"channel-card-actions",children:[n.jsx("button",{className:"secondary-button",onClick:Se,disabled:Z!=="",children:Z==="check"?"检测中":"检测渠道"}),n.jsx("button",{className:"primary-button",onClick:X,disabled:Z!=="",children:Z==="save"?"保存中":"保存"}),n.jsxs("details",{className:"channel-more-actions",children:[n.jsx("summary",{children:"更多操作"}),n.jsxs("div",{children:[n.jsxs("label",{className:"secondary-button",children:[Z==="import"?"导入中":"导入账号 JSON",n.jsx("input",{type:"file",accept:"application/json,application/zip,text/plain,.json,.zip,.txt",disabled:Z!=="",onChange:I=>{const Ke=I.target.files?.[0];Ke&&bt(Ke),I.target.value=""}})]}),n.jsx("button",{className:"secondary-button",onClick:ve,disabled:Z!=="",children:c.status==="disabled"?"启用渠道":"停用渠道"}),n.jsx("button",{className:"danger-button",onClick:()=>A(c.id),disabled:Z!=="",children:"删除渠道"})]})]})]})]}),J&&n.jsx(Sm,{subtitle:`${c.name} · 勾选需要接入的模型`,current:ie.split(",").map(I=>I.trim()).filter(Boolean),loadModels:async()=>{const I=await pe(`/api/channels/${c.id}/upstream-models`,{method:"POST",body:JSON.stringify({})});return be(I.models)},onConfirm:async I=>{await E(c.id,I)},onClose:()=>T(!1)})]})}function Sm({subtitle:c,current:m,loadModels:h,onConfirm:r,onClose:A}){const[E,L]=g.useState(!0),[$,C]=g.useState(""),[y,R]=g.useState([]),[z,P]=g.useState(new Set),[ee,de]=g.useState(""),[ne,le]=g.useState(!1);g.useEffect(()=>{let D=!1;return(async()=>{L(!0),C("");try{const ae=await h();if(D)return;const fe=new Set,Ae=be(ae).map(ue=>ue.trim()).filter(ue=>{if(!ue)return!1;const Z=ue.toLowerCase();return fe.has(Z)?!1:(fe.add(Z),!0)}),Te=new Set(m.map(ue=>ue.toLowerCase()));R(Ae),P(new Set(Ae.filter(ue=>Te.has(ue.toLowerCase()))))}catch(ae){D||C(ae instanceof Error?ae.message:"获取上游模型失败")}finally{D||L(!1)}})(),()=>{D=!0}},[]);const ie=ee.trim().toLowerCase(),xe=ie?y.filter(D=>D.toLowerCase().includes(ie)):y,Y=xe.length>0&&xe.every(D=>z.has(D));function ge(D){P(ae=>{const fe=new Set(ae);return fe.has(D)?fe.delete(D):fe.add(D),fe})}function F(){P(D=>{const ae=new Set(D);return Y?xe.forEach(fe=>ae.delete(fe)):xe.forEach(fe=>ae.add(fe)),ae})}async function me(){const D=new Set(y.map(ue=>ue.toLowerCase())),ae=m.filter(ue=>!D.has(ue.toLowerCase())),fe=y.filter(ue=>z.has(ue)),Ae=new Set,Te=[...ae,...fe].filter(ue=>{const Z=ue.toLowerCase();return Ae.has(Z)?!1:(Ae.add(Z),!0)});le(!0);try{await r(Te),A()}catch{le(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:A,children:n.jsxs("div",{className:"modal-card model-picker-modal",onClick:D=>D.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"选择上游模型"}),n.jsx("span",{children:c})]}),n.jsx("button",{type:"button",className:"icon-button",onClick:A,children:"×"})]}),E?n.jsx("div",{className:"model-picker-status",children:"正在获取上游模型…"}):$?n.jsx("div",{className:"model-picker-status model-picker-error",children:$}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"model-picker-toolbar",children:[n.jsx("input",{className:"model-picker-search",value:ee,onChange:D=>de(D.target.value),placeholder:"搜索模型名称",autoFocus:!0}),n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:F,disabled:xe.length===0,children:Y?"取消全选":"全选"})]}),n.jsxs("div",{className:"model-picker-count",children:["共 ",y.length," 个 · 已选 ",z.size," 个",ie?` · 匹配 ${xe.length} 个`:""]}),n.jsxs("div",{className:"model-picker-list",children:[xe.map(D=>{const ae=z.has(D),fe=m.some(Ae=>Ae.toLowerCase()===D.toLowerCase());return n.jsxs("label",{className:`model-picker-row${ae?" checked":""}`,children:[n.jsx("input",{type:"checkbox",checked:ae,onChange:()=>ge(D)}),n.jsx("span",{className:"model-picker-name",children:D}),fe&&n.jsx("span",{className:"model-picker-tag",children:"已接入"})]},D)}),xe.length===0&&n.jsx("div",{className:"model-picker-status",children:"没有匹配的模型"})]})]}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:A,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:E||!!$||ne,onClick:me,children:ne?"保存中":`导入所选 (${z.size})`})]})]})})}function Yp({logs:c,onCopy:m}){const[h,r]=g.useState(c),[A,E]=g.useState(c.length),[L,$]=g.useState(1),[C,y]=g.useState(""),[R,z]=g.useState("all"),[P,ee]=g.useState(null),[de,ne]=g.useState(!1),[le,ie]=g.useState(!1),xe=25,Y=Math.max(1,Math.ceil(A/xe));g.useEffect(()=>{$(1)},[C,R]),g.useEffect(()=>{L>Y&&$(Y)},[L,Y]),g.useEffect(()=>{const F=new AbortController,me=window.setTimeout(async()=>{ne(!0);try{const D=new URLSearchParams({page:String(L),pageSize:String(xe),status:R,q:C.trim()}),ae=await pe(`/api/logs?${D}`,{signal:F.signal}),fe=be(ae.logs);r(fe),E(ae.total||0),ee(Ae=>Ae&&fe.some(Te=>Te.id===Ae.id)?Ae:null)}catch(D){D instanceof DOMException&&D.name==="AbortError"||(r([]),E(0))}finally{F.signal.aborted||ne(!1)}},C?250:0);return()=>{window.clearTimeout(me),F.abort()}},[L,C,R]);async function ge(F){if(P?.id===F.id){ee(null);return}ee(F),ie(!0);try{const me=await pe(`/api/logs/${encodeURIComponent(F.id)}`);ee(me.log)}catch{ee(F)}finally{ie(!1)}}return n.jsxs(nt,{title:"调用日志",children:[n.jsxs("div",{className:"logs-toolbar",children:[n.jsxs("div",{className:"search-box",children:[n.jsx(Ot,{name:"search"}),n.jsx("input",{value:C,onChange:F=>y(F.target.value),placeholder:"搜索请求 ID、用户、Key、模型、渠道或错误码"})]}),n.jsx("div",{className:"log-status-filter",role:"group","aria-label":"日志状态筛选",children:[{value:"all",label:"全部"},{value:"success",label:"成功"},{value:"failed",label:"失败"}].map(F=>n.jsx("button",{type:"button",className:R===F.value?"selected":"",onClick:()=>z(F.value),children:F.label},F.value))}),n.jsx("span",{className:"muted-inline",children:de?"加载中":`共 ${A} 条`})]}),n.jsxs("div",{className:P?"logs-layout has-detail":"logs-layout",children:[n.jsxs("div",{className:"table",children:[n.jsxs("div",{className:"table-head logs-table",children:[n.jsx("span",{children:"请求"}),n.jsx("span",{children:"模型"}),n.jsx("span",{children:"渠道"}),n.jsx("span",{children:"状态"})]}),h.map(F=>n.jsx("div",{className:"log-entry",children:n.jsxs("div",{className:P?.id===F.id?"table-row logs-table selected":"table-row logs-table",role:"button",tabIndex:0,onClick:()=>ge(F),onKeyDown:me=>{(me.key==="Enter"||me.key===" ")&&ge(F)},children:[n.jsxs("span",{children:[n.jsx("strong",{children:to(F)}),n.jsxs("small",{children:[F.id," · ",el(F.createdAt)," · ",F.latencyMs,"ms"]})]}),n.jsx("span",{children:np(F)}),n.jsx("span",{children:sp(F)}),n.jsx(Dt,{tone:F.status,children:_t(F.status)})]})},F.id)),!de&&h.length===0&&n.jsx(Lt,{text:C||R!=="all"?"没有匹配的日志":"暂无调用日志"})]}),P&&n.jsx(Lp,{log:P,loading:le,onCopy:m})]}),Y>1&&n.jsxs("div",{className:"pagination-bar",children:[n.jsx("button",{className:"secondary-button",disabled:L<=1||de,onClick:()=>$(F=>Math.max(1,F-1)),children:"上一页"}),n.jsxs("span",{children:[L," / ",Y]}),n.jsx("button",{className:"secondary-button",disabled:L>=Y||de,onClick:()=>$(F=>Math.min(Y,F+1)),children:"下一页"})]})]})}function Lp({log:c,loading:m,onCopy:h}){if(!c)return n.jsx("aside",{className:"log-inspector empty-inspector",children:n.jsx("span",{children:"选择一条日志查看详情"})});const r=Number(c.inputTokens||0),A=Number(c.outputTokens||0),E=typeof c.attempts=="number"?Math.max(0,c.attempts):null,L=[["请求 ID",c.id],["状态",_t(c.status)],["时间",ap(c.createdAt)],["用户 ID",c.userId||"未识别"],["API Key",c.apiKeyPrefix?`${c.apiKeyPrefix}***`:"未识别"],["模型",c.model||"未提供"],["渠道",c.channel||"未选择"],["实际账号",c.account||"未记录"],["响应耗时",`${c.latencyMs} ms`],["尝试次数",E===null?"未记录":String(E)],["是否重试",E===null?"未记录":E>1?"是":"否"],["输入 Tokens",ml(r)],["输出 Tokens",ml(A)],["总 Tokens",ml(r+A)],["扣费",c.cost.toFixed(4)],["错误码",c.errorCode||"无"]];return n.jsxs("aside",{className:"log-inspector",children:[n.jsxs("header",{children:[n.jsxs("div",{children:[n.jsx("span",{children:m?"加载中":"日志详情"}),n.jsx("strong",{children:to(c)})]}),n.jsx(Dt,{tone:c.status,children:_t(c.status)})]}),n.jsx("div",{className:"log-detail",children:L.map(([$,C])=>n.jsxs("div",{children:[n.jsx("span",{children:$}),n.jsx("strong",{title:C,children:C})]},$))}),n.jsxs("div",{className:"log-actions",children:[n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>h(c.id,"请求 ID 已复制"),children:"复制请求 ID"}),c.errorCode&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>h(c.errorCode||"","错误码已复制"),children:"复制错误码"})]})]})}function kp({models:c,channels:m,groups:h}){const[r,A]=g.useState(null),[E,L]=g.useState(null),[$,C]=g.useState("username"),[y,R]=g.useState("0"),[z,P]=g.useState(""),[ee,de]=g.useState({enabled:!0,minReward:.1,maxReward:1}),[ne,le]=g.useState({logRetentionDays:30,maxLogs:1e4,maxQuotaEntries:2e4}),[ie,xe]=g.useState(null),[Y,ge]=g.useState(null),[F,me]=g.useState(""),[D,ae]=g.useState(""),[fe,Ae]=g.useState(""),[Te,ue]=g.useState(""),[Z,re]=g.useState(""),[J,T]=g.useState(""),[k,B]=g.useState(""),[Q,O]=g.useState(""),[d,x]=g.useState(""),[G,X]=g.useState(!1),[se,ve]=g.useState("system"),N=c.find(_=>_.recommended&&_.status==="available")?.id||c.find(_=>_.status==="available")?.id||"未配置",Ne=m.filter(_=>_.status!=="disabled").length,Se=[{value:"system",label:"系统",description:"运行概况"},{value:"cli",label:"CLI 接入",description:"一键配置"},{value:"auth",label:"注册",description:"开放方式"},{value:"check-in",label:"签到",description:"奖励范围"},{value:"admin",label:"管理员",description:"账号绑定"},{value:"discord",label:"Discord",description:"登录限制"},{value:"maintenance",label:"维护",description:"日志保留"},{value:"backup",label:"备份",description:"导出恢复"}],bt=Se.find(_=>_.value===se)||Se[0];g.useEffect(()=>{Promise.all([pe("/api/settings/discord"),pe("/api/settings/auth"),pe("/api/settings/check-in"),pe("/api/account/me"),pe("/api/settings/maintenance"),pe("/api/health")]).then(([_,Ee,et,xt,ft,tt])=>{A(Wc(_.discord)),O(be(_.discord.blockedGuildIds).join(` +}`,n.jsx("span",{className:"terminal-caret","aria-hidden":"true"})]})]})]})]})]})]})}function xp({overview:u,channels:m,logs:h,onNavigate:r}){const A=h.filter(E=>E.status!=="success");return n.jsxs("section",{className:"page-stack",children:[n.jsxs("div",{className:"hero-strip",children:[n.jsxs("div",{children:[n.jsx("span",{children:"Live Gateway"}),n.jsxs("strong",{children:["CAPI 网关正在服务 ",u?.activeUsers??"-"," 个活跃用户"]}),n.jsx("p",{children:"请求进入 CAPI 后,会按额度、模型和渠道状态自动选择最合适的上游。"})]}),n.jsxs("div",{className:"live-island",children:[n.jsx("div",{className:"pulse-dot"}),n.jsx("span",{children:"在线"})]})]}),n.jsxs("div",{className:"quick-actions","aria-label":"快捷操作",children:[n.jsx(Si,{icon:"key",label:"创建 Key",onClick:()=>r("keys")}),n.jsx(Si,{icon:"route",label:"配置渠道",onClick:()=>r("channels")}),n.jsx(Si,{icon:"users",label:"调整额度",onClick:()=>r("users")}),n.jsx(Si,{icon:"logs",label:"查看异常",onClick:()=>r("logs")})]}),n.jsxs("div",{className:"metrics-grid",children:[n.jsx(ul,{label:"活跃用户",value:u?ml(u.activeUsers):"-"}),n.jsx(ul,{label:"今日请求",value:u?ml(u.requestsToday):"-"}),n.jsx(ul,{label:"今日输入",value:u?ml(u.todayInputTokens):"-"}),n.jsx(ul,{label:"今日输出",value:u?ml(u.todayOutputTokens):"-"}),n.jsx(ul,{label:"今日扣费",value:u?St(u.todayCost,4):"-"}),n.jsx(ul,{label:"账户余额",value:u?St(u.totalBalance):"-"}),n.jsx(ul,{label:"成功率",value:u?`${u.successRate}%`:"-"})]}),n.jsx(jp,{}),n.jsxs("div",{className:"split-grid",children:[n.jsx(nt,{title:"渠道状态",children:m.length?m.map(E=>n.jsxs("div",{className:"list-row overview-channel-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:E.name}),n.jsx("span",{title:be(E.models).join(", "),children:cp(E.models)})]}),n.jsx(Dt,{tone:E.status,children:_t(E.status)})]},E.id)):n.jsx(Lt,{text:"暂无渠道"})}),n.jsx(nt,{title:"最近请求",children:h.length?h.slice(0,4).map(E=>n.jsxs("div",{className:"list-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:lo(E)}),n.jsxs("span",{children:[E.id," · ",E.errorCode||el(E.createdAt)]})]}),n.jsx(Dt,{tone:E.status,children:_t(E.status)})]},E.id)):n.jsx(Lt,{text:A.length?"暂无最近请求":"暂无请求"})})]})]})}function Si({icon:u,label:m,onClick:h}){return n.jsxs("button",{className:"quick-action",onClick:h,children:[n.jsx(Ot,{name:u}),n.jsx("span",{children:m})]})}function jp(){const u=[{label:"认证",detail:"校验 API Key"},{label:"额度",detail:"检查余额"},{label:"路由",detail:"选择渠道"},{label:"响应",detail:"返回结果"}];return n.jsxs("section",{className:"flow-panel","aria-label":"网关流转",children:[n.jsxs("div",{className:"flow-copy",children:[n.jsx("span",{children:"Request Flow"}),n.jsx("strong",{children:"请求处理流程"})]}),n.jsx("div",{className:"flow-steps",children:u.map((m,h)=>n.jsxs("div",{className:"flow-step",children:[n.jsx("div",{className:"flow-index",children:h+1}),n.jsx("strong",{children:m.label}),n.jsx("span",{children:m.detail})]},m.label))})]})}function Sp({users:u,query:m,selectedUser:h,onQuery:r,onSelect:A,onUpdate:E,onBulkUpdate:L,onCreateKey:$,groups:C,onOpenRegistration:y}){const[z,P]=g.useState(1),[ee,de]=g.useState("all"),[ne,le]=g.useState(new Set),[ie,xe]=g.useState("10"),[Y,ge]=g.useState(""),[F,me]=g.useState(""),[D,ae]=g.useState(!1),[fe,Ae]=g.useState("10"),[Te,ue]=g.useState(""),[Z,re]=g.useState(""),[J,T]=g.useState(!1),k=ee==="all"?u:u.filter(N=>N.status===ee),B=k.filter(N=>N.role!=="admin"),Q=Math.max(1,Math.ceil(k.length/25)),O=Math.min(z,Q),d=k.slice((O-1)*25,O*25),x=B.length>0&&B.every(N=>ne.has(N.id));g.useEffect(()=>{P(1)},[m,ee]),g.useEffect(()=>{const N=new Set(u.map(Ne=>Ne.id));le(Ne=>new Set([...Ne].filter(Se=>N.has(Se))))},[u]),g.useEffect(()=>{Ae("10"),ue(""),re("")},[h?.user.id]);function G(N){le(Ne=>{const Se=new Set(Ne);return Se.has(N)?Se.delete(N):Se.add(N),Se})}function X(){le(N=>{const Ne=new Set(N);return x?B.forEach(Se=>Ne.delete(Se.id)):B.forEach(Se=>Ne.add(Se.id)),Ne})}async function se(N,Ne){if(ne.size!==0){ae(!0);try{await L([...ne],N,Ne),le(new Set),ge("")}finally{ae(!1)}}}async function ve(N){if(!h)return;const Ne=Math.abs(Number(fe));if(!Number.isFinite(Ne)||Ne<=0){re("请输入大于 0 的金额");return}T(!0),re("");try{await L([h.user.id],"adjust_balance",{amount:Number((Ne*N).toFixed(4)),reason:Te.trim()||(N>0?"管理员增加额度":"管理员扣减额度")}),re(N>0?"额度已增加":"额度已扣减"),ue("")}catch(Se){re(Se instanceof Error?Se.message:"额度调整失败")}finally{T(!1)}}return n.jsxs("section",{className:"users-layout",children:[n.jsxs(nt,{title:"用户管理",children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsxs("div",{className:"search-box",children:[n.jsx(Ot,{name:"search"}),n.jsx("input",{value:m,onChange:N=>r(N.target.value),placeholder:"搜索 ID、姓名或邮箱"})]}),n.jsx("button",{className:"icon-button",title:"开放注册",onClick:y,children:n.jsx(Ot,{name:"plus"})})]}),n.jsxs("div",{className:"user-summary-strip",children:[n.jsxs("span",{children:[n.jsx("strong",{children:u.length})," 匹配用户"]}),n.jsxs("span",{children:[n.jsx("strong",{children:u.filter(N=>N.status==="active").length})," 正常"]}),n.jsxs("span",{children:[n.jsx("strong",{children:u.filter(N=>N.status==="disabled").length})," 禁用"]}),n.jsxs("span",{children:[n.jsx("strong",{children:u.reduce((N,Ne)=>N+Ne.requestsToday,0)})," 今日请求"]})]}),n.jsx("div",{className:"user-filter-row",role:"group","aria-label":"用户状态筛选",children:[{value:"all",label:"全部"},{value:"active",label:"正常"},{value:"limited",label:"受限"},{value:"disabled",label:"禁用"}].map(N=>n.jsx("button",{type:"button",className:ee===N.value?"selected":"",onClick:()=>de(N.value),children:N.label},N.value))}),n.jsx("button",{type:"button",className:"secondary-button mobile-bulk-select",onClick:X,children:x?"取消全选":`全选结果(${B.length})`}),ne.size>0&&n.jsxs("div",{className:"bulk-action-bar",children:[n.jsxs("strong",{children:["已选 ",ne.size," 人"]}),n.jsx("input",{type:"number",step:"0.01",value:ie,onChange:N=>xe(N.target.value),"aria-label":"额度调整值"}),n.jsx("input",{value:Y,onChange:N=>ge(N.target.value),placeholder:"原因,例如:活动赠送","aria-label":"调整原因"}),n.jsx("button",{type:"button",className:"secondary-button",disabled:D||!Number(ie),onClick:()=>se("adjust_balance",{amount:Number(ie),reason:Y}),children:"调整额度"}),n.jsx("button",{type:"button",className:"secondary-button",disabled:D,onClick:()=>se("set_status",{value:"active"}),children:"启用"}),n.jsx("button",{type:"button",className:"danger-button",disabled:D,onClick:()=>se("set_status",{value:"disabled"}),children:"禁用"}),n.jsxs("select",{className:"bulk-group-select",value:F,disabled:D,"aria-label":"批量设置分组",onChange:N=>me(N.target.value),children:[n.jsx("option",{value:"",children:"未分组"}),C.map(N=>n.jsx("option",{value:N.id,children:N.name},N.id))]}),n.jsx("button",{type:"button",className:"secondary-button",disabled:D,onClick:()=>se("set_group",{value:F}),children:"设为分组"})]}),n.jsxs("div",{className:"table",children:[n.jsxs("div",{className:"table-head users-table",children:[n.jsx("input",{type:"checkbox",checked:x,onChange:X,"aria-label":"选择当前筛选结果"}),n.jsx("span",{children:"用户"}),n.jsx("span",{children:"状态"}),n.jsx("span",{children:"余额"}),n.jsx("span",{children:"今日"})]}),d.map(N=>n.jsxs("div",{className:h?.user.id===N.id?"table-row users-table selected":"table-row users-table",role:"button",tabIndex:0,onClick:()=>A(N.id),onKeyDown:Ne=>{(Ne.key==="Enter"||Ne.key===" ")&&A(N.id)},children:[n.jsx("input",{type:"checkbox",checked:ne.has(N.id),disabled:N.role==="admin",onChange:()=>G(N.id),onClick:Ne=>Ne.stopPropagation(),"aria-label":N.role==="admin"?`${N.name} 是管理员,不参与批量操作`:`选择 ${N.name}`}),n.jsxs("span",{children:[n.jsx("strong",{children:N.name}),n.jsxs("small",{children:[N.id," · ",N.email||"未绑定邮箱"]})]}),n.jsx(Dt,{tone:N.status,children:_t(N.status)}),n.jsx("span",{children:St(N.balance)}),n.jsx("span",{children:N.requestsToday})]},N.id)),k.length===0&&n.jsx(Lt,{text:"暂无匹配用户"})]}),k.length>25&&n.jsxs("div",{className:"pagination-bar",children:[n.jsx("button",{className:"secondary-button",disabled:O<=1,onClick:()=>P(N=>Math.max(1,N-1)),children:"上一页"}),n.jsxs("span",{children:[O," / ",Q]}),n.jsx("button",{className:"secondary-button",disabled:O>=Q,onClick:()=>P(N=>Math.min(Q,N+1)),children:"下一页"})]})]}),n.jsx(nt,{title:"用户详情",children:h?n.jsxs("div",{className:"detail-stack",children:[n.jsxs("div",{className:"user-hero",children:[n.jsx("div",{className:"avatar",children:h.user.name.slice(0,1)}),n.jsxs("div",{children:[n.jsx("h2",{children:h.user.name}),n.jsx("p",{children:h.user.email})]}),n.jsx(Dt,{tone:h.user.status,children:_t(h.user.status)})]}),n.jsxs("div",{className:"settings-group",children:[n.jsx(Pt,{label:"角色",value:h.user.role==="admin"?"管理员":"用户"}),n.jsx(Pt,{label:"余额",value:St(h.user.balance)}),n.jsx(Pt,{label:"总请求",value:String(h.user.totalRequests)}),n.jsx(Pt,{label:"最后登录",value:el(h.user.lastLoginAt)}),n.jsx(Pt,{label:"API 调用",value:h.user.status==="disabled"?"关闭":"允许",switchOn:h.user.status!=="disabled"})]}),n.jsxs("div",{className:"group-assign-row",children:[n.jsxs("label",{children:[n.jsx("span",{children:"所属分组"}),n.jsxs("select",{value:h.user.groupId||"",onChange:N=>E(h.user.id,{groupId:N.target.value}),children:[n.jsx("option",{value:"",children:"未分组"}),C.map(N=>n.jsx("option",{value:N.id,children:N.name},N.id))]})]}),n.jsx("small",{children:"分组决定该用户可路由到哪些渠道;未分组用户只能使用未限制分组的渠道。"})]}),n.jsxs("div",{className:"balance-adjuster",children:[n.jsxs("div",{className:"balance-adjuster-title",children:[n.jsx("strong",{children:"调整余额"}),n.jsxs("span",{children:["当前 ",St(h.user.balance)]})]}),n.jsxs("div",{className:"balance-adjuster-fields",children:[n.jsxs("label",{children:[n.jsx("span",{children:"金额"}),n.jsx("input",{type:"number",min:"0.0001",step:"0.01",value:fe,onChange:N=>Ae(N.target.value)})]}),n.jsxs("label",{children:[n.jsx("span",{children:"备注"}),n.jsx("input",{value:Te,onChange:N=>ue(N.target.value),placeholder:"可选,会记录到流水"})]})]}),n.jsxs("div",{className:"balance-adjuster-actions",children:[n.jsx("button",{className:"secondary-button",disabled:J,onClick:()=>ve(1),children:"增加"}),n.jsx("button",{className:"danger-button",disabled:J,onClick:()=>ve(-1),children:"扣减"}),n.jsx("span",{role:"status",children:Z})]})]}),n.jsxs("div",{className:"action-row",children:[n.jsx("button",{className:"secondary-button",onClick:()=>$(h.user.id),children:"创建 Key"}),n.jsx("button",{className:"secondary-button",disabled:h.user.role==="admin",onClick:()=>E(h.user.id,{status:h.user.status==="disabled"?"active":"disabled"}),children:h.user.role==="admin"?"管理员保护":h.user.status==="disabled"?"解封":"禁用"})]}),n.jsxs("div",{children:[n.jsx("h3",{children:"API Key"}),h.apiKeys.map(N=>n.jsxs("div",{className:"list-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:N.name}),n.jsxs("span",{children:[N.prefix,"*** · ",N.requestCount," 次"]})]}),n.jsx(Dt,{tone:N.status,children:_t(N.status)})]},N.id)),h.apiKeys.length===0&&n.jsx(Lt,{text:"暂无 API Key"})]})]}):n.jsx(Lt,{text:"请选择一个用户"})})]})}function Np({selectedUser:u,onCreateKey:m,onUpdateKey:h,onDeleteKey:r}){return n.jsx(nt,{title:"密钥管理",children:u?n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsxs("span",{className:"muted-inline",children:[u.user.name," · 完整 Key 只在创建时显示,丢失请重新创建"]}),n.jsx("button",{className:"primary-button",onClick:()=>m(u.user.id),children:"创建 Key"})]}),u.apiKeys.length?u.apiKeys.map(A=>n.jsx(Ap,{apiKey:A,onSave:h,onDelete:r},A.id)):n.jsx(Lt,{text:"暂无密钥"})]}):n.jsx(Lt,{text:"请选择一个用户"})})}function Ap({apiKey:u,onSave:m,onDelete:h}){const[r,A]=g.useState(u.name),[E,L]=g.useState(be(u.allowedModels).join(", ")),[$,C]=g.useState(mm(u.expiresAt||"")),[y,R]=g.useState(String(u.rateLimitPerMinute||"")),[z,P]=g.useState(!1),ee=be(u.allowedModels).length?be(u.allowedModels).join(", "):"全部模型";g.useEffect(()=>{A(u.name),L(be(u.allowedModels).join(", ")),C(mm(u.expiresAt||"")),R(String(u.rateLimitPerMinute||""))},[u]);async function de(){P(!0);try{await m(u.id,{name:r.trim()||"API Key",allowedModels:Pc(E),expiresAt:np($),rateLimitPerMinute:Number(y||0)})}finally{P(!1)}}return n.jsxs("details",{className:"key-editor key-editor-collapsible",children:[n.jsxs("summary",{className:"key-editor-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:u.name}),n.jsxs("span",{children:[u.prefix,"*** · ",ee," · 最后使用 ",el(u.lastUsedAt)]})]}),n.jsxs("div",{className:"row-actions",children:[n.jsx(Dt,{tone:u.status,children:_t(u.status)}),n.jsx("span",{className:"key-expand-hint",children:"管理"})]})]}),n.jsxs("div",{className:"key-editor-body",children:[n.jsxs("div",{className:"key-editor-grid",children:[n.jsxs("label",{children:["名称",n.jsx("input",{value:r,onChange:ne=>A(ne.target.value)})]}),n.jsxs("label",{children:["允许模型",n.jsx("input",{value:E,onChange:ne=>L(ne.target.value),placeholder:"留空表示全部模型,多个用逗号分隔"})]}),n.jsxs("label",{children:["过期时间",n.jsx("input",{type:"datetime-local",value:$,onChange:ne=>C(ne.target.value)})]}),n.jsxs("label",{children:["每分钟限制",n.jsx("input",{type:"number",min:"0",value:y,onChange:ne=>R(ne.target.value),placeholder:"0 使用全局限制"})]})]}),n.jsxs("div",{className:"key-editor-actions",children:[n.jsx("button",{className:"secondary-button",onClick:()=>m(u.id,{status:u.status==="active"?"disabled":"active"}),children:u.status==="active"?"停用密钥":"启用密钥"}),n.jsx("button",{className:"danger-button",onClick:()=>h(u.id),children:"删除密钥"}),n.jsx("button",{className:"primary-button",disabled:z,onClick:de,children:z?"保存中":"保存设置"})]})]})]})}function Cp({models:u,onCopy:m,onCreate:h,onUpdate:r,onDelete:A}){const E=u.filter(B=>B.recommended),[L,$]=g.useState(""),[C,y]=g.useState("all"),[R,z]=g.useState("all"),[P,ee]=g.useState(1),[de,ne]=g.useState(""),[le,ie]=g.useState(""),[xe,Y]=g.useState(""),[ge,F]=g.useState(""),[me,D]=g.useState(""),[ae,fe]=g.useState(""),Ae=60,Te=g.useMemo(()=>{const B=new Map;return u.forEach(Q=>{const O=$c(Q);B.set(O,(B.get(O)||0)+1)}),Array.from(B.entries()).sort((Q,O)=>O[1]-Q[1]||il(Q[0]).localeCompare(il(O[0]))).map(([Q,O])=>({provider:Q,count:O}))},[u]),ue=g.useMemo(()=>{const B=L.trim().toLowerCase();return u.filter(Q=>C!=="all"&&$c(Q)!==C||R!=="all"&&Q.status!==R?!1:B?[Q.id,Q.name,Q.vendor,Q.category,Q.description,...be(Q.aliases)].join(" ").toLowerCase().includes(B):!0)},[u,L,C,R]),Z=g.useMemo(()=>{const B=new Map;ue.forEach(G=>{const X=$c(G);B.set(X,[...B.get(X)||[],G])});const Q=[];let O=[],d=0;const x=Array.from(B.entries()).sort((G,X)=>il(G[0]).localeCompare(il(X[0])));for(const G of x)O.length>0&&d+G[1].length>Ae&&(Q.push(O),O=[],d=0),O.push(G),d+=G[1].length;return O.length>0&&Q.push(O),Q},[ue]),re=Math.max(1,Z.length),J=Math.min(P,re),T=Z[J-1]||[];g.useEffect(()=>{ee(1)},[L,C,R,u.length]);async function k(B){B.preventDefault();const Q=de.trim();if(Q){fe("");try{await h({id:Q,name:le.trim()||Q,vendor:xe.trim()||"Custom",aliases:ge.split(",").map(O=>O.trim()).filter(Boolean),category:"通用",description:me.trim(),price:"自定义",context:"未配置上下文"}),ne(""),ie(""),Y(""),F(""),D("")}catch(O){fe(O instanceof Error?O.message:"模型添加失败")}}}return n.jsxs("section",{className:"models-page",children:[n.jsx("div",{className:"model-hero",children:n.jsxs("div",{children:[n.jsx("span",{children:"Model Catalog"}),n.jsx("strong",{children:"Models"})]})}),n.jsx(nt,{title:"新增模型",children:n.jsxs("form",{className:"model-create-form",onSubmit:k,children:[n.jsx("input",{value:de,onChange:B=>ne(B.target.value),placeholder:"模型 ID,例如 openai/gpt-4.1"}),n.jsx("input",{value:le,onChange:B=>ie(B.target.value),placeholder:"显示名称(可选)"}),n.jsx("input",{value:xe,onChange:B=>Y(B.target.value),placeholder:"供应商(可选)"}),n.jsx("input",{value:ge,onChange:B=>F(B.target.value),placeholder:"代称,多个用逗号分隔(可选)"}),n.jsx("input",{className:"model-create-wide",value:me,onChange:B=>D(B.target.value),placeholder:"描述(可选)"}),n.jsx("button",{className:"primary-button",type:"submit",children:"新增模型"}),n.jsx("div",{className:"model-create-message",role:"status",children:ae})]})}),E.length>0&&n.jsx(nt,{title:"推荐模型",children:n.jsx("div",{className:"model-grid",children:E.map(B=>n.jsx(Ep,{model:B,featured:!0,onCopy:m,onUpdate:r},B.id))})}),n.jsxs(nt,{title:"全部模型",children:[n.jsxs("div",{className:"panel-toolbar model-list-toolbar",children:[n.jsx("input",{value:L,onChange:B=>$(B.target.value),placeholder:"搜索模型 ID、名称、供应商或代称"}),n.jsx("div",{className:"model-filter-actions",children:[{value:"all",label:"全部"},{value:"available",label:"可用"},{value:"disabled",label:"禁用"}].map(B=>n.jsx("button",{type:"button",className:R===B.value?"selected":"",onClick:()=>z(B.value),children:B.label},B.value))})]}),n.jsxs("div",{className:"model-provider-filter","aria-label":"按供应商筛选模型",children:[n.jsxs("button",{type:"button",className:C==="all"?"selected":"",onClick:()=>y("all"),children:[n.jsx("span",{className:"provider-icon provider-icon-all","aria-hidden":"true",children:"All"}),n.jsx("strong",{children:"全部"}),n.jsx("small",{children:u.length})]}),Te.map(B=>n.jsxs("button",{type:"button",className:C===B.provider?"selected":"",onClick:()=>y(B.provider),children:[n.jsx(hm,{provider:B.provider}),n.jsx("strong",{children:il(B.provider)}),n.jsx("small",{children:B.count})]},B.provider))]}),n.jsxs("div",{className:"model-list-summary",children:[n.jsx("span",{children:C==="all"?"全部供应商":il(C)}),n.jsx("strong",{children:ue.length}),n.jsx("span",{children:"个模型"})]}),ue.length>0?n.jsxs(n.Fragment,{children:[n.jsx("div",{className:"model-provider-groups",children:T.map(([B,Q])=>n.jsxs("section",{className:"model-provider-group",children:[n.jsxs("header",{children:[n.jsx(hm,{provider:B}),n.jsxs("div",{children:[n.jsx("strong",{children:il(B)}),n.jsxs("span",{children:[Q.length," 个模型"]})]})]}),n.jsx("div",{className:"model-compact-grid",children:Q.map(O=>n.jsx(Tp,{model:O,onCopy:m,onUpdate:r,onDelete:A},O.id))})]},B))}),re>1&&n.jsxs("div",{className:"pager",children:[n.jsx("button",{className:"secondary-button compact-button",onClick:()=>ee(B=>Math.max(1,B-1)),disabled:J<=1,children:"上一页"}),n.jsxs("span",{children:[J," / ",re]}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>ee(B=>Math.min(re,B+1)),disabled:J>=re,children:"下一页"})]})]}):n.jsx(Lt,{text:u.length?"没有匹配的模型":"暂无模型,请先添加你要开放给用户调用的模型 ID"})]})]})}function Tp({model:u,onCopy:m,onUpdate:h,onDelete:r}){const A=be(u.aliases).slice(0,3),E=u.status==="disabled";return n.jsxs("article",{className:"model-compact-row",children:[n.jsxs("div",{className:"model-compact-main",children:[n.jsx("strong",{children:u.name}),n.jsx("small",{children:u.id}),A.length>0&&n.jsx("span",{children:A.map(L=>n.jsx("em",{children:L},L))})]}),n.jsxs("div",{className:"model-row-actions",children:[n.jsx(Dt,{tone:u.status,children:_t(u.status)}),u.recommended&&n.jsx("span",{className:"model-recommended-mark",children:"推荐"}),n.jsx("button",{className:"icon-button",title:"复制模型 ID",onClick:()=>m(u.id,"模型 ID 已复制"),children:n.jsx(Ot,{name:"copy"})}),n.jsxs("details",{className:"model-row-menu",children:[n.jsx("summary",{"aria-label":"模型操作",children:"•••"}),n.jsxs("div",{children:[n.jsx("button",{type:"button",onClick:()=>h(u.id,{recommended:!u.recommended}),children:u.recommended?"取消推荐":"设为推荐"}),n.jsx("button",{type:"button",onClick:()=>h(u.id,{status:E?"available":"disabled"}),children:E?"启用模型":"停用模型"}),n.jsx("button",{className:"is-danger",type:"button",onClick:()=>r(u.id),children:"删除模型"})]})]})]})]})}function Ep({model:u,featured:m=!1,onCopy:h,onUpdate:r}){return n.jsxs("article",{className:m?"model-card featured":"model-card",children:[n.jsxs("div",{className:"model-card-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:u.name}),n.jsxs("span",{children:[u.vendor," · ",u.category]})]}),n.jsx(Dt,{tone:u.status,children:_t(u.status)})]}),n.jsx("p",{children:u.description}),n.jsx("div",{className:"alias-row",children:be(u.aliases).map(A=>n.jsx("span",{children:A},A))}),n.jsxs("div",{className:"model-meta",children:[n.jsxs("span",{children:["价格:",u.price]}),n.jsx("span",{children:u.context})]}),n.jsxs("div",{className:"model-id",children:[n.jsx("code",{children:u.id}),n.jsx("button",{className:"icon-button",title:"复制模型 ID",onClick:()=>h(u.id,"模型 ID 已复制"),children:n.jsx(Ot,{name:"copy"})})]}),r&&n.jsxs("div",{className:"model-card-actions",children:[n.jsx("button",{className:"secondary-button compact-button",type:"button",onClick:()=>r(u.id,{recommended:!1}),children:"取消推荐"}),n.jsx("button",{className:"secondary-button compact-button",type:"button",onClick:()=>r(u.id,{status:u.status==="disabled"?"available":"disabled"}),children:u.status==="disabled"?"启用":"停用"})]})]})}function Mp({channels:u,onCreate:m,onImport:h,onCheckAccounts:r,onDeduplicateAccounts:A,onDeleteAccount:E,onUpdate:L,onStartOAuth:$,onCompleteOAuth:C}){const y=u.filter(O=>O.provider==="codex"||O.provider==="antigravity"||O.provider==="openai"||be(O.models).some(d=>d.includes("image"))),[R,z]=g.useState(""),[P,ee]=g.useState({}),[de,ne]=g.useState({}),[le,ie]=g.useState({}),[xe,Y]=g.useState({}),[ge,F]=g.useState(""),[me,D]=g.useState(""),[ae,fe]=g.useState(""),[Ae,Te]=g.useState(""),ue=24,Z=48;async function re(O,d){z(`import:${O}`);try{await h(O,d)}finally{z("")}}async function J(O,d=!1,x=""){z(x?`check-account:${x}`:`${d?"retry":"check"}:${O}`);try{await r(O,d,x)}finally{z("")}}async function T(O){z(`dedupe:${O}`);try{await A(O)}finally{z("")}}function k(O){const d=be(O.openaiAccounts).map(N=>[N.email||N.name||N.accountId||N.id,N.accountId||"",N.status||"unchecked",N.credentialMode||"access-token",N.planType||"",N.expiresAt||"",N.lastCheckedAt||"",N.lastUsedAt||"",String(N.requestCount||0),N.lastErrorCode||"",N.lastError||""]),x=N=>`"${N.replace(/"/g,'""')}"`,G=[["账号","Account ID","状态","凭据方式","套餐","到期时间","最近检测","最近调用","调用次数","错误码","最后错误"],...d].map(N=>N.map(x).join(",")).join(`\r +`),X=new Blob(["\uFEFF"+G],{type:"text/csv;charset=utf-8"}),se=URL.createObjectURL(X),ve=document.createElement("a");ve.href=se,ve.download=`${O.name||"account-pool"}-health-report.csv`,ve.click(),URL.revokeObjectURL(se)}async function B(O){z(`status:${O.id}`);try{await L(O.id,{status:O.status==="disabled"?"healthy":"disabled",baseUrl:O.baseUrl||Ei(O.provider)||Ti,provider:O.provider||"codex",models:be(O.models).length?O.models:xm.split(",").map(d=>d.trim())})}finally{z("")}}async function Q(O,d){const x=d.email||d.name||d.accountId||d.id;if(window.confirm(`删除账号「${x}」?`)){z(`delete-account:${d.id}`);try{await E(O.id,d.id)}finally{z("")}}}return n.jsxs(nt,{title:"账号池",children:[n.jsxs("div",{className:"panel-toolbar",children:[n.jsx("span",{className:"muted-inline",children:"账号有两种来源,任选其一即可。"}),n.jsx("button",{className:"primary-button",onClick:()=>m(Ic("codex")),children:"新增账号池渠道"}),n.jsx("button",{className:"secondary-button",onClick:()=>m(Ic("antigravity")),children:"新增 Antigravity 账号池"})]}),n.jsxs("div",{className:"source-guide",children:[n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"网页会话(推荐)"}),n.jsx("span",{children:"支持完整 auth/session JSON 或浏览器 Session Cookie,并在调用前重新获取 accessToken。"})]}),n.jsxs("div",{className:"source-guide-item",children:[n.jsx("strong",{children:"批量导入"}),n.jsx("span",{children:"支持 JSON、ZIP、TXT;TXT 可使用 JSONL 或每行一个 access token。"})]})]}),n.jsxs("div",{className:"channels-stack",children:[y.map(O=>{const d=be(O.openaiAccounts),x=d.filter(V=>V.status==="healthy").length,G=d.filter(V=>V.status==="invalid").length,X=d.filter(V=>!!V.lastErrorCode).length,se=Math.max(0,d.length-x-G),ve=d.filter(V=>V.credentialMode==="refreshable").length,N=d.filter(V=>V.credentialMode==="browser-session").length,Ne=Math.max(0,d.length-ve-N),Se=de[O.id]||"all",bt=(le[O.id]||"").trim().toLowerCase(),I=d.filter(V=>{const _=Se==="all"||Se==="attention"&&Gp(V)||Se==="invalid"&&V.status==="invalid"||Se==="error"&&!!V.lastErrorCode||Se==="refreshable"&&V.credentialMode==="refreshable",Ee=`${V.email||""} ${V.name||""} ${V.accountId||""} ${V.userId||""} ${V.lastError||""}`.toLowerCase();return _&&(!bt||Ee.includes(bt))}),Ke=xe[O.id]||"pool",We=[...I].sort((V,_)=>{if(Ke==="pool")return 0;const Ee=Ke==="expiry"?V.expiresAt||"9999-12-31":V.lastUsedAt||"",et=Ke==="expiry"?_.expiresAt||"9999-12-31":_.lastUsedAt||"";return Ke==="recent"?et.localeCompare(Ee):Ee.localeCompare(et)}),Pe=Math.min(We.length,P[O.id]||ue),tl=We.slice(0,Pe),kt=Math.max(0,We.length-tl.length),cl=kt===0;return n.jsxs("div",{className:"channel-card",children:[n.jsxs("div",{className:"channel-card-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:O.name}),n.jsx("span",{children:O.baseUrl||Ei(O.provider)||Ti}),n.jsxs("small",{children:["账号 ",d.length," 个,可用 ",x,",无效 ",G,",未验证 ",se]}),n.jsxs("small",{children:["可续期 ",ve," · 网页会话 ",N," · 仅 Token ",Ne]}),n.jsxs("small",{children:["自动检测 ",O.lastCheckedAt?el(O.lastCheckedAt):"等待首次检测"]})]}),n.jsxs("div",{className:"channel-card-head-actions",children:[n.jsx(Dt,{tone:O.status,children:_t(O.status)}),n.jsx("button",{className:"primary-button compact-button",onClick:()=>Te(O.id),disabled:R!=="",children:"添加账号"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>J(O.id),disabled:R!==""||d.length===0,children:R===`check:${O.id}`?"检测中":"批量检测"}),G>0&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>J(O.id,!0),disabled:R!=="",children:R===`retry:${O.id}`?"复检中":`复检无效 ${G}`}),d.length>1&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>T(O.id),disabled:R!=="",children:R===`dedupe:${O.id}`?"去重中":"账号去重"}),d.length>0&&n.jsx("button",{className:"secondary-button compact-button",onClick:()=>k(O),disabled:R!=="",children:"导出报告"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>B(O),disabled:R!=="",children:O.status==="disabled"?"启用渠道":"停用渠道"})]})]}),n.jsxs("div",{className:"account-filter-bar",role:"group","aria-label":"账号筛选",children:[n.jsx("input",{value:le[O.id]||"",onChange:V=>ie(_=>({..._,[O.id]:V.target.value})),placeholder:"搜索账号或错误","aria-label":"搜索账号"}),n.jsxs("select",{value:Ke,onChange:V=>Y(_=>({..._,[O.id]:V.target.value})),"aria-label":"账号排序",children:[n.jsx("option",{value:"pool",children:"账号池顺序"}),n.jsx("option",{value:"oldest",children:"最久未用优先"}),n.jsx("option",{value:"recent",children:"最近使用优先"}),n.jsx("option",{value:"expiry",children:"最早到期优先"})]}),[["all",`全部 ${d.length}`],["attention","需关注"],["invalid",`无效 ${G}`],["error",`有错误 ${X}`],["refreshable",`可续期 ${ve}`]].map(([V,_])=>n.jsx("button",{type:"button",className:Se===V?"selected":"",onClick:()=>ne(Ee=>({...Ee,[O.id]:V})),children:_},V))]}),n.jsxs("div",{className:"metrics-grid",children:[n.jsx(ul,{label:"账号总数",value:d.length}),n.jsx(ul,{label:"可用账号",value:x}),n.jsx(ul,{label:"无效账号",value:G}),n.jsx(ul,{label:"未验证账号",value:se})]}),n.jsx("div",{className:"drawing-channel-models",children:be(O.models).length?be(O.models).map(V=>n.jsx("span",{children:V},V)):n.jsx("span",{children:"未绑定绘图模型"})}),d.length>0&&n.jsxs("div",{className:"account-pool-list",children:[tl.map(V=>n.jsxs("div",{className:"account-pool-row",children:[n.jsxs("div",{className:"account-pool-main",children:[n.jsxs("div",{children:[n.jsxs("div",{className:"account-pool-title",children:[n.jsx("strong",{title:V.email||V.name||V.accountId||V.id,children:V.email||V.name||V.accountId||V.id}),n.jsx("span",{className:`source-tag source-tag-${V.source==="web-login"?"web":"manual"}`,children:V.source==="web-login"?"网页登录":V.source==="web-oauth"?"网页 OAuth":V.source==="oauth"?"Codex OAuth":V.source==="antigravity"||V.source==="agy"||V.source==="google-antigravity"?"Antigravity":"导入"})]}),n.jsx("span",{children:V.lastError?`${fm(V.lastErrorCode)}${fm(V.lastErrorCode)?" · ":""}${V.lastError}`:V.lastCheckedAt?`上次检测 ${el(V.lastCheckedAt)}`:"未检测"}),n.jsxs("span",{children:[V.credentialMode==="refreshable"?"可自动续期":V.credentialMode==="browser-session"?"依赖网页会话":"仅 access token",V.expiresAt?` · 到期 ${el(V.expiresAt)}`:""]}),n.jsxs("span",{children:["套餐 ",lp(V.planType)]}),V.lastUsedAt&&n.jsxs("span",{children:["最近调用 ",el(V.lastUsedAt)," · ",V.requestCount||0," 次"]})]}),n.jsx(wp,{limits:V.quotaLimits})]}),n.jsxs("div",{className:"account-pool-meta",children:[n.jsx(Dt,{tone:V.status==="healthy"?"healthy":V.status==="invalid"?"disabled":"standby",children:V.status==="healthy"?"可用":V.status==="invalid"?"无效":"未验证"}),n.jsx("button",{type:"button",className:"secondary-button compact-button",disabled:R!=="",onClick:()=>J(O.id,!1,V.id),children:R===`check-account:${V.id}`?"检测中":"检测"}),n.jsx("button",{type:"button",className:"danger-button compact-button",disabled:R!=="",onClick:()=>Q(O,V),children:R===`delete-account:${V.id}`?"删除中":"删除"})]})]},V.id)),I.length===0&&n.jsx(Lt,{text:"没有匹配的账号"}),We.length>ue&&n.jsxs("div",{className:"account-pool-more",children:[n.jsx("span",{className:"muted-inline",children:cl?`已显示全部 ${We.length} 个账号`:`已显示 ${tl.length} 个,还有 ${kt} 个`}),n.jsxs("div",{className:"account-pool-more-actions",children:[!cl&&n.jsxs("button",{type:"button",className:"secondary-button compact-button",onClick:()=>ee(V=>({...V,[O.id]:Math.min(We.length,Pe+Z)})),children:["再显示 ",Math.min(Z,kt)," 个"]}),!cl&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>ee(V=>({...V,[O.id]:We.length})),children:"全部显示"}),Pe>ue&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>ee(V=>({...V,[O.id]:ue})),children:"收起"})]})]})]})]},O.id)}),y.length===0&&n.jsx(Lt,{text:"暂无绘图渠道,先新增一个 OpenAI 账号池渠道"})]}),ge&&n.jsx(Rp,{channelId:ge,onStart:$,onComplete:C,onClose:()=>F("")}),Ae&&n.jsx(zp,{busy:R!=="",onAuthSession:()=>{D(Ae),Te("")},onAntigravity:()=>{fe(Ae),Te("")},onImport:async O=>{await re(Ae,O),Te("")},onClose:()=>Te("")}),me&&n.jsx(_p,{onImport:async O=>{await re(me,new File([JSON.stringify(Op(O))],"authsession.json",{type:"application/json"}))},onClose:()=>D("")}),ae&&n.jsx(Up,{onImport:async O=>{await re(ae,new File([JSON.stringify(Dp(O))],"antigravity.json",{type:"application/json"}))},onClose:()=>fe("")})]})}function zp({busy:u,onAuthSession:m,onAntigravity:h,onImport:r,onClose:A}){return n.jsx("div",{className:"modal-backdrop",onClick:A,children:n.jsxs("div",{className:"modal-card account-add-modal",onClick:E=>E.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"添加账号"}),n.jsx("span",{children:"选择一种账号接入方式"})]}),n.jsx("button",{type:"button",className:"icon-button",onClick:A,children:"×"})]}),n.jsxs("div",{className:"account-add-options",children:[n.jsxs("button",{type:"button",className:"account-add-option recommended",onClick:m,disabled:u,children:[n.jsx("span",{className:"account-add-icon",children:"A"}),n.jsx("strong",{children:"导入网页会话"}),n.jsx("small",{children:"粘贴完整 authsession JSON,保留 sessionToken"})]}),n.jsxs("button",{type:"button",className:"account-add-option",onClick:h,disabled:u,children:[n.jsx("span",{className:"account-add-icon",children:"G"}),n.jsx("strong",{children:"导入 Antigravity"}),n.jsx("small",{children:"粘贴 Google OAuth JSON 或 refresh token"})]}),n.jsxs("label",{className:`account-add-option${u?" disabled":""}`,children:[n.jsx("span",{className:"account-add-icon",children:"J"}),n.jsx("strong",{children:u?"导入中":"导入 JSON / ZIP / TXT"}),n.jsx("small",{children:"批量导入已有账号文件"}),n.jsx("input",{type:"file",accept:"application/json,application/zip,text/plain,.json,.zip,.txt",disabled:u,onChange:E=>{const L=E.target.files?.[0];L&&r(L),E.target.value=""}})]})]}),n.jsx("div",{className:"modal-actions",children:n.jsx("button",{type:"button",className:"secondary-button",onClick:A,children:"取消"})})]})})}function Op(u){const m=u.trim(),h=m.match(/(?:^|[;\s])(__Secure-(?:next-auth|authjs)\.session-token)=([^;\s]+)/);if(h)return{sessionToken:h[2],source:"web-login"};try{const r=JSON.parse(m),A=r.tokens&&typeof r.tokens=="object"?r.tokens:{},E=R=>typeof r[R]=="string"?r[R]:typeof A[R]=="string"?A[R]:"",L=E("accessToken")||E("access_token"),$=E("refreshToken")||E("refresh_token"),C=E("sessionToken")||E("session_token"),y=r.user&&typeof r.user=="object"?r.user:{};if(L||$||C)return{accessToken:L||void 0,refreshToken:$||void 0,sessionToken:C||void 0,email:typeof y.email=="string"?y.email:void 0,name:typeof y.name=="string"?y.name:void 0,source:"web-login"}}catch{}return{sessionToken:m,source:"web-login"}}function _p({onImport:u,onClose:m}){const[h,r]=g.useState(""),[A,E]=g.useState(!1),[L,$]=g.useState(""),[C,y]=g.useState("");async function R(){if(!h.trim()){$("请粘贴 authsession");return}E(!0),$(""),y("");try{await u(h.trim()),r(""),y("已导入,继续粘贴下一条即可")}catch(z){$(z instanceof Error?z.message:"导入失败")}finally{E(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:m,children:n.jsxs("div",{className:"modal-card",onClick:z=>z.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"添加网页会话"}),n.jsx("button",{type:"button",className:"icon-button",onClick:m,children:"×"})]}),n.jsxs("p",{className:"muted-inline",children:["可直接粘贴 chatgpt.com/api/auth/session 的完整 JSON;也支持浏览器 ",n.jsx("code",{children:"__Secure-next-auth.session-token"})," 的值或完整 Cookie 字符串。"]}),n.jsxs("label",{className:"authsession-field",children:[n.jsx("span",{children:"authsession"}),n.jsx("textarea",{autoFocus:!0,value:h,onChange:z=>r(z.target.value),placeholder:"eyJhbGci..."})]}),L&&n.jsx("div",{className:"form-error",children:L}),C&&n.jsx("div",{className:"form-success",children:C}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:m,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:A,onClick:R,children:A?"导入中":"导入账号"})]})]})})}function Dp(u){const m=u.trim();try{const h=JSON.parse(m),r=h.tokens&&typeof h.tokens=="object"?h.tokens:{},A=(...y)=>{for(const R of y){if(typeof h[R]=="string"&&h[R])return h[R];if(typeof r[R]=="string"&&r[R])return r[R]}return""},E=A("access_token","accessToken"),L=A("refresh_token","refreshToken"),$=A("email"),C=A("expired","expires_at","expiresAt","expiry");if(E||L)return{accessToken:E||void 0,refreshToken:L||void 0,email:$||void 0,expired:C||void 0,source:"antigravity"}}catch{}return{refreshToken:m,source:"antigravity"}}function Up({onImport:u,onClose:m}){const[h,r]=g.useState(""),[A,E]=g.useState(!1),[L,$]=g.useState(""),[C,y]=g.useState("");async function R(){if(!h.trim()){$("请粘贴 Antigravity OAuth JSON 或 refresh token");return}E(!0),$(""),y("");try{await u(h.trim()),r(""),y("已导入,继续粘贴下一条即可")}catch(z){$(z instanceof Error?z.message:"导入失败")}finally{E(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:m,children:n.jsxs("div",{className:"modal-card",onClick:z=>z.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"导入 Antigravity 账号"}),n.jsx("button",{type:"button",className:"icon-button",onClick:m,children:"×"})]}),n.jsxs("p",{className:"muted-inline",children:["粘贴 Antigravity 的 Google OAuth 凭证 JSON(含 ",n.jsx("code",{children:"access_token"})," / ",n.jsx("code",{children:"refresh_token"}),"),或直接粘贴 refresh token。导入后会自动刷新并加入账号池。"]}),n.jsxs("label",{className:"authsession-field",children:[n.jsx("span",{children:"OAuth JSON / refresh token"}),n.jsx("textarea",{autoFocus:!0,value:h,onChange:z=>r(z.target.value),placeholder:'{"access_token":"ya29...","refresh_token":"1//..."}'})]}),L&&n.jsx("div",{className:"form-error",children:L}),C&&n.jsx("div",{className:"form-success",children:C}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:m,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:A,onClick:R,children:A?"导入中":"导入账号"})]})]})})}function Rp({channelId:u,onStart:m,onComplete:h,onClose:r}){const[A,E]=g.useState(""),[L,$]=g.useState(""),[C,y]=g.useState(""),[R,z]=g.useState(!1),[P,ee]=g.useState("");async function de(){z(!0),ee("");try{const le=await m(u);E(le.authorizeUrl),$(le.state),window.open(le.authorizeUrl,"_blank","noopener")}catch(le){ee(le instanceof Error?le.message:"发起授权失败")}finally{z(!1)}}async function ne(){if(!C.trim()){ee("请粘贴授权完成后浏览器跳转的回调地址");return}z(!0),ee("");try{await h(u,{callbackUrl:C.trim(),state:L}),r()}catch(le){ee(le instanceof Error?le.message:"完成授权失败")}finally{z(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:r,children:n.jsxs("div",{className:"modal-card",onClick:le=>le.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsx("strong",{children:"OAuth 授权添加网页账号"}),n.jsx("button",{type:"button",className:"icon-button",onClick:r,children:"×"})]}),n.jsx("p",{className:"muted-inline",children:"使用 ChatGPT 网页兼容的 OAuth 客户端获取 refresh_token,只调用网页 backend-api,不会走 Codex 接口。"}),n.jsxs("ol",{className:"oauth-steps",children:[n.jsxs("li",{children:[n.jsx("button",{type:"button",className:"primary-button",onClick:de,disabled:R,children:A?"重新生成授权链接":"① 生成授权链接并打开"}),A&&n.jsxs("div",{className:"oauth-link",children:[n.jsx("input",{readOnly:!0,value:A,onFocus:le=>le.target.select()}),n.jsx("span",{className:"muted-inline",children:"若未自动打开,复制到浏览器手动访问,用要添加的 ChatGPT 账号登录授权。"})]})]}),n.jsxs("li",{children:[n.jsx("label",{children:"② 粘贴授权后浏览器跳转的完整回调地址"}),n.jsx("input",{value:C,placeholder:"https://platform.openai.com/auth/callback?code=...&state=...",onChange:le=>y(le.target.value),disabled:!A||R})]})]}),P&&n.jsx("p",{className:"form-error",children:P}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:r,disabled:R,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",onClick:ne,disabled:!A||R,children:R?"处理中":"完成授权"})]})]})})}function wp({limits:u}){const m=be(u).filter(h=>h.label||h.name).slice(0,3);return m.length?n.jsx("div",{className:"quota-bars",children:m.map(h=>{const r=Hp(h);return n.jsxs("div",{className:"quota-bar",children:[n.jsxs("div",{className:"quota-bar-label",children:[n.jsx("strong",{children:h.label||h.name}),n.jsx("span",{children:Bp(h,r)})]}),n.jsx("div",{className:"quota-bar-track",children:n.jsx("span",{style:{width:`${r}%`}})})]},`${h.label||h.name}-${h.resetAt||""}`)})}):null}function Hp(u){return typeof u.percentRemaining=="number"&&Number.isFinite(u.percentRemaining)?Math.max(0,Math.min(100,u.percentRemaining)):typeof u.remaining=="number"&&typeof u.limit=="number"&&u.limit>0?Math.max(0,Math.min(100,u.remaining/u.limit*100)):typeof u.used=="number"&&typeof u.limit=="number"&&u.limit>0?Math.max(0,Math.min(100,(u.limit-u.used)/u.limit*100)):0}function Bp(u,m){const h=u.resetAt?` · ${el(u.resetAt)}`:"";return typeof u.remaining=="number"?`${Math.round(m)}% 剩余${h}`:`${Math.round(m)}%${h}`}function qp(u){const m=be(u.models).join(" ").toLowerCase(),h=["对话"];u.streamMode!=="disabled"&&h.push("流式"),/(image|dall-e|gpt-image)/.test(m)&&h.push("图片"),(u.openaiAccountCount??u.openaiAccounts?.length??0)>0&&h.push("账号池");const r=u.upstreamKeyCount??0;return r>1&&h.push(`${r} Key 轮询`),h}function Gp(u){if(u.status==="invalid"||u.credentialMode==="browser-session")return!0;if(!u.expiresAt)return!1;const m=new Date(u.expiresAt).getTime();return Number.isFinite(m)&&m-Date.now()<=1440*60*1e3}function Yp({channels:u,groups:m,onUpdate:h,onCreate:r,onImport:A,onDelete:E,onSyncModels:L,onCheck:$}){const C=Ta("openai"),[y,R]=g.useState(!1),[z,P]=g.useState(C.provider),[ee,de]=g.useState(C.name),[ne,le]=g.useState(C.baseUrl),[ie,xe]=g.useState(C.models.join(", ")),[Y,ge]=g.useState(""),[F,me]=g.useState(""),[D,ae]=g.useState(!1),[fe,Ae]=g.useState(!1);function Te(Z){const re=Ta(Z);P(re.provider),de(re.name),le(re.baseUrl),xe(re.models.join(", ")),me("")}async function ue(Z){Z.preventDefault(),ae(!0),me("");try{await r({name:ee.trim()||Ta(z).name,provider:z,baseUrl:ne.trim(),...Sm(Y),models:Pc(ie),streamMode:"auto"}),R(!1),ge(""),Te(z)}catch(re){me(re instanceof Error?re.message:"渠道创建失败")}finally{ae(!1)}}return n.jsxs(nt,{title:"渠道",children:[n.jsxs("div",{className:"channel-page-intro",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"管理上游服务"}),n.jsx("span",{children:"每个渠道对应一个 API 上游。先添加渠道,再检测连通性并同步可用模型。"})]}),n.jsxs("div",{className:"channel-page-summary",children:[n.jsxs("span",{children:[n.jsx("b",{children:u.length})," 个渠道"]}),n.jsxs("span",{children:[n.jsx("b",{children:u.filter(Z=>Z.status!=="disabled").length})," 个已启用"]})]})]}),n.jsxs("div",{className:"panel-toolbar channel-toolbar",children:[n.jsx("span",{className:"muted-inline",children:"列表显示当前状态;点击任一渠道可修改连接、模型和计费设置。"}),n.jsx("button",{className:"primary-button",onClick:()=>R(Z=>!Z),children:y?"取消新增":"+ 新增渠道"})]}),y&&n.jsxs("form",{className:"channel-card channel-create-form",onSubmit:ue,children:[n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"选择渠道类型"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:Ta(z).label}),n.jsx("small",{children:"选择后自动填入建议配置"})]}),n.jsx("div",{role:"listbox","aria-label":"选择渠道类型",children:Fc.map(Z=>n.jsxs("button",{type:"button",className:z===Z.provider?"selected":"",onClick:re=>{Te(Z.provider),re.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:Z.label}),n.jsx("span",{children:"使用推荐的名称和地址"})]},Z.provider))})]})]}),n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"渠道名称"}),n.jsx("input",{value:ee,onChange:Z=>de(Z.target.value),placeholder:"例如 OpenAI 主线路"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"供应商"}),n.jsx("input",{value:il(z),readOnly:!0})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"Base URL"}),n.jsx("input",{value:ne,onChange:Z=>le(Z.target.value),placeholder:"https://provider.example/v1"})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"上游 Key"}),n.jsx("textarea",{className:"channel-key-input",value:Y,onChange:Z=>ge(Z.target.value),placeholder:z==="codex"?"账号池导入后使用":z==="cpa"?"填写 CPA 的 API key,多个每行一个":"每行一个 Key;填多个会自动轮询分发",autoComplete:"off",rows:3})]}),n.jsxs("div",{className:"channel-form-wide channel-model-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"模型"}),n.jsx("button",{type:"button",className:"model-pull-button",onClick:()=>{if(z!=="codex"&&!ne.trim()){me("请先填写 Base URL 再获取模型");return}me(""),Ae(!0)},children:"从上游获取模型"})]}),n.jsx("textarea",{value:ie,onChange:Z=>xe(Z.target.value),placeholder:"多个模型用逗号分隔,或点上方『从上游获取模型』拉取后多选"})]})]}),n.jsxs("div",{className:"channel-card-actions",children:[n.jsx("span",{className:"model-create-message",role:"status",children:F}),n.jsx("button",{className:"secondary-button",type:"button",onClick:()=>Te(z),disabled:D,children:"填入模板"}),n.jsx("button",{className:"primary-button",type:"submit",disabled:D,children:D?"创建中":"创建渠道"})]})]}),y&&fe&&n.jsx(Nm,{subtitle:`${ee.trim()||Ta(z).name} · 勾选需要接入的模型`,current:Pc(ie),loadModels:async()=>{const Z=await pe("/api/channel-model-preview",{method:"POST",body:JSON.stringify({provider:z,baseUrl:ne.trim(),upstreamApiKey:Y})});return be(Z.models)},onConfirm:async Z=>{xe(Z.join(", "))},onClose:()=>Ae(!1)}),n.jsxs("div",{className:"channels-stack",children:[u.map(Z=>n.jsx(Lp,{channel:Z,groups:m,onUpdate:h,onImport:A,onDelete:E,onSyncModels:L,onCheck:$},Z.id)),u.length===0&&n.jsx(Lt,{text:"暂无渠道,先在后端添加渠道接口或导入配置"})]})]})}function Lp({channel:u,groups:m,onUpdate:h,onImport:r,onDelete:A,onSyncModels:E,onCheck:L}){const[$,C]=g.useState(u.name),[y,R]=g.useState(u.provider),[z,P]=g.useState(u.streamMode||"auto"),[ee,de]=g.useState(u.baseUrl),[ne,le]=g.useState(be(u.allowedGroupIds)),[ie,xe]=g.useState(be(u.models).join(", ")),[Y,ge]=g.useState("saved"),[F,me]=g.useState(String(u.inputPricePer1K||0)),[D,ae]=g.useState(String(u.outputPricePer1K||0)),[fe,Ae]=g.useState(!!u.webEndpoint),[Te,ue]=g.useState(""),[Z,re]=g.useState(""),[J,T]=g.useState(!1),k=u.openaiAccountCount??u.openaiAccounts?.length??0,B=be(u.models).length,Q=qp(u),O=u.status==="disabled",d={saved:"已保存",template:"模板",manual:"手动",synced:"上游同步"}[Y],x=Ni.find(I=>I.value===z)||Ni[0],G={auto:"自动处理(推荐)",real:"强制流式",fake:"兼容流式",disabled:"关闭流式"};g.useEffect(()=>{C(u.name),R(u.provider),P(u.streamMode||"auto"),de(u.baseUrl),le(be(u.allowedGroupIds)),xe(be(u.models).join(", ")),ge("saved"),me(String(u.inputPricePer1K||0)),ae(String(u.outputPricePer1K||0)),Ae(!!u.webEndpoint),ue("")},[u.id,u.name,u.provider,u.streamMode,u.baseUrl,u.models,u.inputPricePer1K,u.outputPricePer1K,u.webEndpoint]);async function X(){const I=se();re("save");try{await h(u.id,I),ue("")}finally{re("")}}function se(){const I=Ei(y),Ke=!/^https?:\/\//i.test(ee.trim())&&I?I:ee,We={name:$.trim()||u.name,provider:y,streamMode:z,baseUrl:Ke,inputPricePer1K:Number(F)||0,outputPricePer1K:Number(D)||0,webEndpoint:fe,models:ie.split(",").map(Pe=>Pe.trim()).filter(Boolean),allowedGroupIds:ne};return Object.assign(We,Sm(Te)),We}async function ve(){const I=u.status==="disabled"?"healthy":"disabled";re("status");try{await h(u.id,{...se(),status:I}),ue("")}finally{re("")}}async function N(){re("sync");try{await h(u.id,se()),ue(""),T(!0)}finally{re("")}}function Ne(){const I=Ta(y);xe(I.models.join(", ")),ge("template"),I.baseUrl&&!/^https?:\/\//i.test(ee.trim())&&de(I.baseUrl)}async function Se(){re("check");try{await X(),await L(u.id)}finally{re("")}}async function bt(I){re("import");try{await r(u.id,I)}finally{re("")}}return n.jsxs(n.Fragment,{children:[n.jsxs("details",{className:"channel-card channel-card-collapsible",children:[n.jsxs("summary",{className:"channel-card-head channel-list-row",children:[n.jsxs("div",{className:"channel-identity",children:[n.jsx("strong",{children:u.name}),n.jsx("span",{children:il(y)}),n.jsx("small",{children:u.baseUrl||"尚未配置上游地址"}),n.jsx("div",{className:"channel-capability-tags",children:Q.map(I=>n.jsx("span",{children:I},I))})]}),n.jsxs("div",{className:"channel-list-meta",children:[n.jsxs("span",{children:[n.jsx("b",{children:B})," 个模型"]}),k>0&&n.jsxs("span",{children:[n.jsx("b",{children:k})," 个账号"]})]}),n.jsxs("div",{className:"channel-check-result",children:[n.jsx("span",{children:"连通性"}),n.jsx("b",{className:u.lastError?"is-error":u.lastCheckedAt?"is-ok":"",children:u.lastError?"检测失败":u.lastCheckedAt?`已检测 ${el(u.lastCheckedAt)}`:"尚未检测"})]}),n.jsxs("div",{className:"channel-list-status",children:[n.jsx(Dt,{tone:u.status,children:O?"已停用":_t(u.status)}),n.jsx("span",{className:"channel-expand-hint",children:"配置"})]})]}),n.jsxs("div",{className:"channel-editor-controls",children:[n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"供应商"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:il(y)}),n.jsx("small",{children:"修改上游协议类型"})]}),n.jsx("div",{role:"listbox","aria-label":"供应商",children:to.map(I=>n.jsxs("button",{type:"button",className:y===I.value?"selected":"",onClick:Ke=>{R(I.value);const We=Ei(I.value);We&&!/^https?:\/\//i.test(ee.trim())&&de(We),Ke.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:I.label}),n.jsx("span",{children:I.value==="compatible"?"适用于兼容 OpenAI 格式的服务":"选择对应的上游协议"})]},I.value))})]})]}),n.jsxs("label",{className:"channel-select-field",children:[n.jsx("span",{children:"响应方式"}),n.jsxs("details",{className:"channel-choice-menu",children:[n.jsxs("summary",{children:[n.jsx("span",{children:G[x.value]}),n.jsx("small",{children:x.description})]}),n.jsx("div",{role:"listbox","aria-label":"响应方式",children:Ni.map(I=>n.jsxs("button",{type:"button",className:z===I.value?"selected":"",onClick:Ke=>{P(I.value),Ke.currentTarget.closest("details")?.removeAttribute("open")},children:[n.jsx("strong",{children:G[I.value]}),n.jsx("span",{children:I.description})]},I.value))})]})]})]}),(y==="codex"||k>0)&&n.jsxs("div",{className:"setting",children:[n.jsxs("div",{children:[n.jsx("span",{children:"网页对话接口"}),n.jsx("small",{children:"开启后走 ChatGPT 网页对话接口,把 Plus 订阅账号包装成 API"})]}),n.jsx("div",{className:"setting-value",children:n.jsx("button",{type:"button",className:fe?"ios-switch is-on":"ios-switch","aria-label":fe?"关闭网页对话接口":"开启网页对话接口","aria-pressed":fe,onClick:()=>Ae(I=>!I),children:n.jsx("span",{})})})]}),n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"渠道名称"}),n.jsx("input",{value:$,onChange:I=>C(I.target.value),placeholder:"例如 Gemini 主线路"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"供应商"}),n.jsx("input",{value:il(y),readOnly:!0})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsx("span",{children:"Base URL"}),n.jsx("input",{value:ee,onChange:I=>de(I.target.value),placeholder:"https://provider.example/v1"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"优先级"}),n.jsx("input",{value:u.priority,readOnly:!0})]}),n.jsxs("div",{className:"channel-form-wide channel-model-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"模型"}),n.jsxs("small",{children:["来源:",d]})]}),n.jsx("textarea",{value:ie,onChange:I=>{xe(I.target.value),ge("manual")},placeholder:"优先拉取上游模型,也可以手动补充,多个用逗号分隔"}),n.jsxs("div",{className:"channel-model-actions",children:[n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:Ne,disabled:Z!=="",children:"填入模板"}),n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:N,disabled:Z!=="",children:Z==="sync"?"拉取中":"获取上游模型"})]})]}),n.jsxs("label",{className:"channel-form-wide",children:[n.jsxs("span",{children:["上游 Key",(u.upstreamKeyCount??0)>0?` (已配置 ${u.upstreamKeyCount} 个)`:u.upstreamKeySet?" (已配置)":""]}),n.jsx("textarea",{className:"channel-key-input",value:Te,onChange:I=>ue(I.target.value),placeholder:y==="codex"?"Codex 账号池不需要上游 Key":y==="cpa"?"填写 CPA 的 API key,多个每行一个":"每行一个 Key;填多个会自动轮询分发;留空不修改",autoComplete:"off",rows:3})]}),n.jsxs("label",{children:[n.jsx("span",{children:"输入单价 / 1K Token"}),n.jsx("input",{type:"number",min:"0",step:"0.0001",value:F,onChange:I=>me(I.target.value)})]}),n.jsxs("label",{children:[n.jsx("span",{children:"输出单价 / 1K Token"}),n.jsx("input",{type:"number",min:"0",step:"0.0001",value:D,onChange:I=>ae(I.target.value)})]}),n.jsx("span",{className:"channel-billing-note",children:"定价可先留空;接入是否可用优先看渠道检测和模型同步结果。"})]}),n.jsxs("div",{className:"channel-group-field",children:[n.jsxs("div",{className:"field-label-row",children:[n.jsx("span",{children:"可见分组"}),n.jsx("small",{children:ne.length?`已选择 ${ne.length} 个分组`:"全部用户可用"})]}),m.length===0?n.jsx("p",{className:"channel-group-empty",children:"还没有用户分组。去「分组」页创建后,可在这里把渠道限制为只对特定分组开放。"}):n.jsx("div",{className:"channel-group-options",children:m.map(I=>{const Ke=ne.includes(I.id);return n.jsxs("button",{type:"button",className:Ke?"selected":"","aria-pressed":Ke,onClick:()=>le(We=>Ke?We.filter(Pe=>Pe!==I.id):[...We,I.id]),children:[n.jsx("span",{children:I.name}),I.description&&n.jsx("small",{children:I.description})]},I.id)})})]}),n.jsxs("div",{className:"channel-card-actions",children:[n.jsx("button",{className:"secondary-button",onClick:Se,disabled:Z!=="",children:Z==="check"?"检测中":"检测渠道"}),n.jsx("button",{className:"primary-button",onClick:X,disabled:Z!=="",children:Z==="save"?"保存中":"保存"}),n.jsxs("details",{className:"channel-more-actions",children:[n.jsx("summary",{children:"更多操作"}),n.jsxs("div",{children:[n.jsxs("label",{className:"secondary-button",children:[Z==="import"?"导入中":"导入账号 JSON",n.jsx("input",{type:"file",accept:"application/json,application/zip,text/plain,.json,.zip,.txt",disabled:Z!=="",onChange:I=>{const Ke=I.target.files?.[0];Ke&&bt(Ke),I.target.value=""}})]}),n.jsx("button",{className:"secondary-button",onClick:ve,disabled:Z!=="",children:u.status==="disabled"?"启用渠道":"停用渠道"}),n.jsx("button",{className:"danger-button",onClick:()=>A(u.id),disabled:Z!=="",children:"删除渠道"})]})]})]})]}),J&&n.jsx(Nm,{subtitle:`${u.name} · 勾选需要接入的模型`,current:ie.split(",").map(I=>I.trim()).filter(Boolean),loadModels:async()=>{const I=await pe(`/api/channels/${u.id}/upstream-models`,{method:"POST",body:JSON.stringify({})});return be(I.models)},onConfirm:async I=>{await E(u.id,I)},onClose:()=>T(!1)})]})}function Nm({subtitle:u,current:m,loadModels:h,onConfirm:r,onClose:A}){const[E,L]=g.useState(!0),[$,C]=g.useState(""),[y,R]=g.useState([]),[z,P]=g.useState(new Set),[ee,de]=g.useState(""),[ne,le]=g.useState(!1);g.useEffect(()=>{let D=!1;return(async()=>{L(!0),C("");try{const ae=await h();if(D)return;const fe=new Set,Ae=be(ae).map(ue=>ue.trim()).filter(ue=>{if(!ue)return!1;const Z=ue.toLowerCase();return fe.has(Z)?!1:(fe.add(Z),!0)}),Te=new Set(m.map(ue=>ue.toLowerCase()));R(Ae),P(new Set(Ae.filter(ue=>Te.has(ue.toLowerCase()))))}catch(ae){D||C(ae instanceof Error?ae.message:"获取上游模型失败")}finally{D||L(!1)}})(),()=>{D=!0}},[]);const ie=ee.trim().toLowerCase(),xe=ie?y.filter(D=>D.toLowerCase().includes(ie)):y,Y=xe.length>0&&xe.every(D=>z.has(D));function ge(D){P(ae=>{const fe=new Set(ae);return fe.has(D)?fe.delete(D):fe.add(D),fe})}function F(){P(D=>{const ae=new Set(D);return Y?xe.forEach(fe=>ae.delete(fe)):xe.forEach(fe=>ae.add(fe)),ae})}async function me(){const D=new Set(y.map(ue=>ue.toLowerCase())),ae=m.filter(ue=>!D.has(ue.toLowerCase())),fe=y.filter(ue=>z.has(ue)),Ae=new Set,Te=[...ae,...fe].filter(ue=>{const Z=ue.toLowerCase();return Ae.has(Z)?!1:(Ae.add(Z),!0)});le(!0);try{await r(Te),A()}catch{le(!1)}}return n.jsx("div",{className:"modal-backdrop",onClick:A,children:n.jsxs("div",{className:"modal-card model-picker-modal",onClick:D=>D.stopPropagation(),children:[n.jsxs("div",{className:"modal-head",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"选择上游模型"}),n.jsx("span",{children:u})]}),n.jsx("button",{type:"button",className:"icon-button",onClick:A,children:"×"})]}),E?n.jsx("div",{className:"model-picker-status",children:"正在获取上游模型…"}):$?n.jsx("div",{className:"model-picker-status model-picker-error",children:$}):n.jsxs(n.Fragment,{children:[n.jsxs("div",{className:"model-picker-toolbar",children:[n.jsx("input",{className:"model-picker-search",value:ee,onChange:D=>de(D.target.value),placeholder:"搜索模型名称",autoFocus:!0}),n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:F,disabled:xe.length===0,children:Y?"取消全选":"全选"})]}),n.jsxs("div",{className:"model-picker-count",children:["共 ",y.length," 个 · 已选 ",z.size," 个",ie?` · 匹配 ${xe.length} 个`:""]}),n.jsxs("div",{className:"model-picker-list",children:[xe.map(D=>{const ae=z.has(D),fe=m.some(Ae=>Ae.toLowerCase()===D.toLowerCase());return n.jsxs("label",{className:`model-picker-row${ae?" checked":""}`,children:[n.jsx("input",{type:"checkbox",checked:ae,onChange:()=>ge(D)}),n.jsx("span",{className:"model-picker-name",children:D}),fe&&n.jsx("span",{className:"model-picker-tag",children:"已接入"})]},D)}),xe.length===0&&n.jsx("div",{className:"model-picker-status",children:"没有匹配的模型"})]})]}),n.jsxs("div",{className:"modal-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",onClick:A,children:"取消"}),n.jsx("button",{type:"button",className:"primary-button",disabled:E||!!$||ne,onClick:me,children:ne?"保存中":`导入所选 (${z.size})`})]})]})})}function kp({logs:u,onCopy:m}){const[h,r]=g.useState(u),[A,E]=g.useState(u.length),[L,$]=g.useState(1),[C,y]=g.useState(""),[R,z]=g.useState("all"),[P,ee]=g.useState(null),[de,ne]=g.useState(!1),[le,ie]=g.useState(!1),xe=25,Y=Math.max(1,Math.ceil(A/xe));g.useEffect(()=>{$(1)},[C,R]),g.useEffect(()=>{L>Y&&$(Y)},[L,Y]),g.useEffect(()=>{const F=new AbortController,me=window.setTimeout(async()=>{ne(!0);try{const D=new URLSearchParams({page:String(L),pageSize:String(xe),status:R,q:C.trim()}),ae=await pe(`/api/logs?${D}`,{signal:F.signal}),fe=be(ae.logs);r(fe),E(ae.total||0),ee(Ae=>Ae&&fe.some(Te=>Te.id===Ae.id)?Ae:null)}catch(D){D instanceof DOMException&&D.name==="AbortError"||(r([]),E(0))}finally{F.signal.aborted||ne(!1)}},C?250:0);return()=>{window.clearTimeout(me),F.abort()}},[L,C,R]);async function ge(F){if(P?.id===F.id){ee(null);return}ee(F),ie(!0);try{const me=await pe(`/api/logs/${encodeURIComponent(F.id)}`);ee(me.log)}catch{ee(F)}finally{ie(!1)}}return n.jsxs(nt,{title:"调用日志",children:[n.jsxs("div",{className:"logs-toolbar",children:[n.jsxs("div",{className:"search-box",children:[n.jsx(Ot,{name:"search"}),n.jsx("input",{value:C,onChange:F=>y(F.target.value),placeholder:"搜索请求 ID、用户、Key、模型、渠道或错误码"})]}),n.jsx("div",{className:"log-status-filter",role:"group","aria-label":"日志状态筛选",children:[{value:"all",label:"全部"},{value:"success",label:"成功"},{value:"failed",label:"失败"}].map(F=>n.jsx("button",{type:"button",className:R===F.value?"selected":"",onClick:()=>z(F.value),children:F.label},F.value))}),n.jsx("span",{className:"muted-inline",children:de?"加载中":`共 ${A} 条`})]}),n.jsxs("div",{className:P?"logs-layout has-detail":"logs-layout",children:[n.jsxs("div",{className:"table",children:[n.jsxs("div",{className:"table-head logs-table",children:[n.jsx("span",{children:"请求"}),n.jsx("span",{children:"模型"}),n.jsx("span",{children:"渠道"}),n.jsx("span",{children:"状态"})]}),h.map(F=>n.jsx("div",{className:"log-entry",children:n.jsxs("div",{className:P?.id===F.id?"table-row logs-table selected":"table-row logs-table",role:"button",tabIndex:0,onClick:()=>ge(F),onKeyDown:me=>{(me.key==="Enter"||me.key===" ")&&ge(F)},children:[n.jsxs("span",{children:[n.jsx("strong",{children:lo(F)}),n.jsxs("small",{children:[F.id," · ",el(F.createdAt)," · ",F.latencyMs,"ms"]})]}),n.jsx("span",{children:ip(F)}),n.jsx("span",{children:up(F)}),n.jsx(Dt,{tone:F.status,children:_t(F.status)})]})},F.id)),!de&&h.length===0&&n.jsx(Lt,{text:C||R!=="all"?"没有匹配的日志":"暂无调用日志"})]}),P&&n.jsx(Qp,{log:P,loading:le,onCopy:m})]}),Y>1&&n.jsxs("div",{className:"pagination-bar",children:[n.jsx("button",{className:"secondary-button",disabled:L<=1||de,onClick:()=>$(F=>Math.max(1,F-1)),children:"上一页"}),n.jsxs("span",{children:[L," / ",Y]}),n.jsx("button",{className:"secondary-button",disabled:L>=Y||de,onClick:()=>$(F=>Math.min(Y,F+1)),children:"下一页"})]})]})}function Qp({log:u,loading:m,onCopy:h}){if(!u)return n.jsx("aside",{className:"log-inspector empty-inspector",children:n.jsx("span",{children:"选择一条日志查看详情"})});const r=Number(u.inputTokens||0),A=Number(u.outputTokens||0),E=typeof u.attempts=="number"?Math.max(0,u.attempts):null,L=[["请求 ID",u.id],["状态",_t(u.status)],["时间",sp(u.createdAt)],["用户 ID",u.userId||"未识别"],["API Key",u.apiKeyPrefix?`${u.apiKeyPrefix}***`:"未识别"],["模型",u.model||"未提供"],["渠道",u.channel||"未选择"],["实际账号",u.account||"未记录"],["响应耗时",`${u.latencyMs} ms`],["尝试次数",E===null?"未记录":String(E)],["是否重试",E===null?"未记录":E>1?"是":"否"],["输入 Tokens",ml(r)],["输出 Tokens",ml(A)],["总 Tokens",ml(r+A)],["扣费",u.cost.toFixed(4)],["错误码",u.errorCode||"无"]];return n.jsxs("aside",{className:"log-inspector",children:[n.jsxs("header",{children:[n.jsxs("div",{children:[n.jsx("span",{children:m?"加载中":"日志详情"}),n.jsx("strong",{children:lo(u)})]}),n.jsx(Dt,{tone:u.status,children:_t(u.status)})]}),n.jsx("div",{className:"log-detail",children:L.map(([$,C])=>n.jsxs("div",{children:[n.jsx("span",{children:$}),n.jsx("strong",{title:C,children:C})]},$))}),n.jsxs("div",{className:"log-actions",children:[n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>h(u.id,"请求 ID 已复制"),children:"复制请求 ID"}),u.errorCode&&n.jsx("button",{type:"button",className:"secondary-button compact-button",onClick:()=>h(u.errorCode||"","错误码已复制"),children:"复制错误码"})]})]})}function Xp({models:u,channels:m,groups:h}){const[r,A]=g.useState(null),[E,L]=g.useState(null),[$,C]=g.useState("username"),[y,R]=g.useState("0"),[z,P]=g.useState(""),[ee,de]=g.useState({enabled:!0,minReward:.1,maxReward:1}),[ne,le]=g.useState({logRetentionDays:30,maxLogs:1e4,maxQuotaEntries:2e4}),[ie,xe]=g.useState(null),[Y,ge]=g.useState(null),[F,me]=g.useState(""),[D,ae]=g.useState(""),[fe,Ae]=g.useState(""),[Te,ue]=g.useState(""),[Z,re]=g.useState(""),[J,T]=g.useState(""),[k,B]=g.useState(""),[Q,O]=g.useState(""),[d,x]=g.useState(""),[G,X]=g.useState(!1),[se,ve]=g.useState("system"),N=u.find(_=>_.recommended&&_.status==="available")?.id||u.find(_=>_.status==="available")?.id||"未配置",Ne=m.filter(_=>_.status!=="disabled").length,Se=[{value:"system",label:"系统",description:"运行概况"},{value:"cli",label:"CLI 接入",description:"一键配置"},{value:"auth",label:"注册",description:"开放方式"},{value:"check-in",label:"签到",description:"奖励范围"},{value:"admin",label:"管理员",description:"账号绑定"},{value:"discord",label:"Discord",description:"登录限制"},{value:"maintenance",label:"维护",description:"日志保留"},{value:"backup",label:"备份",description:"导出恢复"}],bt=Se.find(_=>_.value===se)||Se[0];g.useEffect(()=>{Promise.all([pe("/api/settings/discord"),pe("/api/settings/auth"),pe("/api/settings/check-in"),pe("/api/account/me"),pe("/api/settings/maintenance"),pe("/api/health")]).then(([_,Ee,et,xt,ft,tt])=>{A(Wc(_.discord)),O(be(_.discord.blockedGuildIds).join(` `)),L(Ee.auth.registrationEnabled),C(Mi(Ee.auth.registrationMode)),R(String(Ee.auth.defaultBalance||0)),P(Ee.auth.defaultGroupId||""),de(et.checkIn),ge(xt.account),me(xt.account?.username||""),ae(xt.user.name||""),Ae(xt.account?.email||""),ue(xt.account?.discordUserId||""),le(ft.maintenance),xe(tt)}).catch(()=>x("设置加载失败"))},[]);async function I(_=E,Ee=$,et=Number(y),xt=z){if(_!==null)try{const ft=await pe("/api/settings/auth",{method:"PATCH",body:JSON.stringify({registrationEnabled:_,registrationMode:Ee,defaultBalance:et,defaultGroupId:xt})});L(ft.auth.registrationEnabled),C(Mi(ft.auth.registrationMode)),R(String(ft.auth.defaultBalance||0)),P(ft.auth.defaultGroupId||""),x(ft.auth.registrationEnabled?"注册设置已保存":"已关闭用户注册")}catch(ft){x(ft instanceof Error?ft.message:"注册设置保存失败")}}async function Ke(){E!==null&&I(!E,$)}async function We(){X(!0),x("");try{const _=await pe("/api/settings/check-in",{method:"PATCH",body:JSON.stringify(ee)});de(_.checkIn),x(_.checkIn.enabled?"签到奖励设置已保存":"已关闭每日签到")}catch(_){x(_ instanceof Error?_.message:"签到设置保存失败")}finally{X(!1)}}async function Pe(){if(r){X(!0),x("");try{const _=Wc(r),Ee=Q.split(/[\s,]+/).map(xt=>xt.trim()).filter(Boolean),et=await pe("/api/settings/discord",{method:"PATCH",body:JSON.stringify({..._,blockedGuildIds:Ee,clientSecret:k})});A(Wc(et.discord)),O(be(et.discord.blockedGuildIds).join(` -`)),B(""),x("Discord 配置已保存")}catch(_){x(_ instanceof Error?_.message:"保存失败,请检查填写内容")}finally{X(!1)}}}async function tl(){try{const _=await pe("/api/account/profile",{method:"PATCH",body:JSON.stringify({username:F,displayName:D,email:fe,discordUserId:Te,currentPassword:Z,newPassword:J})});ge(_.account),me(_.account.username),Ae(_.account.email||""),ue(_.account.discordUserId||""),re(""),T(""),x("管理员账号已保存")}catch(_){x(_ instanceof Error?_.message:"账号设置保存失败")}}async function kt(){X(!0),x("");try{const _=await pe("/api/settings/maintenance",{method:"PATCH",body:JSON.stringify(ne)});le(_.maintenance),x("维护设置已保存,历史数据已按新规则清理")}catch(_){x(_ instanceof Error?_.message:"维护设置保存失败")}finally{X(!1)}}async function cl(){X(!0),x("");try{const _=await fetch("/api/backup",{credentials:"include"});if(!_.ok)throw new Error("备份导出失败");const Ee=await _.blob(),xt=(_.headers.get("Content-Disposition")||"").match(/filename="([^"]+)"/)?.[1]||"capi-backup.json",ft=URL.createObjectURL(Ee),tt=document.createElement("a");tt.href=ft,tt.download=xt,tt.click(),URL.revokeObjectURL(ft),x("备份已导出,请妥善保管")}catch(_){x(_ instanceof Error?_.message:"备份导出失败")}finally{X(!1)}}async function V(_){if(window.confirm("恢复会覆盖当前全部数据,并退出现有登录会话。确定继续?")){X(!0),x("");try{const Ee=await fetch("/api/restore",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:_}),et=await Ee.json().catch(()=>null);if(!Ee.ok)throw new Error(et?.error?.message||"备份恢复失败");x(`已恢复 ${et.users} 个用户、${et.channels} 条渠道和 ${et.models} 个模型,请重新登录`)}catch(Ee){x(Ee instanceof Error?Ee.message:"备份恢复失败")}finally{X(!1)}}}return n.jsxs("div",{className:"settings-layout",children:[n.jsx("div",{className:"settings-tabs",children:Se.map(_=>n.jsxs("button",{type:"button",className:se===_.value?"selected":"",onClick:()=>ve(_.value),children:[n.jsx("strong",{children:_.label}),n.jsx("small",{children:_.description})]},_.value))}),n.jsxs("div",{className:"settings-tab-note",children:[n.jsx("strong",{children:bt.label}),n.jsx("span",{children:bt.description})]}),se==="system"&&n.jsx(nt,{title:"系统设置",children:n.jsxs("div",{className:"settings-group",children:[n.jsx(Pt,{label:"接口兼容",value:"OpenAI API"}),n.jsx(Pt,{label:"当前默认模型",value:N}),n.jsx(Pt,{label:"已配置渠道",value:`${m.length} 个,${Ne} 个启用`}),n.jsx(Pt,{label:"可选供应商",value:`${eo.length} 种`}),n.jsx(Pt,{label:"运行版本",value:`${ie?.version||"未知"} · ${ie?.commit||"未知"}`}),n.jsx(Pt,{label:"构建时间",value:ie?.buildTime?el(ie.buildTime):"本地构建"}),n.jsx(Pt,{label:"账号自动检测",value:"每 15 分钟自动检测一次"})]})}),se==="cli"&&n.jsxs(nt,{title:"CLI 工具接入",children:[n.jsx("p",{className:"cli-intro",children:"CAPI 兼容 OpenAI 和 Anthropic 协议,常见 AI 命令行工具可直接接入。"}),n.jsxs("div",{className:"cli-credentials",children:[n.jsxs("div",{className:"cli-credential",children:[n.jsx("span",{children:"Base URL"}),n.jsx("code",{children:Ul()}),n.jsx("button",{type:"button",className:"copy-button","aria-label":"复制",onClick:()=>{Ai(Ul()),x("已复制 Base URL")},children:n.jsx(Ot,{name:"copy"})})]}),n.jsxs("div",{className:"cli-credential",children:[n.jsx("span",{children:"API Key"}),n.jsx("code",{children:"cat_你的_api_key"})]})]}),n.jsxs("div",{className:"cli-tools",children:[n.jsxs("details",{className:"cli-tool",open:!0,children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Claude Code"}),n.jsx("span",{children:"Anthropic Messages 协议"})]}),n.jsx("pre",{children:`export ANTHROPIC_BASE_URL="${Ul()}" +`)),B(""),x("Discord 配置已保存")}catch(_){x(_ instanceof Error?_.message:"保存失败,请检查填写内容")}finally{X(!1)}}}async function tl(){try{const _=await pe("/api/account/profile",{method:"PATCH",body:JSON.stringify({username:F,displayName:D,email:fe,discordUserId:Te,currentPassword:Z,newPassword:J})});ge(_.account),me(_.account.username),Ae(_.account.email||""),ue(_.account.discordUserId||""),re(""),T(""),x("管理员账号已保存")}catch(_){x(_ instanceof Error?_.message:"账号设置保存失败")}}async function kt(){X(!0),x("");try{const _=await pe("/api/settings/maintenance",{method:"PATCH",body:JSON.stringify(ne)});le(_.maintenance),x("维护设置已保存,历史数据已按新规则清理")}catch(_){x(_ instanceof Error?_.message:"维护设置保存失败")}finally{X(!1)}}async function cl(){X(!0),x("");try{const _=await fetch("/api/backup",{credentials:"include"});if(!_.ok)throw new Error("备份导出失败");const Ee=await _.blob(),xt=(_.headers.get("Content-Disposition")||"").match(/filename="([^"]+)"/)?.[1]||"capi-backup.json",ft=URL.createObjectURL(Ee),tt=document.createElement("a");tt.href=ft,tt.download=xt,tt.click(),URL.revokeObjectURL(ft),x("备份已导出,请妥善保管")}catch(_){x(_ instanceof Error?_.message:"备份导出失败")}finally{X(!1)}}async function V(_){if(window.confirm("恢复会覆盖当前全部数据,并退出现有登录会话。确定继续?")){X(!0),x("");try{const Ee=await fetch("/api/restore",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:_}),et=await Ee.json().catch(()=>null);if(!Ee.ok)throw new Error(et?.error?.message||"备份恢复失败");x(`已恢复 ${et.users} 个用户、${et.channels} 条渠道和 ${et.models} 个模型,请重新登录`)}catch(Ee){x(Ee instanceof Error?Ee.message:"备份恢复失败")}finally{X(!1)}}}return n.jsxs("div",{className:"settings-layout",children:[n.jsx("div",{className:"settings-tabs",children:Se.map(_=>n.jsxs("button",{type:"button",className:se===_.value?"selected":"",onClick:()=>ve(_.value),children:[n.jsx("strong",{children:_.label}),n.jsx("small",{children:_.description})]},_.value))}),n.jsxs("div",{className:"settings-tab-note",children:[n.jsx("strong",{children:bt.label}),n.jsx("span",{children:bt.description})]}),se==="system"&&n.jsx(nt,{title:"系统设置",children:n.jsxs("div",{className:"settings-group",children:[n.jsx(Pt,{label:"接口兼容",value:"OpenAI API"}),n.jsx(Pt,{label:"当前默认模型",value:N}),n.jsx(Pt,{label:"已配置渠道",value:`${m.length} 个,${Ne} 个启用`}),n.jsx(Pt,{label:"可选供应商",value:`${to.length} 种`}),n.jsx(Pt,{label:"运行版本",value:`${ie?.version||"未知"} · ${ie?.commit||"未知"}`}),n.jsx(Pt,{label:"构建时间",value:ie?.buildTime?el(ie.buildTime):"本地构建"}),n.jsx(Pt,{label:"账号自动检测",value:"每 15 分钟自动检测一次"})]})}),se==="cli"&&n.jsxs(nt,{title:"CLI 工具接入",children:[n.jsx("p",{className:"cli-intro",children:"CAPI 兼容 OpenAI 和 Anthropic 协议,常见 AI 命令行工具可直接接入。"}),n.jsxs("div",{className:"cli-credentials",children:[n.jsxs("div",{className:"cli-credential",children:[n.jsx("span",{children:"Base URL"}),n.jsx("code",{children:Ul()}),n.jsx("button",{type:"button",className:"copy-button","aria-label":"复制",onClick:()=>{Ai(Ul()),x("已复制 Base URL")},children:n.jsx(Ot,{name:"copy"})})]}),n.jsxs("div",{className:"cli-credential",children:[n.jsx("span",{children:"API Key"}),n.jsx("code",{children:"cat_你的_api_key"})]})]}),n.jsxs("div",{className:"cli-tools",children:[n.jsxs("details",{className:"cli-tool",open:!0,children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Claude Code"}),n.jsx("span",{children:"Anthropic Messages 协议"})]}),n.jsx("pre",{children:`export ANTHROPIC_BASE_URL="${Ul()}" export ANTHROPIC_AUTH_TOKEN="cat_你的_api_key" export ANTHROPIC_MODEL="${N}" claude`})]}),n.jsxs("details",{className:"cli-tool",children:[n.jsxs("summary",{children:[n.jsx("strong",{children:"Codex CLI"}),n.jsx("span",{children:"OpenAI Chat 协议"})]}),n.jsxs("p",{children:["编辑 ",n.jsx("code",{children:"~/.codex/config.toml"}),":"]}),n.jsx("pre",{children:`model = "${N}" @@ -40,4 +40,4 @@ client = OpenAI() response = client.chat.completions.create( model="${N}", messages=[{"role": "user", "content": "hello"}] -)`})]})]}),d&&n.jsx("p",{className:"cli-message",role:"status",children:d})]}),se==="maintenance"&&n.jsx(nt,{title:"维护设置",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"日志保留天数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"1",max:"3650",value:ne.logRetentionDays,onChange:_=>le(Ee=>({...Ee,logRetentionDays:Number(_.target.value)}))})})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"日志最大条数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"100",max:"1000000",step:"100",value:ne.maxLogs,onChange:_=>le(Ee=>({...Ee,maxLogs:Number(_.target.value)}))})})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"额度流水最大条数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"100",max:"2000000",step:"100",value:ne.maxQuotaEntries,onChange:_=>le(Ee=>({...Ee,maxQuotaEntries:Number(_.target.value)}))})})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:d}),n.jsx("button",{type:"button",className:"primary-button",disabled:G,onClick:kt,children:G?"保存中":"保存维护设置"})]})]})}),se==="backup"&&n.jsx(nt,{title:"备份与恢复",children:n.jsx("div",{className:"settings-group",children:n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["备份与恢复",n.jsx("small",{children:"包含账号哈希和加密后的上游密钥,恢复时需要相同的 SECRET_KEY"})]}),n.jsxs("div",{className:"setting-value backup-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",disabled:G,onClick:cl,children:"导出备份"}),n.jsxs("label",{className:"secondary-button",children:["恢复备份",n.jsx("input",{type:"file",accept:"application/json,.json",disabled:G,onChange:_=>{const Ee=_.target.files?.[0];Ee&&V(Ee),_.target.value=""}})]})]})]})})}),se==="auth"&&n.jsx(nt,{title:"账号与注册",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"开放用户注册"}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:E?"启用":"关闭"}),n.jsx("button",{type:"button",className:E?"ios-switch is-on":"ios-switch","aria-label":E?"关闭用户注册":"开放用户注册","aria-pressed":!!E,onClick:Ke,children:n.jsx("span",{})})]})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"注册方式"}),n.jsx("div",{className:"registration-mode-control",role:"group","aria-label":"注册方式",children:[{value:"username",label:"账号密码"},{value:"email",label:"邮箱"},{value:"discord",label:"Discord"}].map(_=>n.jsx("button",{type:"button",className:$===_.value?"selected":"",onClick:()=>I(E??!0,_.value),children:_.label},_.value))})]}),n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["新用户初始额度",n.jsx("small",{children:"注册完成后自动发放,仅影响之后的新用户"})]}),n.jsxs("div",{className:"setting-value auth-default-balance",children:[n.jsx("input",{type:"number",min:"0",step:"0.01",value:y,onChange:_=>R(_.target.value),"aria-label":"新用户初始额度"}),n.jsx("button",{type:"button",className:"secondary-button",onClick:()=>I(E,$,Number(y)),children:"保存"})]})]}),n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["默认注册分组",n.jsx("small",{children:"新注册用户自动归入该分组,决定他们能用哪些渠道"})]}),n.jsxs("div",{className:"setting-value auth-default-balance",children:[n.jsxs("select",{value:z,onChange:_=>P(_.target.value),"aria-label":"默认注册分组",children:[h.map(_=>n.jsx("option",{value:_.id,children:_.name},_.id)),h.length===0&&n.jsx("option",{value:"",children:"暂无分组"})]}),n.jsx("button",{type:"button",className:"secondary-button",disabled:h.length===0,onClick:()=>I(E,$,Number(y),z),children:"保存"})]})]})]})}),se==="check-in"&&n.jsx(nt,{title:"每日签到奖励",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["开放每日签到",n.jsx("small",{children:"用户每天可领取一次随机额度,按北京时间刷新"})]}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:ee.enabled?"启用":"关闭"}),n.jsx("button",{type:"button",className:ee.enabled?"ios-switch is-on":"ios-switch","aria-label":ee.enabled?"关闭每日签到":"开放每日签到","aria-pressed":ee.enabled,onClick:()=>de(_=>({..._,enabled:!_.enabled})),children:n.jsx("span",{})})]})]}),n.jsxs("div",{className:"setting check-in-settings-row",children:[n.jsxs("span",{children:["随机奖励范围",n.jsx("small",{children:"领取金额精确到 0.01,直接计入用户余额和额度流水"})]}),n.jsxs("div",{className:"check-in-reward-inputs",children:[n.jsxs("label",{children:[n.jsx("span",{children:"最低"}),n.jsx("input",{type:"number",min:"0.01",max:"1000000",step:"0.01",value:ee.minReward,onChange:_=>de(Ee=>({...Ee,minReward:Number(_.target.value)}))})]}),n.jsxs("label",{children:[n.jsx("span",{children:"最高"}),n.jsx("input",{type:"number",min:"0.01",max:"1000000",step:"0.01",value:ee.maxReward,onChange:_=>de(Ee=>({...Ee,maxReward:Number(_.target.value)}))})]})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:d}),n.jsx("button",{type:"button",className:"primary-button",disabled:G,onClick:We,children:G?"保存中":"保存签到设置"})]})]})}),se==="admin"&&n.jsx(nt,{title:"管理员账号",children:n.jsxs("form",{className:"discord-settings",onSubmit:_=>{_.preventDefault(),tl()},children:[n.jsxs("div",{className:"settings-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"登录账号"}),n.jsx("input",{value:F,onChange:_=>me(_.target.value),autoComplete:"username"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"显示名称"}),n.jsx("input",{value:D,onChange:_=>ae(_.target.value),autoComplete:"name"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"邮箱"}),n.jsx("input",{type:"email",value:fe,onChange:_=>Ae(_.target.value),autoComplete:"email"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"Discord 用户 ID(可选)"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:Te,onChange:_=>ue(_.target.value),placeholder:Y?.discordUserId?"已绑定":"输入管理员的 Discord 用户 ID"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"当前密码"}),n.jsx("input",{type:"password",value:Z,onChange:_=>re(_.target.value),autoComplete:"current-password",placeholder:"修改密码时填写"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"新密码"}),n.jsx("input",{type:"password",value:J,onChange:_=>T(_.target.value),autoComplete:"new-password",placeholder:"留空表示不修改"})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:d}),n.jsx("button",{className:"primary-button",type:"submit",children:"保存账号"})]})]})}),se==="discord"&&n.jsx(nt,{title:"Discord 登录",children:r?n.jsxs("form",{className:"discord-settings",autoComplete:"off",onSubmit:_=>{_.preventDefault(),Pe()},children:[n.jsxs("div",{className:"discord-toggle-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"Discord 登录"}),n.jsx("span",{children:r.enabled?"已启用":"未启用"})]}),n.jsx("button",{type:"button",className:r.enabled?"ios-switch is-on":"ios-switch","aria-label":r.enabled?"停用 Discord 登录":"启用 Discord 登录","aria-pressed":r.enabled,onClick:()=>A({...r,enabled:!r.enabled}),children:n.jsx("span",{})})]}),n.jsxs("div",{className:"settings-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"Client ID"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:r.clientId,onChange:_=>A({...r,clientId:_.target.value}),placeholder:"100000000000000001"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"Client Secret"}),n.jsx("input",{type:"password",autoComplete:"new-password",value:k,onChange:_=>B(_.target.value),placeholder:r.clientSecretSet?"已设置,留空表示不修改":"粘贴 Discord Client Secret"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"回调地址"}),n.jsx("input",{type:"url",value:r.redirectUri,onChange:_=>A({...r,redirectUri:_.target.value}),placeholder:"https://你的域名/api/auth/discord/callback"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"服务器 ID"}),n.jsx("input",{inputMode:"numeric",value:r.allowedGuildId,onChange:_=>A({...r,allowedGuildId:_.target.value}),placeholder:"允许登录的服务器 ID"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"身份组 ID"}),n.jsx("input",{inputMode:"numeric",value:r.allowedRoleId,onChange:_=>A({...r,allowedRoleId:_.target.value}),placeholder:"允许登录的身份组 ID"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"拉黑服务器 ID"}),n.jsx("textarea",{value:Q,onChange:_=>O(_.target.value),placeholder:"每行一个服务器 ID;命中的用户禁止注册 / 登录",rows:3}),n.jsx("small",{children:"用户若加入了这些 Discord 服务器中的任意一个,将无法注册或登录(优先于上面的允许规则)。"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"登录成功跳转地址"}),n.jsx("input",{type:"url",value:r.authSuccessUrl,onChange:_=>A({...r,authSuccessUrl:_.target.value}),placeholder:"https://你的域名/"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"登录有效期(小时)"}),n.jsx("input",{type:"number",min:"1",max:"8760",value:r.sessionTtlHours,onChange:_=>A({...r,sessionTtlHours:Number(_.target.value)})})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:d}),n.jsx("button",{className:"primary-button",type:"submit",disabled:G,children:G?"保存中":"保存配置"})]})]}):n.jsx("div",{className:"empty",children:"正在读取配置"})})]})}function ul({label:c,value:m}){return n.jsxs("div",{className:"metric",children:[n.jsx("span",{children:c}),n.jsx("strong",{children:m})]})}function Qp({groups:c,onCreate:m,onUpdate:h,onDelete:r}){const[A,E]=g.useState(""),[L,$]=g.useState(""),[C,y]=g.useState(!1);async function R(z){if(z.preventDefault(),!!A.trim()){y(!0);try{await m({name:A.trim(),description:L.trim()}),E(""),$("")}finally{y(!1)}}}return n.jsxs("section",{className:"models-page",children:[n.jsxs(nt,{title:"用户分组",children:[n.jsxs("form",{className:"channel-create-form",onSubmit:R,children:[n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"分组名称"}),n.jsx("input",{value:A,onChange:z=>E(z.target.value),placeholder:"例如 尊享用户 / 试用用户"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"说明"}),n.jsx("input",{value:L,onChange:z=>$(z.target.value),placeholder:"可选"})]})]}),n.jsx("div",{className:"channel-card-actions",children:n.jsx("button",{className:"primary-button",type:"submit",disabled:C||!A.trim(),children:C?"创建中":"创建分组"})})]}),n.jsx("p",{className:"muted-inline",children:"分组用于控制渠道对用户的可见范围:把用户归入分组,并在渠道上勾选「可见分组」即可限制访问。未分组的用户只能使用未限制分组的渠道。"})]}),n.jsx(nt,{title:"全部分组",children:c.length===0?n.jsx(Lt,{text:"还没有分组"}):n.jsx("div",{className:"channels-stack",children:c.map(z=>n.jsx(Xp,{group:z,onUpdate:h,onDelete:r},z.id))})})]})}function Xp({group:c,onUpdate:m,onDelete:h}){const[r,A]=g.useState(!1),[E,L]=g.useState(c.name),[$,C]=g.useState(c.description),[y,R]=g.useState(!1);async function z(){R(!0);try{await m(c.id,{name:E.trim(),description:$.trim()}),A(!1)}finally{R(!1)}}return n.jsx("div",{className:"channel-card",children:n.jsxs("div",{className:"channel-card-head",children:[n.jsx("div",{children:r?n.jsxs("div",{className:"group-edit-fields",children:[n.jsx("input",{value:E,onChange:P=>L(P.target.value),placeholder:"分组名称"}),n.jsx("input",{value:$,onChange:P=>C(P.target.value),placeholder:"说明"})]}):n.jsxs(n.Fragment,{children:[n.jsx("strong",{children:c.name}),c.description&&n.jsx("span",{children:c.description}),n.jsxs("small",{children:["创建于 ",el(c.createdAt)]})]})}),n.jsx("div",{className:"channel-card-head-actions",children:r?n.jsxs(n.Fragment,{children:[n.jsx("button",{className:"primary-button compact-button",onClick:z,disabled:y||!E.trim(),children:y?"保存中":"保存"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>{L(c.name),C(c.description),A(!1)},children:"取消"})]}):n.jsxs(n.Fragment,{children:[n.jsx("button",{className:"secondary-button compact-button",onClick:()=>A(!0),children:"重命名"}),n.jsx("button",{className:"danger-button compact-button",onClick:()=>h(c.id),children:"删除"})]})})]})})}function nt({title:c,children:m}){return n.jsxs("section",{className:"panel",children:[n.jsx("div",{className:"panel-title",children:n.jsx("h2",{children:c})}),m]})}function Dt({tone:c,children:m}){return n.jsx("span",{className:`badge tone-${c}`,children:m})}function Pt({label:c,value:m,switchOn:h}){return n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:c}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:m}),typeof h=="boolean"&&n.jsx("div",{className:h?"ios-switch is-on":"ios-switch","aria-hidden":"true",children:n.jsx("span",{})})]})]})}function Kp({value:c,options:m,onChange:h}){return n.jsx("div",{className:"segmented-control",children:m.map(r=>n.jsx("button",{className:c===r.value?"selected":"",onClick:()=>h(r.value),children:r.label},r.value))})}function Lt({text:c}){return n.jsx("div",{className:"empty",children:c})}V0.createRoot(document.getElementById("root")).render(n.jsx(Y0.StrictMode,{children:n.jsx(rp,{})})); +)`})]})]}),d&&n.jsx("p",{className:"cli-message",role:"status",children:d})]}),se==="maintenance"&&n.jsx(nt,{title:"维护设置",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"日志保留天数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"1",max:"3650",value:ne.logRetentionDays,onChange:_=>le(Ee=>({...Ee,logRetentionDays:Number(_.target.value)}))})})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"日志最大条数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"100",max:"1000000",step:"100",value:ne.maxLogs,onChange:_=>le(Ee=>({...Ee,maxLogs:Number(_.target.value)}))})})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"额度流水最大条数"}),n.jsx("div",{className:"setting-value maintenance-control",children:n.jsx("input",{type:"number",min:"100",max:"2000000",step:"100",value:ne.maxQuotaEntries,onChange:_=>le(Ee=>({...Ee,maxQuotaEntries:Number(_.target.value)}))})})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:d}),n.jsx("button",{type:"button",className:"primary-button",disabled:G,onClick:kt,children:G?"保存中":"保存维护设置"})]})]})}),se==="backup"&&n.jsx(nt,{title:"备份与恢复",children:n.jsx("div",{className:"settings-group",children:n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["备份与恢复",n.jsx("small",{children:"包含账号哈希和加密后的上游密钥,恢复时需要相同的 SECRET_KEY"})]}),n.jsxs("div",{className:"setting-value backup-actions",children:[n.jsx("button",{type:"button",className:"secondary-button",disabled:G,onClick:cl,children:"导出备份"}),n.jsxs("label",{className:"secondary-button",children:["恢复备份",n.jsx("input",{type:"file",accept:"application/json,.json",disabled:G,onChange:_=>{const Ee=_.target.files?.[0];Ee&&V(Ee),_.target.value=""}})]})]})]})})}),se==="auth"&&n.jsx(nt,{title:"账号与注册",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"开放用户注册"}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:E?"启用":"关闭"}),n.jsx("button",{type:"button",className:E?"ios-switch is-on":"ios-switch","aria-label":E?"关闭用户注册":"开放用户注册","aria-pressed":!!E,onClick:Ke,children:n.jsx("span",{})})]})]}),n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:"注册方式"}),n.jsx("div",{className:"registration-mode-control",role:"group","aria-label":"注册方式",children:[{value:"username",label:"账号密码"},{value:"email",label:"邮箱"},{value:"discord",label:"Discord"}].map(_=>n.jsx("button",{type:"button",className:$===_.value?"selected":"",onClick:()=>I(E??!0,_.value),children:_.label},_.value))})]}),n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["新用户初始额度",n.jsx("small",{children:"注册完成后自动发放,仅影响之后的新用户"})]}),n.jsxs("div",{className:"setting-value auth-default-balance",children:[n.jsx("input",{type:"number",min:"0",step:"0.01",value:y,onChange:_=>R(_.target.value),"aria-label":"新用户初始额度"}),n.jsx("button",{type:"button",className:"secondary-button",onClick:()=>I(E,$,Number(y)),children:"保存"})]})]}),n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["默认注册分组",n.jsx("small",{children:"新注册用户自动归入该分组,决定他们能用哪些渠道"})]}),n.jsxs("div",{className:"setting-value auth-default-balance",children:[n.jsxs("select",{value:z,onChange:_=>P(_.target.value),"aria-label":"默认注册分组",children:[h.map(_=>n.jsx("option",{value:_.id,children:_.name},_.id)),h.length===0&&n.jsx("option",{value:"",children:"暂无分组"})]}),n.jsx("button",{type:"button",className:"secondary-button",disabled:h.length===0,onClick:()=>I(E,$,Number(y),z),children:"保存"})]})]})]})}),se==="check-in"&&n.jsx(nt,{title:"每日签到奖励",children:n.jsxs("div",{className:"settings-group",children:[n.jsxs("div",{className:"setting",children:[n.jsxs("span",{children:["开放每日签到",n.jsx("small",{children:"用户每天可领取一次随机额度,按北京时间刷新"})]}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:ee.enabled?"启用":"关闭"}),n.jsx("button",{type:"button",className:ee.enabled?"ios-switch is-on":"ios-switch","aria-label":ee.enabled?"关闭每日签到":"开放每日签到","aria-pressed":ee.enabled,onClick:()=>de(_=>({..._,enabled:!_.enabled})),children:n.jsx("span",{})})]})]}),n.jsxs("div",{className:"setting check-in-settings-row",children:[n.jsxs("span",{children:["随机奖励范围",n.jsx("small",{children:"领取金额精确到 0.01,直接计入用户余额和额度流水"})]}),n.jsxs("div",{className:"check-in-reward-inputs",children:[n.jsxs("label",{children:[n.jsx("span",{children:"最低"}),n.jsx("input",{type:"number",min:"0.01",max:"1000000",step:"0.01",value:ee.minReward,onChange:_=>de(Ee=>({...Ee,minReward:Number(_.target.value)}))})]}),n.jsxs("label",{children:[n.jsx("span",{children:"最高"}),n.jsx("input",{type:"number",min:"0.01",max:"1000000",step:"0.01",value:ee.maxReward,onChange:_=>de(Ee=>({...Ee,maxReward:Number(_.target.value)}))})]})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:d}),n.jsx("button",{type:"button",className:"primary-button",disabled:G,onClick:We,children:G?"保存中":"保存签到设置"})]})]})}),se==="admin"&&n.jsx(nt,{title:"管理员账号",children:n.jsxs("form",{className:"discord-settings",onSubmit:_=>{_.preventDefault(),tl()},children:[n.jsxs("div",{className:"settings-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"登录账号"}),n.jsx("input",{value:F,onChange:_=>me(_.target.value),autoComplete:"username"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"显示名称"}),n.jsx("input",{value:D,onChange:_=>ae(_.target.value),autoComplete:"name"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"邮箱"}),n.jsx("input",{type:"email",value:fe,onChange:_=>Ae(_.target.value),autoComplete:"email"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"Discord 用户 ID(可选)"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:Te,onChange:_=>ue(_.target.value),placeholder:Y?.discordUserId?"已绑定":"输入管理员的 Discord 用户 ID"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"当前密码"}),n.jsx("input",{type:"password",value:Z,onChange:_=>re(_.target.value),autoComplete:"current-password",placeholder:"修改密码时填写"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"新密码"}),n.jsx("input",{type:"password",value:J,onChange:_=>T(_.target.value),autoComplete:"new-password",placeholder:"留空表示不修改"})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:d}),n.jsx("button",{className:"primary-button",type:"submit",children:"保存账号"})]})]})}),se==="discord"&&n.jsx(nt,{title:"Discord 登录",children:r?n.jsxs("form",{className:"discord-settings",autoComplete:"off",onSubmit:_=>{_.preventDefault(),Pe()},children:[n.jsxs("div",{className:"discord-toggle-row",children:[n.jsxs("div",{children:[n.jsx("strong",{children:"Discord 登录"}),n.jsx("span",{children:r.enabled?"已启用":"未启用"})]}),n.jsx("button",{type:"button",className:r.enabled?"ios-switch is-on":"ios-switch","aria-label":r.enabled?"停用 Discord 登录":"启用 Discord 登录","aria-pressed":r.enabled,onClick:()=>A({...r,enabled:!r.enabled}),children:n.jsx("span",{})})]}),n.jsxs("div",{className:"settings-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"Client ID"}),n.jsx("input",{inputMode:"numeric",autoComplete:"off",value:r.clientId,onChange:_=>A({...r,clientId:_.target.value}),placeholder:"100000000000000001"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"Client Secret"}),n.jsx("input",{type:"password",autoComplete:"new-password",value:k,onChange:_=>B(_.target.value),placeholder:r.clientSecretSet?"已设置,留空表示不修改":"粘贴 Discord Client Secret"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"回调地址"}),n.jsx("input",{type:"url",value:r.redirectUri,onChange:_=>A({...r,redirectUri:_.target.value}),placeholder:"https://你的域名/api/auth/discord/callback"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"服务器 ID"}),n.jsx("input",{inputMode:"numeric",value:r.allowedGuildId,onChange:_=>A({...r,allowedGuildId:_.target.value}),placeholder:"允许登录的服务器 ID"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"身份组 ID"}),n.jsx("input",{inputMode:"numeric",value:r.allowedRoleId,onChange:_=>A({...r,allowedRoleId:_.target.value}),placeholder:"允许登录的身份组 ID"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"拉黑服务器 ID"}),n.jsx("textarea",{value:Q,onChange:_=>O(_.target.value),placeholder:"每行一个服务器 ID;命中的用户禁止注册 / 登录",rows:3}),n.jsx("small",{children:"用户若加入了这些 Discord 服务器中的任意一个,将无法注册或登录(优先于上面的允许规则)。"})]}),n.jsxs("label",{className:"settings-form-wide",children:[n.jsx("span",{children:"登录成功跳转地址"}),n.jsx("input",{type:"url",value:r.authSuccessUrl,onChange:_=>A({...r,authSuccessUrl:_.target.value}),placeholder:"https://你的域名/"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"登录有效期(小时)"}),n.jsx("input",{type:"number",min:"1",max:"8760",value:r.sessionTtlHours,onChange:_=>A({...r,sessionTtlHours:Number(_.target.value)})})]})]}),n.jsxs("div",{className:"settings-save-row",children:[n.jsx("span",{role:"status",children:d}),n.jsx("button",{className:"primary-button",type:"submit",disabled:G,children:G?"保存中":"保存配置"})]})]}):n.jsx("div",{className:"empty",children:"正在读取配置"})})]})}function ul({label:u,value:m}){return n.jsxs("div",{className:"metric",children:[n.jsx("span",{children:u}),n.jsx("strong",{children:m})]})}function Kp({groups:u,onCreate:m,onUpdate:h,onDelete:r}){const[A,E]=g.useState(""),[L,$]=g.useState(""),[C,y]=g.useState(!1);async function R(z){if(z.preventDefault(),!!A.trim()){y(!0);try{await m({name:A.trim(),description:L.trim()}),E(""),$("")}finally{y(!1)}}}return n.jsxs("section",{className:"models-page",children:[n.jsxs(nt,{title:"用户分组",children:[n.jsxs("form",{className:"channel-create-form",onSubmit:R,children:[n.jsxs("div",{className:"channel-form-grid",children:[n.jsxs("label",{children:[n.jsx("span",{children:"分组名称"}),n.jsx("input",{value:A,onChange:z=>E(z.target.value),placeholder:"例如 尊享用户 / 试用用户"})]}),n.jsxs("label",{children:[n.jsx("span",{children:"说明"}),n.jsx("input",{value:L,onChange:z=>$(z.target.value),placeholder:"可选"})]})]}),n.jsx("div",{className:"channel-card-actions",children:n.jsx("button",{className:"primary-button",type:"submit",disabled:C||!A.trim(),children:C?"创建中":"创建分组"})})]}),n.jsx("p",{className:"muted-inline",children:"分组用于控制渠道对用户的可见范围:把用户归入分组,并在渠道上勾选「可见分组」即可限制访问。未分组的用户只能使用未限制分组的渠道。"})]}),n.jsx(nt,{title:"全部分组",children:u.length===0?n.jsx(Lt,{text:"还没有分组"}):n.jsx("div",{className:"channels-stack",children:u.map(z=>n.jsx(Zp,{group:z,onUpdate:h,onDelete:r},z.id))})})]})}function Zp({group:u,onUpdate:m,onDelete:h}){const[r,A]=g.useState(!1),[E,L]=g.useState(u.name),[$,C]=g.useState(u.description),[y,R]=g.useState(!1);async function z(){R(!0);try{await m(u.id,{name:E.trim(),description:$.trim()}),A(!1)}finally{R(!1)}}return n.jsx("div",{className:"channel-card",children:n.jsxs("div",{className:"channel-card-head",children:[n.jsx("div",{children:r?n.jsxs("div",{className:"group-edit-fields",children:[n.jsx("input",{value:E,onChange:P=>L(P.target.value),placeholder:"分组名称"}),n.jsx("input",{value:$,onChange:P=>C(P.target.value),placeholder:"说明"})]}):n.jsxs(n.Fragment,{children:[n.jsx("strong",{children:u.name}),u.description&&n.jsx("span",{children:u.description}),n.jsxs("small",{children:["创建于 ",el(u.createdAt)]})]})}),n.jsx("div",{className:"channel-card-head-actions",children:r?n.jsxs(n.Fragment,{children:[n.jsx("button",{className:"primary-button compact-button",onClick:z,disabled:y||!E.trim(),children:y?"保存中":"保存"}),n.jsx("button",{className:"secondary-button compact-button",onClick:()=>{L(u.name),C(u.description),A(!1)},children:"取消"})]}):n.jsxs(n.Fragment,{children:[n.jsx("button",{className:"secondary-button compact-button",onClick:()=>A(!0),children:"重命名"}),n.jsx("button",{className:"danger-button compact-button",onClick:()=>h(u.id),children:"删除"})]})})]})})}function nt({title:u,children:m}){return n.jsxs("section",{className:"panel",children:[n.jsx("div",{className:"panel-title",children:n.jsx("h2",{children:u})}),m]})}function Dt({tone:u,children:m}){return n.jsx("span",{className:`badge tone-${u}`,children:m})}function Pt({label:u,value:m,switchOn:h}){return n.jsxs("div",{className:"setting",children:[n.jsx("span",{children:u}),n.jsxs("div",{className:"setting-value",children:[n.jsx("strong",{children:m}),typeof h=="boolean"&&n.jsx("div",{className:h?"ios-switch is-on":"ios-switch","aria-hidden":"true",children:n.jsx("span",{})})]})]})}function Vp({value:u,options:m,onChange:h}){return n.jsx("div",{className:"segmented-control",children:m.map(r=>n.jsx("button",{className:u===r.value?"selected":"",onClick:()=>h(r.value),children:r.label},r.value))})}function Lt({text:u}){return n.jsx("div",{className:"empty",children:u})}J0.createRoot(document.getElementById("root")).render(n.jsx(L0.StrictMode,{children:n.jsx(fp,{})})); diff --git a/dist/index.html b/dist/index.html index 77b934f..7db8b92 100644 --- a/dist/index.html +++ b/dist/index.html @@ -5,7 +5,7 @@ CAPI - + diff --git a/src/App.tsx b/src/App.tsx index 453c5a6..f1a2b51 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -446,6 +446,7 @@ const navItems = [ const providerOptions = [ { value: "kiro", label: "Kiro / Amazon Q" }, { value: "codex", label: "Codex / ChatGPT OAuth" }, + { value: "antigravity", label: "Antigravity / Google" }, { value: "cpa", label: "CPA / CLIProxyAPI" }, { value: "openai", label: "OpenAI" }, { value: "anthropic", label: "Anthropic / Claude" }, @@ -466,6 +467,8 @@ const defaultCodexModels = "gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, g const defaultOpenAIModels = "gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-image-2"; const defaultCPAModels = "gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, claude-sonnet-4, gemini-3.1-pro"; const defaultKiroModels = "claude-sonnet-4.5, claude-sonnet-4, claude-haiku-4.5, claude-opus-4.5"; +const defaultAntigravityBaseURL = "https://daily-cloudcode-pa.googleapis.com"; +const defaultAntigravityModels = "claude-opus-4-6-thinking, claude-sonnet-4-6, gemini-3.8-flash-high, gemini-3.7-flash-high, gemini-3.6-flash-high, gemini-3-flash, gemini-pro-agent, gemini-3.1-pro-low, gpt-oss-120b-medium, gemini-3.1-flash-lite, gemini-3.5-flash-lite, gemini-3.1-flash-image"; const channelTemplates = [ { @@ -489,6 +492,13 @@ const channelTemplates = [ baseUrl: defaultCodexBaseURL, models: defaultCodexModels.split(",").map((model) => model.trim()) }, + { + provider: "antigravity", + label: "Antigravity 账号池", + name: "Antigravity 账号池", + baseUrl: defaultAntigravityBaseURL, + models: defaultAntigravityModels.split(",").map((model) => model.trim()) + }, { provider: "cpa", label: "CPA / CLIProxyAPI", @@ -563,6 +573,7 @@ function accountErrorLabel(code?: string) { function defaultBaseURLForProvider(provider: string) { if (provider === "openai") return defaultOpenAIBaseURL; if (provider === "codex") return defaultCodexBaseURL; + if (provider === "antigravity") return defaultAntigravityBaseURL; if (provider === "cpa" || provider === "cliproxyapi") return defaultCPABaseURL; if (provider === "kiro") return defaultKiroBaseURL; return ""; @@ -733,6 +744,7 @@ function ProviderIcon({ provider }: { provider: string }) { ); } const mark = provider === "codex" ? "C" + : provider === "antigravity" ? "G" : provider === "cpa" || provider === "cliproxyapi" ? "CPA" : provider === "anthropic" ? "A" : provider === "google" ? "✦" @@ -3054,7 +3066,7 @@ function DrawingView({ onStartOAuth: (channelId: string) => Promise<{ authorizeUrl: string; state: string; redirectUri: string }>; onCompleteOAuth: (channelId: string, payload: { callbackUrl?: string; code?: string; state?: string }) => Promise; }) { - const drawingChannels = channels.filter((channel) => channel.provider === "codex" || channel.provider === "openai" || arrayOf(channel.models).some((model) => model.includes("image"))); + const drawingChannels = channels.filter((channel) => channel.provider === "codex" || channel.provider === "antigravity" || channel.provider === "openai" || arrayOf(channel.models).some((model) => model.includes("image"))); const [busy, setBusy] = useState(""); const [accountVisibleCounts, setAccountVisibleCounts] = useState>({}); const [accountFilters, setAccountFilters] = useState>({}); @@ -3151,6 +3163,7 @@ function DrawingView({
账号有两种来源,任选其一即可。 +