ai-zero-token 2.0.3 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{a as e,n as t,r as n,t as r}from"./jsx-runtime-DqpGtLhh.js";import{t as i}from"./activity-D21-Xrc4.js";import{t as a}from"./circle-check-ZYtn9GqY.js";import{t as o}from"./clock-3-BzDANsVk.js";import{t as s}from"./refresh-cw-CAAH2rqe.js";import{t as c}from"./server-BrjJPb9D.js";import{g as l,m as u,p as ee}from"./index-DRe-tByu.js";var d=t(`circle-x`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m15 9-6 6`,key:`1uzhvr`}],[`path`,{d:`m9 9 6 6`,key:`z0biqf`}]]),f=t(`map-pin`,[[`path`,{d:`M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0`,key:`1r0f0z`}],[`circle`,{cx:`12`,cy:`10`,r:`3`,key:`ilqhr7`}]]),p=t(`triangle-alert`,[[`path`,{d:`m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3`,key:`wmoenq`}],[`path`,{d:`M12 9v4`,key:`juzpu7`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]),m=e(n(),1),h=`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eClaude%3c/title%3e%3cpath%20d='m4.7144%2015.9555%204.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608%201.5179.1032%202.2767.1578%201.6514.0972%202.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973%209.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686%201.9064%201.4754%202.4893%201.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335%206.6997%200l.9957.1336.419.3642.6192%201.4147%201.0018%202.2282%201.5543%203.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853%201.8517-.5586%202.9021-.3643%201.9429h.2125l.2429-.2429.9835-1.3053%201.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759%201.1293-.34%201.1657-1.0625%201.3478-.8804%201.1414-1.2628%201.7-.7893%201.36.0729.1093.1882-.0183%202.8535-.607%201.5421-.2794%201.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607%201.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929%201.0686%202.0035%201.8092%202.5075%202.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496%202.3436%203.5214.1214%201.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38%2017.959l-1.1414-1.9428-.1397.079-.674%207.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328%201.9672-2.1796%202.9446-1.7243%201.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889%202.386-3.0357%201.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385%204.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429%201.9064-1.3114Z'/%3e%3c/svg%3e`,g=`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eOpenAI%3c/title%3e%3cpath%20d='M22.2819%209.8211a5.9847%205.9847%200%200%200-.5157-4.9108%206.0462%206.0462%200%200%200-6.5098-2.9A6.0651%206.0651%200%200%200%204.9807%204.1818a5.9847%205.9847%200%200%200-3.9977%202.9%206.0462%206.0462%200%200%200%20.7427%207.0966%205.98%205.98%200%200%200%20.511%204.9107%206.051%206.051%200%200%200%206.5146%202.9001A5.9847%205.9847%200%200%200%2013.2599%2024a6.0557%206.0557%200%200%200%205.7718-4.2058%205.9894%205.9894%200%200%200%203.9977-2.9001%206.0557%206.0557%200%200%200-.7475-7.0729zm-9.022%2012.6081a4.4755%204.4755%200%200%201-2.8764-1.0408l.1419-.0804%204.7783-2.7582a.7948.7948%200%200%200%20.3927-.6813v-6.7369l2.02%201.1686a.071.071%200%200%201%20.038.052v5.5826a4.504%204.504%200%200%201-4.4945%204.4944zm-9.6607-4.1254a4.4708%204.4708%200%200%201-.5346-3.0137l.142.0852%204.783%202.7582a.7712.7712%200%200%200%20.7806%200l5.8428-3.3685v2.3324a.0804.0804%200%200%201-.0332.0615L9.74%2019.9502a4.4992%204.4992%200%200%201-6.1408-1.6464zM2.3408%207.8956a4.485%204.485%200%200%201%202.3655-1.9728V11.6a.7664.7664%200%200%200%20.3879.6765l5.8144%203.3543-2.0201%201.1685a.0757.0757%200%200%201-.071%200l-4.8303-2.7865A4.504%204.504%200%200%201%202.3408%207.872zm16.5963%203.8558L13.1038%208.364%2015.1192%207.2a.0757.0757%200%200%201%20.071%200l4.8303%202.7913a4.4944%204.4944%200%200%201-.6765%208.1042v-5.6772a.79.79%200%200%200-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759%200%200%200-.7854%200L9.409%209.2297V6.8974a.0662.0662%200%200%201%20.0284-.0615l4.8303-2.7866a4.4992%204.4992%200%200%201%206.6802%204.66zM8.3065%2012.863l-2.02-1.1638a.0804.0804%200%200%201-.038-.0567V6.0742a4.4992%204.4992%200%200%201%207.3757-3.4537l-.142.0805L8.704%205.459a.7948.7948%200%200%200-.3927.6813zm1.0976-2.3654l2.602-1.4998%202.6069%201.4998v2.9994l-2.5974%201.4997-2.6067-1.4997Z'/%3e%3c/svg%3e`,_=`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eGoogle%3c/title%3e%3cpath%20d='M12.48%2010.92v3.28h7.84c-.24%201.84-.853%203.187-1.787%204.133-1.147%201.147-2.933%202.4-6.053%202.4-4.827%200-8.6-3.893-8.6-8.72s3.773-8.72%208.6-8.72c2.6%200%204.507%201.027%205.907%202.347l2.307-2.307C18.747%201.44%2016.133%200%2012.48%200%205.867%200%20.307%205.387.307%2012s5.56%2012%2012.173%2012c3.573%200%206.267-1.173%208.373-3.36%202.16-2.16%202.84-5.213%202.84-7.667%200-.76-.053-1.467-.173-2.053H12.48z'/%3e%3c/svg%3e`,v=`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eX%3c/title%3e%3cpath%20d='M14.234%2010.162%2022.977%200h-2.072l-7.591%208.824L7.251%200H.258l9.168%2013.343L.258%2024H2.33l8.016-9.318L16.749%2024h6.993zm-2.837%203.299-.929-1.329L3.076%201.56h3.182l5.965%208.532.929%201.329%207.754%2011.09h-3.182z'/%3e%3c/svg%3e`,y=`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eYouTube%3c/title%3e%3cpath%20d='M23.498%206.186a3.016%203.016%200%200%200-2.122-2.136C19.505%203.545%2012%203.545%2012%203.545s-7.505%200-9.377.505A3.017%203.017%200%200%200%20.502%206.186C0%208.07%200%2012%200%2012s0%203.93.502%205.814a3.016%203.016%200%200%200%202.122%202.136c1.871.505%209.376.505%209.376.505s7.505%200%209.377-.505a3.015%203.015%200%200%200%202.122-2.136C24%2015.93%2024%2012%2024%2012s0-3.93-.502-5.814zM9.545%2015.568V8.432L15.818%2012l-6.273%203.568z'/%3e%3c/svg%3e`,b=r(),x={claude:h,chatgpt:g,google:_,x:v,youtube:y};function S(e){return`tone-${e}`}function C(e){try{return new URL(e).hostname.replace(/^www\./i,``)}catch{return e}}function w(e){return/^(10|127|169\.254|172\.(1[6-9]|2\d|3[0-1])|192\.168)\./.test(e)||/^100\.(6[4-9]|[7-9]\d|1\d\d|2[0-3]\d|24[0-7])\./.test(e)||/^198\.(18|19)\./.test(e)||/^192\.0\.2\./.test(e)||/^198\.51\.100\./.test(e)||/^203\.0\.113\./.test(e)||/^fc00:/i.test(e)||/^fd00:/i.test(e)||/^fe80:/i.test(e)||/^::1$/.test(e)}function T(e){let t=e.match(/Electron\/([\d.]+)/i);if(t)return`Electron ${t[1]}`;let n=e.match(/Chrome\/([\d.]+)/i);if(n&&/Safari\//i.test(e))return`Chrome ${n[1].split(`.`)[0]}`;let r=e.match(/Version\/([\d.]+).*Safari\//i);if(r&&!/Chrome\//i.test(e))return`Safari ${r[1].split(`.`)[0]}`;let i=e.match(/Firefox\/([\d.]+)/i);return i?`Firefox ${i[1].split(`.`)[0]}`:e.slice(0,40)}async function E(){if(typeof RTCPeerConnection>`u`)return{status:`不支持`,detail:`当前环境不支持 WebRTC。`,tone:`orange`,candidates:[]};let e=new Set,t=new RTCPeerConnection({iceServers:[]}),n=!1,r=new Promise(r=>{t.onicecandidate=t=>{t.candidate?.candidate&&e.add(t.candidate.candidate),t.candidate||(n=!0,r())}});try{t.createDataChannel(`probe`);let e=await t.createOffer();await t.setLocalDescription(e),await Promise.race([r,new Promise(e=>window.setTimeout(e,2400))])}catch{}finally{t.close()}let i=[...e],a=i.some(e=>/\btyp srflx\b/.test(e)||/\btyp relay\b/.test(e)),o=i.some(e=>/\btyp host\b/.test(e));return a?{status:`需要留意`,detail:`收集到 ${i.length} 个候选地址,其中包含公网回显特征。`,tone:`red`,candidates:i}:o||n?{status:`本地候选为主`,detail:`收集到 ${i.length} 个候选地址,主要来自本地网段。`,tone:`orange`,candidates:i}:{status:`暂未发现异常`,detail:`未收集到可识别的候选地址。`,tone:`green`,candidates:i}}async function D(){let[e]=await Promise.all([E()]);return{timezone:Intl.DateTimeFormat().resolvedOptions().timeZone||`-`,language:navigator.language||`-`,browser:T(navigator.userAgent||``),webrtc:e}}function O(e){return e.length===0?`slate`:e.some(e=>w(e))?`orange`:`green`}function k(e){return e.length===0?`未读取`:e.some(e=>w(e))?`内网 / 企业 DNS`:`公网 DNS`}function A(e){return{total:e.length,reachable:e.filter(e=>e.status===`可达`).length,limited:e.filter(e=>e.status===`受限`).length,unavailable:e.filter(e=>e.status===`不可用`).length}}function j(e,t){return!e||t.total===0?{label:`正在判断海外访问`,detail:`正在检查 ChatGPT、Claude、Google、YouTube 和 X 的连通性。`,tone:`blue`}:t.unavailable>0?{label:`海外访问受阻`,detail:`${t.unavailable} 个海外应用不可用,优先检查代理出口、DNS 或上游链路。`,tone:`red`}:t.limited>0?{label:`部分应用受限`,detail:`${t.reachable}/${t.total} 个海外应用可达,其余应用返回限制状态。`,tone:`orange`}:{label:`海外应用可访问`,detail:`${t.total} 个目标应用均已连通,当前出口可用于海外反向代理场景。`,tone:`green`}}function te(e,t){if(!e&&!t)return{label:`检测中`,detail:`正在采集公网出口、DNS、WebRTC、代理和平台可达性。`,tone:`blue`};if(!e||!t)return{label:`部分结果`,detail:`已有项目返回,剩余项目会保留失败原因,方便继续排查。`,tone:`orange`};let n=e.publicIpv4.available&&!!e.publicIpv4.ip,r=e.publicIpv6.available&&!!e.publicIpv6.ip,i=[e.platforms.some(e=>e.tone===`red`),t.webrtc.tone===`red`,!n&&!r],a=[e.platforms.some(e=>e.tone===`orange`),t.webrtc.tone===`orange`,O(e.dns.servers)!==`green`,!n,!e.publicIpv6.available];return i.some(Boolean)?{label:`建议先处理`,detail:`有明显阻塞项,先把出口或浏览器回显风险排掉。`,tone:`red`}:a.some(Boolean)?{label:`需要留意`,detail:`结果可用,但有几项信息值得再看一眼。`,tone:`orange`}:{label:`状态正常`,detail:`出口、DNS、WebRTC 和常用平台状态都比较稳定。`,tone:`green`}}function M(e){return(0,b.jsx)(`span`,{className:`network-chip ${e.tone}`,children:e.children})}function N(e){return(0,b.jsxs)(`span`,{className:`access-badge ${e.tone}`,children:[e.tone===`green`?(0,b.jsx)(a,{size:13}):e.tone===`red`?(0,b.jsx)(d,{size:13}):(0,b.jsx)(p,{size:13}),e.children]})}function P(e){let t=e.platformKey.toLowerCase(),n=x[t];return(0,b.jsx)(`span`,{className:`platform-icon ${e.tone} platform-${t}`,children:n?(0,b.jsx)(`img`,{alt:``,src:n}):e.icon})}function F(e){return(0,b.jsxs)(`div`,{className:`network-metric ${S(e.tone)}`,children:[(0,b.jsx)(`span`,{children:e.label}),(0,b.jsx)(`strong`,{children:e.value}),e.detail?(0,b.jsx)(`p`,{children:e.detail}):null]})}function I(e){let t=e.icon;return(0,b.jsxs)(`div`,{className:`signal-card ${S(e.tone)}`,children:[(0,b.jsx)(`div`,{className:`signal-card-icon`,children:(0,b.jsx)(t,{size:17})}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{children:e.label}),(0,b.jsx)(`strong`,{children:e.value}),(0,b.jsx)(`p`,{children:e.detail})]})]})}function L(e){return(0,b.jsxs)(`div`,{className:`network-block ${S(e.tone)}`,children:[(0,b.jsx)(`span`,{children:e.label}),(0,b.jsx)(`strong`,{children:e.value}),(0,b.jsx)(`p`,{children:e.detail})]})}function R(e){let{item:t}=e;return(0,b.jsxs)(`div`,{className:`platform-access-row ${t.tone}`,children:[(0,b.jsxs)(`div`,{className:`platform-access-main`,children:[(0,b.jsx)(P,{icon:t.label.slice(0,1),tone:t.tone,platformKey:t.key}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`strong`,{children:t.label}),(0,b.jsx)(`span`,{children:C(t.url)})]})]}),(0,b.jsxs)(`div`,{className:`platform-access-result`,children:[(0,b.jsx)(N,{tone:t.tone,children:t.status}),(0,b.jsx)(`span`,{children:t.httpStatus?`HTTP ${t.httpStatus}`:`连接结果`})]}),(0,b.jsxs)(`div`,{className:`platform-access-latency`,children:[(0,b.jsx)(`strong`,{children:z(t.elapsedMs)}),(0,b.jsx)(`span`,{children:t.httpStatus?`${t.httpStatus} 响应`:`等待结果`})]}),(0,b.jsx)(`div`,{className:`platform-access-detail`,children:(0,b.jsx)(`span`,{children:t.detail})})]})}function z(e){return typeof e==`number`?`${e} ms`:`-`}function B(e){return e instanceof DOMException&&e.name===`AbortError`?`网络探测超过 18 秒,已停止等待。`:e instanceof Error?e.message:String(e)}function V(){let[e,t]=(0,m.useState)(null),[n,r]=(0,m.useState)(null),[a,d]=(0,m.useState)(!0),[p,h]=(0,m.useState)(`正在采集真实网络状态...`),[g,_]=(0,m.useState)(null);async function v(){d(!0),_(null),h(`正在采集真实网络状态...`);let e=new AbortController,n=window.setTimeout(()=>e.abort(),18e3);try{let[n,i]=await Promise.allSettled([ee(`/_gateway/admin/network-detect`,{signal:e.signal}),D()]);n.status===`fulfilled`&&t(n.value),i.status===`fulfilled`&&r(i.value);let a=[];n.status===`rejected`&&a.push(`网络探测: ${B(n.reason)}`),i.status===`rejected`&&a.push(`本地环境: ${B(i.reason)}`);let o=n.status===`fulfilled`&&i.status===`fulfilled`?`检测完成。`:n.status===`fulfilled`||i.status===`fulfilled`?`部分结果已更新。`:`检测失败。`;_(a.length>0?a.join(` · `):null),h(o)}catch(e){_(B(e)),h(`检测失败。`)}finally{window.clearTimeout(n),d(!1)}}(0,m.useEffect)(()=>{v().catch(()=>void 0)},[]);let y=(0,m.useMemo)(()=>e?new Intl.DateTimeFormat(`zh-CN`,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1}).format(new Date(e.checkedAt)):`--:--:--`,[e]),x=te(e,n),S=O(e?.dns.servers||[]),C=k(e?.dns.servers||[]),T=e?.dns.servers?.length?e.dns.servers.slice(0,2).join(` / `):`-`,E=e?.dns.detail||`尚未检测到系统 DNS。`,N=A(e?.platforms||[]),P=e?e.publicIpv4.available&&e.publicIpv4.ip?`green`:`orange`:`blue`,V=e?e.publicIpv6.available?`green`:`orange`:`blue`,H=e?e.publicIpv4.available&&e.publicIpv4.ip?e.publicIpv4.ip:`未获取到`:a?`检测中`:`未读取`,U=e?.publicIpv4.detail||`正在采集公网 IPv4 出口。`,W=e?.proxy.enabled?`代理已启用`:e?`直连`:`待检测`,G=e?.proxy.enabled?e.proxy.url||`代理地址未读取`:`检测请求按当前网关配置发起。`,K=e?e.proxy.enabled?`orange`:`green`:`blue`,q=j(e,N),J=N.total>0?Math.round(N.reachable/N.total*100):0,Y=e?`${J}%`:`--`,X=N.total>0?String(N.total):`5`,Z=e?.publicIpv4.countryName?`${e.publicIpv4.countryName}${e.publicIpv4.colo?` · ${e.publicIpv4.colo}`:``}`:e?.publicIpv4.countryCode||`未知出口`,ne=e?.publicIpv4.available?`${e.publicIpv4.source} · ${z(e.publicIpv4.elapsedMs)}`:U,Q=e?.platforms.find(e=>e.tone===`red`)??e?.platforms.find(e=>e.tone===`orange`),re=Q?`${Q.label}: ${Q.detail}`:e?`海外目标应用均有响应。`:`等待海外目标应用响应。`,$=n?.webrtc.tone===`red`?`red`:n?.webrtc.tone===`orange`||S===`orange`?`orange`:S===`slate`||!n?`blue`:`green`;return(0,b.jsxs)(`section`,{className:`network-page`,children:[(0,b.jsxs)(`section`,{className:`network-command-center ${q.tone}`,children:[(0,b.jsxs)(`div`,{className:`network-command-copy`,children:[(0,b.jsxs)(`div`,{className:`network-eyebrow`,children:[(0,b.jsx)(u,{size:14}),(0,b.jsx)(`span`,{children:`海外应用访问诊断`})]}),(0,b.jsx)(`h2`,{children:q.label}),(0,b.jsx)(`p`,{children:q.detail}),(0,b.jsxs)(`div`,{className:`network-command-status`,children:[(0,b.jsx)(M,{tone:x.tone,children:x.label}),(0,b.jsxs)(`span`,{children:[(0,b.jsx)(o,{size:13}),y]}),(0,b.jsx)(`span`,{className:`network-toolbar-status`,children:p})]})]}),(0,b.jsxs)(`div`,{className:`access-score-card`,children:[(0,b.jsx)(`span`,{children:`海外可达率`}),(0,b.jsx)(`strong`,{children:Y}),(0,b.jsx)(`div`,{className:`access-score-bar`,"aria-hidden":`true`,children:(0,b.jsx)(`i`,{style:{width:`${J}%`}})}),(0,b.jsxs)(`p`,{children:[N.reachable,`/`,X,` 个目标应用可达`]}),(0,b.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>v().catch(()=>void 0),disabled:a,children:[(0,b.jsx)(s,{size:16}),a?`检测中`:`重新检测`]})]})]}),g?(0,b.jsxs)(`p`,{className:`network-error`,children:[`检测提示: `,g]}):null,(0,b.jsxs)(`section`,{className:`signal-grid`,children:[(0,b.jsx)(I,{icon:i,label:`海外连通性`,value:`${N.reachable}/${X}`,detail:re,tone:q.tone}),(0,b.jsx)(I,{icon:f,label:`当前出口`,value:e?.publicIpv4.available?Z:H,detail:ne,tone:P}),(0,b.jsx)(I,{icon:c,label:`代理路径`,value:W,detail:G,tone:K}),(0,b.jsx)(I,{icon:l,label:`解析与浏览器`,value:n?`${C} · ${n.webrtc.status}`:`检测中`,detail:n?.webrtc.detail||E,tone:$})]}),(0,b.jsxs)(`section`,{className:`network-workspace`,children:[(0,b.jsxs)(`section`,{className:`card network-section network-platform-panel`,children:[(0,b.jsxs)(`div`,{className:`section-head compact`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h3`,{children:`海外应用矩阵`}),(0,b.jsx)(`p`,{children:`反代链路最常用目标的实时可达性。`})]}),(0,b.jsxs)(`div`,{className:`platform-summary-strip`,children:[(0,b.jsxs)(`div`,{className:`platform-summary-chip green`,children:[(0,b.jsx)(`strong`,{children:N.reachable}),(0,b.jsx)(`span`,{children:`可达`})]}),(0,b.jsxs)(`div`,{className:`platform-summary-chip orange`,children:[(0,b.jsx)(`strong`,{children:N.limited}),(0,b.jsx)(`span`,{children:`受限`})]}),(0,b.jsxs)(`div`,{className:`platform-summary-chip red`,children:[(0,b.jsx)(`strong`,{children:N.unavailable}),(0,b.jsx)(`span`,{children:`阻断`})]})]})]}),e?.platforms.length?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`platform-access-header`,"aria-hidden":`true`,children:[(0,b.jsx)(`span`,{children:`应用`}),(0,b.jsx)(`span`,{children:`状态`}),(0,b.jsx)(`span`,{children:`耗时`}),(0,b.jsx)(`span`,{children:`说明`})]}),(0,b.jsx)(`div`,{className:`platform-access-list`,children:e.platforms.map(e=>(0,b.jsx)(R,{item:e},e.key))})]}):(0,b.jsx)(`div`,{className:`network-empty-state`,children:`平台探测结果还没有返回。`})]}),(0,b.jsxs)(`aside`,{className:`network-side`,children:[(0,b.jsxs)(`section`,{className:`card network-section network-diagnosis-panel`,children:[(0,b.jsx)(`div`,{className:`section-head compact`,children:(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h3`,{children:`访问结论`}),(0,b.jsx)(`p`,{children:`用于判断当前环境是否适合海外反向代理。`})]})}),(0,b.jsxs)(`div`,{className:`network-list`,children:[(0,b.jsxs)(`div`,{className:`network-list-item`,children:[(0,b.jsx)(M,{tone:q.tone,children:q.label}),(0,b.jsx)(`p`,{children:q.detail})]}),(0,b.jsxs)(`div`,{className:`network-list-item`,children:[(0,b.jsx)(M,{tone:x.tone,children:x.label}),(0,b.jsx)(`p`,{children:x.detail})]}),(0,b.jsxs)(`div`,{className:`network-list-item`,children:[(0,b.jsx)(M,{tone:n?.webrtc.tone||`blue`,children:n?.webrtc.status||`检测中`}),(0,b.jsx)(`p`,{children:n?.webrtc.detail||`正在采集 WebRTC 候选。`})]})]})]}),(0,b.jsxs)(`section`,{className:`card network-section`,children:[(0,b.jsx)(`div`,{className:`section-head compact`,children:(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h3`,{children:`出口与代理`}),(0,b.jsx)(`p`,{children:`反代请求实际经过的公网出口。`})]})}),(0,b.jsxs)(`div`,{className:`network-dual`,children:[(0,b.jsx)(L,{label:`IPv4 出口`,value:H,detail:e?e.publicIpv4.available?`${Z} · ${z(e.publicIpv4.elapsedMs)}`:`${e.publicIpv4.detail} · ${z(e.publicIpv4.elapsedMs)}`:`正在采集公网出口信息。`,tone:P}),(0,b.jsx)(L,{label:`IPv6 出口`,value:e?.publicIpv6.available?e.publicIpv6.ip||`-`:`未检测到`,detail:e?.publicIpv6.detail||`未检测到独立 IPv6 出口。`,tone:V})]}),(0,b.jsx)(`div`,{className:`network-list compact-list`,children:(0,b.jsxs)(`div`,{className:`network-list-item`,children:[(0,b.jsx)(M,{tone:K,children:W}),(0,b.jsx)(`p`,{children:G})]})})]})]})]}),(0,b.jsxs)(`section`,{className:`card network-section network-environment-panel`,children:[(0,b.jsx)(`div`,{className:`section-head compact`,children:(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h3`,{children:`解析与本地指纹`}),(0,b.jsx)(`p`,{children:`DNS、WebRTC、时区和语言会影响海外应用的风控判断。`})]})}),(0,b.jsxs)(`div`,{className:`network-three-up`,children:[(0,b.jsx)(F,{label:`DNS`,value:T,detail:`${C} · ${e?.dns.source||`尚未获取`}`,tone:S}),(0,b.jsx)(F,{label:`WebRTC`,value:n?.webrtc.status||(a?`检测中`:`-`),detail:n?.webrtc.detail||`正在采集 WebRTC 候选。`,tone:n?.webrtc.tone||`blue`}),(0,b.jsx)(F,{label:`本地环境`,value:n?.timezone||`-`,detail:`${n?.language||`-`} · ${n?.browser||`-`}`,tone:$})]}),e?.dns.servers.length?(0,b.jsx)(`div`,{className:`dns-chip-row`,children:e.dns.servers.map(e=>(0,b.jsx)(`span`,{className:`dns-chip ${w(e)?`orange`:`green`}`,children:e},e))}):null]})]})}export{V as NetworkDetectPage};
1
+ import{a as e,n as t,r as n,t as r}from"./jsx-runtime-DqpGtLhh.js";import{t as i}from"./activity-D21-Xrc4.js";import{t as a}from"./circle-check-ZYtn9GqY.js";import{t as o}from"./clock-3-BzDANsVk.js";import{t as s}from"./refresh-cw-CAAH2rqe.js";import{t as c}from"./server-BrjJPb9D.js";import{g as l,m as u,p as ee}from"./index-rgcJgVAu.js";var d=t(`circle-x`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m15 9-6 6`,key:`1uzhvr`}],[`path`,{d:`m9 9 6 6`,key:`z0biqf`}]]),f=t(`map-pin`,[[`path`,{d:`M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0`,key:`1r0f0z`}],[`circle`,{cx:`12`,cy:`10`,r:`3`,key:`ilqhr7`}]]),p=t(`triangle-alert`,[[`path`,{d:`m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3`,key:`wmoenq`}],[`path`,{d:`M12 9v4`,key:`juzpu7`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]),m=e(n(),1),h=`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eClaude%3c/title%3e%3cpath%20d='m4.7144%2015.9555%204.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608%201.5179.1032%202.2767.1578%201.6514.0972%202.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973%209.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686%201.9064%201.4754%202.4893%201.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335%206.6997%200l.9957.1336.419.3642.6192%201.4147%201.0018%202.2282%201.5543%203.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853%201.8517-.5586%202.9021-.3643%201.9429h.2125l.2429-.2429.9835-1.3053%201.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759%201.1293-.34%201.1657-1.0625%201.3478-.8804%201.1414-1.2628%201.7-.7893%201.36.0729.1093.1882-.0183%202.8535-.607%201.5421-.2794%201.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607%201.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929%201.0686%202.0035%201.8092%202.5075%202.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496%202.3436%203.5214.1214%201.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38%2017.959l-1.1414-1.9428-.1397.079-.674%207.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328%201.9672-2.1796%202.9446-1.7243%201.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889%202.386-3.0357%201.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385%204.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429%201.9064-1.3114Z'/%3e%3c/svg%3e`,g=`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eOpenAI%3c/title%3e%3cpath%20d='M22.2819%209.8211a5.9847%205.9847%200%200%200-.5157-4.9108%206.0462%206.0462%200%200%200-6.5098-2.9A6.0651%206.0651%200%200%200%204.9807%204.1818a5.9847%205.9847%200%200%200-3.9977%202.9%206.0462%206.0462%200%200%200%20.7427%207.0966%205.98%205.98%200%200%200%20.511%204.9107%206.051%206.051%200%200%200%206.5146%202.9001A5.9847%205.9847%200%200%200%2013.2599%2024a6.0557%206.0557%200%200%200%205.7718-4.2058%205.9894%205.9894%200%200%200%203.9977-2.9001%206.0557%206.0557%200%200%200-.7475-7.0729zm-9.022%2012.6081a4.4755%204.4755%200%200%201-2.8764-1.0408l.1419-.0804%204.7783-2.7582a.7948.7948%200%200%200%20.3927-.6813v-6.7369l2.02%201.1686a.071.071%200%200%201%20.038.052v5.5826a4.504%204.504%200%200%201-4.4945%204.4944zm-9.6607-4.1254a4.4708%204.4708%200%200%201-.5346-3.0137l.142.0852%204.783%202.7582a.7712.7712%200%200%200%20.7806%200l5.8428-3.3685v2.3324a.0804.0804%200%200%201-.0332.0615L9.74%2019.9502a4.4992%204.4992%200%200%201-6.1408-1.6464zM2.3408%207.8956a4.485%204.485%200%200%201%202.3655-1.9728V11.6a.7664.7664%200%200%200%20.3879.6765l5.8144%203.3543-2.0201%201.1685a.0757.0757%200%200%201-.071%200l-4.8303-2.7865A4.504%204.504%200%200%201%202.3408%207.872zm16.5963%203.8558L13.1038%208.364%2015.1192%207.2a.0757.0757%200%200%201%20.071%200l4.8303%202.7913a4.4944%204.4944%200%200%201-.6765%208.1042v-5.6772a.79.79%200%200%200-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759%200%200%200-.7854%200L9.409%209.2297V6.8974a.0662.0662%200%200%201%20.0284-.0615l4.8303-2.7866a4.4992%204.4992%200%200%201%206.6802%204.66zM8.3065%2012.863l-2.02-1.1638a.0804.0804%200%200%201-.038-.0567V6.0742a4.4992%204.4992%200%200%201%207.3757-3.4537l-.142.0805L8.704%205.459a.7948.7948%200%200%200-.3927.6813zm1.0976-2.3654l2.602-1.4998%202.6069%201.4998v2.9994l-2.5974%201.4997-2.6067-1.4997Z'/%3e%3c/svg%3e`,_=`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eGoogle%3c/title%3e%3cpath%20d='M12.48%2010.92v3.28h7.84c-.24%201.84-.853%203.187-1.787%204.133-1.147%201.147-2.933%202.4-6.053%202.4-4.827%200-8.6-3.893-8.6-8.72s3.773-8.72%208.6-8.72c2.6%200%204.507%201.027%205.907%202.347l2.307-2.307C18.747%201.44%2016.133%200%2012.48%200%205.867%200%20.307%205.387.307%2012s5.56%2012%2012.173%2012c3.573%200%206.267-1.173%208.373-3.36%202.16-2.16%202.84-5.213%202.84-7.667%200-.76-.053-1.467-.173-2.053H12.48z'/%3e%3c/svg%3e`,v=`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eX%3c/title%3e%3cpath%20d='M14.234%2010.162%2022.977%200h-2.072l-7.591%208.824L7.251%200H.258l9.168%2013.343L.258%2024H2.33l8.016-9.318L16.749%2024h6.993zm-2.837%203.299-.929-1.329L3.076%201.56h3.182l5.965%208.532.929%201.329%207.754%2011.09h-3.182z'/%3e%3c/svg%3e`,y=`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eYouTube%3c/title%3e%3cpath%20d='M23.498%206.186a3.016%203.016%200%200%200-2.122-2.136C19.505%203.545%2012%203.545%2012%203.545s-7.505%200-9.377.505A3.017%203.017%200%200%200%20.502%206.186C0%208.07%200%2012%200%2012s0%203.93.502%205.814a3.016%203.016%200%200%200%202.122%202.136c1.871.505%209.376.505%209.376.505s7.505%200%209.377-.505a3.015%203.015%200%200%200%202.122-2.136C24%2015.93%2024%2012%2024%2012s0-3.93-.502-5.814zM9.545%2015.568V8.432L15.818%2012l-6.273%203.568z'/%3e%3c/svg%3e`,b=r(),x={claude:h,chatgpt:g,google:_,x:v,youtube:y};function S(e){return`tone-${e}`}function C(e){try{return new URL(e).hostname.replace(/^www\./i,``)}catch{return e}}function w(e){return/^(10|127|169\.254|172\.(1[6-9]|2\d|3[0-1])|192\.168)\./.test(e)||/^100\.(6[4-9]|[7-9]\d|1\d\d|2[0-3]\d|24[0-7])\./.test(e)||/^198\.(18|19)\./.test(e)||/^192\.0\.2\./.test(e)||/^198\.51\.100\./.test(e)||/^203\.0\.113\./.test(e)||/^fc00:/i.test(e)||/^fd00:/i.test(e)||/^fe80:/i.test(e)||/^::1$/.test(e)}function T(e){let t=e.match(/Electron\/([\d.]+)/i);if(t)return`Electron ${t[1]}`;let n=e.match(/Chrome\/([\d.]+)/i);if(n&&/Safari\//i.test(e))return`Chrome ${n[1].split(`.`)[0]}`;let r=e.match(/Version\/([\d.]+).*Safari\//i);if(r&&!/Chrome\//i.test(e))return`Safari ${r[1].split(`.`)[0]}`;let i=e.match(/Firefox\/([\d.]+)/i);return i?`Firefox ${i[1].split(`.`)[0]}`:e.slice(0,40)}async function E(){if(typeof RTCPeerConnection>`u`)return{status:`不支持`,detail:`当前环境不支持 WebRTC。`,tone:`orange`,candidates:[]};let e=new Set,t=new RTCPeerConnection({iceServers:[]}),n=!1,r=new Promise(r=>{t.onicecandidate=t=>{t.candidate?.candidate&&e.add(t.candidate.candidate),t.candidate||(n=!0,r())}});try{t.createDataChannel(`probe`);let e=await t.createOffer();await t.setLocalDescription(e),await Promise.race([r,new Promise(e=>window.setTimeout(e,2400))])}catch{}finally{t.close()}let i=[...e],a=i.some(e=>/\btyp srflx\b/.test(e)||/\btyp relay\b/.test(e)),o=i.some(e=>/\btyp host\b/.test(e));return a?{status:`需要留意`,detail:`收集到 ${i.length} 个候选地址,其中包含公网回显特征。`,tone:`red`,candidates:i}:o||n?{status:`本地候选为主`,detail:`收集到 ${i.length} 个候选地址,主要来自本地网段。`,tone:`orange`,candidates:i}:{status:`暂未发现异常`,detail:`未收集到可识别的候选地址。`,tone:`green`,candidates:i}}async function D(){let[e]=await Promise.all([E()]);return{timezone:Intl.DateTimeFormat().resolvedOptions().timeZone||`-`,language:navigator.language||`-`,browser:T(navigator.userAgent||``),webrtc:e}}function O(e){return e.length===0?`slate`:e.some(e=>w(e))?`orange`:`green`}function k(e){return e.length===0?`未读取`:e.some(e=>w(e))?`内网 / 企业 DNS`:`公网 DNS`}function A(e){return{total:e.length,reachable:e.filter(e=>e.status===`可达`).length,limited:e.filter(e=>e.status===`受限`).length,unavailable:e.filter(e=>e.status===`不可用`).length}}function j(e,t){return!e||t.total===0?{label:`正在判断海外访问`,detail:`正在检查 ChatGPT、Claude、Google、YouTube 和 X 的连通性。`,tone:`blue`}:t.unavailable>0?{label:`海外访问受阻`,detail:`${t.unavailable} 个海外应用不可用,优先检查代理出口、DNS 或上游链路。`,tone:`red`}:t.limited>0?{label:`部分应用受限`,detail:`${t.reachable}/${t.total} 个海外应用可达,其余应用返回限制状态。`,tone:`orange`}:{label:`海外应用可访问`,detail:`${t.total} 个目标应用均已连通,当前出口可用于海外反向代理场景。`,tone:`green`}}function te(e,t){if(!e&&!t)return{label:`检测中`,detail:`正在采集公网出口、DNS、WebRTC、代理和平台可达性。`,tone:`blue`};if(!e||!t)return{label:`部分结果`,detail:`已有项目返回,剩余项目会保留失败原因,方便继续排查。`,tone:`orange`};let n=e.publicIpv4.available&&!!e.publicIpv4.ip,r=e.publicIpv6.available&&!!e.publicIpv6.ip,i=[e.platforms.some(e=>e.tone===`red`),t.webrtc.tone===`red`,!n&&!r],a=[e.platforms.some(e=>e.tone===`orange`),t.webrtc.tone===`orange`,O(e.dns.servers)!==`green`,!n,!e.publicIpv6.available];return i.some(Boolean)?{label:`建议先处理`,detail:`有明显阻塞项,先把出口或浏览器回显风险排掉。`,tone:`red`}:a.some(Boolean)?{label:`需要留意`,detail:`结果可用,但有几项信息值得再看一眼。`,tone:`orange`}:{label:`状态正常`,detail:`出口、DNS、WebRTC 和常用平台状态都比较稳定。`,tone:`green`}}function M(e){return(0,b.jsx)(`span`,{className:`network-chip ${e.tone}`,children:e.children})}function N(e){return(0,b.jsxs)(`span`,{className:`access-badge ${e.tone}`,children:[e.tone===`green`?(0,b.jsx)(a,{size:13}):e.tone===`red`?(0,b.jsx)(d,{size:13}):(0,b.jsx)(p,{size:13}),e.children]})}function P(e){let t=e.platformKey.toLowerCase(),n=x[t];return(0,b.jsx)(`span`,{className:`platform-icon ${e.tone} platform-${t}`,children:n?(0,b.jsx)(`img`,{alt:``,src:n}):e.icon})}function F(e){return(0,b.jsxs)(`div`,{className:`network-metric ${S(e.tone)}`,children:[(0,b.jsx)(`span`,{children:e.label}),(0,b.jsx)(`strong`,{children:e.value}),e.detail?(0,b.jsx)(`p`,{children:e.detail}):null]})}function I(e){let t=e.icon;return(0,b.jsxs)(`div`,{className:`signal-card ${S(e.tone)}`,children:[(0,b.jsx)(`div`,{className:`signal-card-icon`,children:(0,b.jsx)(t,{size:17})}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{children:e.label}),(0,b.jsx)(`strong`,{children:e.value}),(0,b.jsx)(`p`,{children:e.detail})]})]})}function L(e){return(0,b.jsxs)(`div`,{className:`network-block ${S(e.tone)}`,children:[(0,b.jsx)(`span`,{children:e.label}),(0,b.jsx)(`strong`,{children:e.value}),(0,b.jsx)(`p`,{children:e.detail})]})}function R(e){let{item:t}=e;return(0,b.jsxs)(`div`,{className:`platform-access-row ${t.tone}`,children:[(0,b.jsxs)(`div`,{className:`platform-access-main`,children:[(0,b.jsx)(P,{icon:t.label.slice(0,1),tone:t.tone,platformKey:t.key}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`strong`,{children:t.label}),(0,b.jsx)(`span`,{children:C(t.url)})]})]}),(0,b.jsxs)(`div`,{className:`platform-access-result`,children:[(0,b.jsx)(N,{tone:t.tone,children:t.status}),(0,b.jsx)(`span`,{children:t.httpStatus?`HTTP ${t.httpStatus}`:`连接结果`})]}),(0,b.jsxs)(`div`,{className:`platform-access-latency`,children:[(0,b.jsx)(`strong`,{children:z(t.elapsedMs)}),(0,b.jsx)(`span`,{children:t.httpStatus?`${t.httpStatus} 响应`:`等待结果`})]}),(0,b.jsx)(`div`,{className:`platform-access-detail`,children:(0,b.jsx)(`span`,{children:t.detail})})]})}function z(e){return typeof e==`number`?`${e} ms`:`-`}function B(e){return e instanceof DOMException&&e.name===`AbortError`?`网络探测超过 18 秒,已停止等待。`:e instanceof Error?e.message:String(e)}function V(){let[e,t]=(0,m.useState)(null),[n,r]=(0,m.useState)(null),[a,d]=(0,m.useState)(!0),[p,h]=(0,m.useState)(`正在采集真实网络状态...`),[g,_]=(0,m.useState)(null);async function v(){d(!0),_(null),h(`正在采集真实网络状态...`);let e=new AbortController,n=window.setTimeout(()=>e.abort(),18e3);try{let[n,i]=await Promise.allSettled([ee(`/_gateway/admin/network-detect`,{signal:e.signal}),D()]);n.status===`fulfilled`&&t(n.value),i.status===`fulfilled`&&r(i.value);let a=[];n.status===`rejected`&&a.push(`网络探测: ${B(n.reason)}`),i.status===`rejected`&&a.push(`本地环境: ${B(i.reason)}`);let o=n.status===`fulfilled`&&i.status===`fulfilled`?`检测完成。`:n.status===`fulfilled`||i.status===`fulfilled`?`部分结果已更新。`:`检测失败。`;_(a.length>0?a.join(` · `):null),h(o)}catch(e){_(B(e)),h(`检测失败。`)}finally{window.clearTimeout(n),d(!1)}}(0,m.useEffect)(()=>{v().catch(()=>void 0)},[]);let y=(0,m.useMemo)(()=>e?new Intl.DateTimeFormat(`zh-CN`,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1}).format(new Date(e.checkedAt)):`--:--:--`,[e]),x=te(e,n),S=O(e?.dns.servers||[]),C=k(e?.dns.servers||[]),T=e?.dns.servers?.length?e.dns.servers.slice(0,2).join(` / `):`-`,E=e?.dns.detail||`尚未检测到系统 DNS。`,N=A(e?.platforms||[]),P=e?e.publicIpv4.available&&e.publicIpv4.ip?`green`:`orange`:`blue`,V=e?e.publicIpv6.available?`green`:`orange`:`blue`,H=e?e.publicIpv4.available&&e.publicIpv4.ip?e.publicIpv4.ip:`未获取到`:a?`检测中`:`未读取`,U=e?.publicIpv4.detail||`正在采集公网 IPv4 出口。`,W=e?.proxy.enabled?`代理已启用`:e?`直连`:`待检测`,G=e?.proxy.enabled?e.proxy.url||`代理地址未读取`:`检测请求按当前网关配置发起。`,K=e?e.proxy.enabled?`orange`:`green`:`blue`,q=j(e,N),J=N.total>0?Math.round(N.reachable/N.total*100):0,Y=e?`${J}%`:`--`,X=N.total>0?String(N.total):`5`,Z=e?.publicIpv4.countryName?`${e.publicIpv4.countryName}${e.publicIpv4.colo?` · ${e.publicIpv4.colo}`:``}`:e?.publicIpv4.countryCode||`未知出口`,ne=e?.publicIpv4.available?`${e.publicIpv4.source} · ${z(e.publicIpv4.elapsedMs)}`:U,Q=e?.platforms.find(e=>e.tone===`red`)??e?.platforms.find(e=>e.tone===`orange`),re=Q?`${Q.label}: ${Q.detail}`:e?`海外目标应用均有响应。`:`等待海外目标应用响应。`,$=n?.webrtc.tone===`red`?`red`:n?.webrtc.tone===`orange`||S===`orange`?`orange`:S===`slate`||!n?`blue`:`green`;return(0,b.jsxs)(`section`,{className:`network-page`,children:[(0,b.jsxs)(`section`,{className:`network-command-center ${q.tone}`,children:[(0,b.jsxs)(`div`,{className:`network-command-copy`,children:[(0,b.jsxs)(`div`,{className:`network-eyebrow`,children:[(0,b.jsx)(u,{size:14}),(0,b.jsx)(`span`,{children:`海外应用访问诊断`})]}),(0,b.jsx)(`h2`,{children:q.label}),(0,b.jsx)(`p`,{children:q.detail}),(0,b.jsxs)(`div`,{className:`network-command-status`,children:[(0,b.jsx)(M,{tone:x.tone,children:x.label}),(0,b.jsxs)(`span`,{children:[(0,b.jsx)(o,{size:13}),y]}),(0,b.jsx)(`span`,{className:`network-toolbar-status`,children:p})]})]}),(0,b.jsxs)(`div`,{className:`access-score-card`,children:[(0,b.jsx)(`span`,{children:`海外可达率`}),(0,b.jsx)(`strong`,{children:Y}),(0,b.jsx)(`div`,{className:`access-score-bar`,"aria-hidden":`true`,children:(0,b.jsx)(`i`,{style:{width:`${J}%`}})}),(0,b.jsxs)(`p`,{children:[N.reachable,`/`,X,` 个目标应用可达`]}),(0,b.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>v().catch(()=>void 0),disabled:a,children:[(0,b.jsx)(s,{size:16}),a?`检测中`:`重新检测`]})]})]}),g?(0,b.jsxs)(`p`,{className:`network-error`,children:[`检测提示: `,g]}):null,(0,b.jsxs)(`section`,{className:`signal-grid`,children:[(0,b.jsx)(I,{icon:i,label:`海外连通性`,value:`${N.reachable}/${X}`,detail:re,tone:q.tone}),(0,b.jsx)(I,{icon:f,label:`当前出口`,value:e?.publicIpv4.available?Z:H,detail:ne,tone:P}),(0,b.jsx)(I,{icon:c,label:`代理路径`,value:W,detail:G,tone:K}),(0,b.jsx)(I,{icon:l,label:`解析与浏览器`,value:n?`${C} · ${n.webrtc.status}`:`检测中`,detail:n?.webrtc.detail||E,tone:$})]}),(0,b.jsxs)(`section`,{className:`network-workspace`,children:[(0,b.jsxs)(`section`,{className:`card network-section network-platform-panel`,children:[(0,b.jsxs)(`div`,{className:`section-head compact`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h3`,{children:`海外应用矩阵`}),(0,b.jsx)(`p`,{children:`反代链路最常用目标的实时可达性。`})]}),(0,b.jsxs)(`div`,{className:`platform-summary-strip`,children:[(0,b.jsxs)(`div`,{className:`platform-summary-chip green`,children:[(0,b.jsx)(`strong`,{children:N.reachable}),(0,b.jsx)(`span`,{children:`可达`})]}),(0,b.jsxs)(`div`,{className:`platform-summary-chip orange`,children:[(0,b.jsx)(`strong`,{children:N.limited}),(0,b.jsx)(`span`,{children:`受限`})]}),(0,b.jsxs)(`div`,{className:`platform-summary-chip red`,children:[(0,b.jsx)(`strong`,{children:N.unavailable}),(0,b.jsx)(`span`,{children:`阻断`})]})]})]}),e?.platforms.length?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`platform-access-header`,"aria-hidden":`true`,children:[(0,b.jsx)(`span`,{children:`应用`}),(0,b.jsx)(`span`,{children:`状态`}),(0,b.jsx)(`span`,{children:`耗时`}),(0,b.jsx)(`span`,{children:`说明`})]}),(0,b.jsx)(`div`,{className:`platform-access-list`,children:e.platforms.map(e=>(0,b.jsx)(R,{item:e},e.key))})]}):(0,b.jsx)(`div`,{className:`network-empty-state`,children:`平台探测结果还没有返回。`})]}),(0,b.jsxs)(`aside`,{className:`network-side`,children:[(0,b.jsxs)(`section`,{className:`card network-section network-diagnosis-panel`,children:[(0,b.jsx)(`div`,{className:`section-head compact`,children:(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h3`,{children:`访问结论`}),(0,b.jsx)(`p`,{children:`用于判断当前环境是否适合海外反向代理。`})]})}),(0,b.jsxs)(`div`,{className:`network-list`,children:[(0,b.jsxs)(`div`,{className:`network-list-item`,children:[(0,b.jsx)(M,{tone:q.tone,children:q.label}),(0,b.jsx)(`p`,{children:q.detail})]}),(0,b.jsxs)(`div`,{className:`network-list-item`,children:[(0,b.jsx)(M,{tone:x.tone,children:x.label}),(0,b.jsx)(`p`,{children:x.detail})]}),(0,b.jsxs)(`div`,{className:`network-list-item`,children:[(0,b.jsx)(M,{tone:n?.webrtc.tone||`blue`,children:n?.webrtc.status||`检测中`}),(0,b.jsx)(`p`,{children:n?.webrtc.detail||`正在采集 WebRTC 候选。`})]})]})]}),(0,b.jsxs)(`section`,{className:`card network-section`,children:[(0,b.jsx)(`div`,{className:`section-head compact`,children:(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h3`,{children:`出口与代理`}),(0,b.jsx)(`p`,{children:`反代请求实际经过的公网出口。`})]})}),(0,b.jsxs)(`div`,{className:`network-dual`,children:[(0,b.jsx)(L,{label:`IPv4 出口`,value:H,detail:e?e.publicIpv4.available?`${Z} · ${z(e.publicIpv4.elapsedMs)}`:`${e.publicIpv4.detail} · ${z(e.publicIpv4.elapsedMs)}`:`正在采集公网出口信息。`,tone:P}),(0,b.jsx)(L,{label:`IPv6 出口`,value:e?.publicIpv6.available?e.publicIpv6.ip||`-`:`未检测到`,detail:e?.publicIpv6.detail||`未检测到独立 IPv6 出口。`,tone:V})]}),(0,b.jsx)(`div`,{className:`network-list compact-list`,children:(0,b.jsxs)(`div`,{className:`network-list-item`,children:[(0,b.jsx)(M,{tone:K,children:W}),(0,b.jsx)(`p`,{children:G})]})})]})]})]}),(0,b.jsxs)(`section`,{className:`card network-section network-environment-panel`,children:[(0,b.jsx)(`div`,{className:`section-head compact`,children:(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h3`,{children:`解析与本地指纹`}),(0,b.jsx)(`p`,{children:`DNS、WebRTC、时区和语言会影响海外应用的风控判断。`})]})}),(0,b.jsxs)(`div`,{className:`network-three-up`,children:[(0,b.jsx)(F,{label:`DNS`,value:T,detail:`${C} · ${e?.dns.source||`尚未获取`}`,tone:S}),(0,b.jsx)(F,{label:`WebRTC`,value:n?.webrtc.status||(a?`检测中`:`-`),detail:n?.webrtc.detail||`正在采集 WebRTC 候选。`,tone:n?.webrtc.tone||`blue`}),(0,b.jsx)(F,{label:`本地环境`,value:n?.timezone||`-`,detail:`${n?.language||`-`} · ${n?.browser||`-`}`,tone:$})]}),e?.dns.servers.length?(0,b.jsx)(`div`,{className:`dns-chip-row`,children:e.dns.servers.map(e=>(0,b.jsx)(`span`,{className:`dns-chip ${w(e)?`orange`:`green`}`,children:e},e))}):null]})]})}export{V as NetworkDetectPage};
@@ -1 +1 @@
1
- import{a as e,r as t,t as n}from"./jsx-runtime-DqpGtLhh.js";import{t as r}from"./circle-check-ZYtn9GqY.js";import{t as i}from"./clock-3-BzDANsVk.js";import{t as a}from"./earth-DFdZaQIi.js";import{t as o}from"./zap-B4_oDbCp.js";import{c as s,l as c,m as l,x as u}from"./profiles-DMOjJORP.js";import{g as d,h as f}from"./index-DRe-tByu.js";import{t as p}from"./InfoRow-0ULI9iI3.js";var m=e(t(),1),h=n();function g(e){let t=e.icon;return(0,h.jsxs)(`article`,{className:`summary-card tone-${e.tone||`brand`} ${e.compact?`compact-value`:``}`,children:[(0,h.jsx)(`div`,{className:`summary-icon ${e.tone||`brand`}`,children:(0,h.jsx)(t,{size:16})}),(0,h.jsxs)(`div`,{children:[(0,h.jsx)(`span`,{children:e.label}),(0,h.jsx)(`strong`,{children:e.value}),(0,h.jsx)(`p`,{children:e.detail})]})]})}function _(e){let t=l(e.apiProfile,e.showEmails),n=e.codexProfile?l(e.codexProfile,e.showEmails):e.codexEmail?e.showEmails?e.codexEmail:s(e.codexEmail):e.codexAccountId?e.showEmails?e.codexAccountId:c(e.codexAccountId):`未应用`;return(0,h.jsxs)(`div`,{className:`usage-summary`,children:[(0,h.jsxs)(`div`,{className:`usage-summary-row`,children:[(0,h.jsx)(`span`,{children:`网关:`}),(0,h.jsx)(`strong`,{children:t})]}),(0,h.jsxs)(`div`,{className:`usage-summary-row`,children:[(0,h.jsx)(`span`,{children:`Codex:`}),(0,h.jsx)(`strong`,{children:n})]})]})}function v(e){let t=e?.quota?.primaryUsedPercent;return typeof t!=`number`||!Number.isFinite(t)?0:Math.max(0,Math.min(100,Math.round(t)))}function y(e,t,n,r){let i=Array.isArray(e?.profiles)?e.profiles:[],a=620+(e?.profile?v(e.profile):42)*7+n*90,o=i.reduce((e,t,n)=>e+v(t)*(n+1),0),s=Math.max(1,r/60);return Array.from({length:12},(e,r)=>{let i=Math.sin((r+1+n)*(.65+s*.08))*(120+s*18),c=Math.cos((r+1)*(1.05+s*.06)+n)*(72+s*10),l=t[r]?t[r].durationMs*(n===0?.24:.12):0,u=a+i+c+l+o%280;return Math.max(220,Math.min(2200,Math.round(u)))})}function b(e,t,n,r){return e.map((i,a)=>{let o=t/(e.length-1)*a,s=n-i/r*(n-16)-8;return`${a===0?`M`:`L`}${o.toFixed(2)} ${s.toFixed(2)}`}).join(` `)}function x(e){let t=y(e.config,e.requestLogs,0,e.windowMinutes),n=y(e.config,e.requestLogs,1,e.windowMinutes).map(e=>Math.max(180,e-260)),r=Math.max(...t,...n,2e3),i=b(t,720,210,r),a=b(n,720,210,r),o=Date.now(),s=Math.max(10,Math.round(e.windowMinutes/6)),c=Array.from({length:6},(e,t)=>new Date(o-(5-t)*s*60*1e3).toLocaleTimeString(`zh-CN`,{hour12:!1,hour:`2-digit`,minute:`2-digit`}));return(0,h.jsxs)(`section`,{className:`trend-card`,"aria-label":`请求耗时趋势`,children:[(0,h.jsxs)(`div`,{className:`section-head compact`,children:[(0,h.jsxs)(`div`,{children:[(0,h.jsx)(`h3`,{children:`请求耗时趋势`}),(0,h.jsx)(`p`,{children:`基于最近调试请求和账号额度状态生成的本地趋势视图。`})]}),(0,h.jsxs)(`select`,{className:`control`,value:e.windowMinutes,onChange:t=>e.onWindow(Number(t.target.value)),children:[(0,h.jsx)(`option`,{value:60,children:`近 1 小时`}),(0,h.jsx)(`option`,{value:180,children:`近 3 小时`}),(0,h.jsx)(`option`,{value:720,children:`近 12 小时`})]})]}),(0,h.jsxs)(`div`,{className:`chart-wrap`,children:[(0,h.jsxs)(`div`,{className:`chart-legend`,children:[(0,h.jsxs)(`span`,{className:`legend-item`,children:[(0,h.jsx)(`span`,{className:`legend-swatch purple`}),`网关响应`]}),(0,h.jsxs)(`span`,{className:`legend-item`,children:[(0,h.jsx)(`span`,{className:`legend-swatch blue`}),`上游响应`]})]}),(0,h.jsxs)(`svg`,{className:`trend-svg`,viewBox:`0 0 720 210`,role:`img`,"aria-label":`请求耗时趋势折线图`,children:[(0,h.jsxs)(`defs`,{children:[(0,h.jsxs)(`linearGradient`,{id:`areaA`,x1:`0`,y1:`0`,x2:`0`,y2:`1`,children:[(0,h.jsx)(`stop`,{offset:`0%`,stopColor:`rgba(99,91,255,0.18)`}),(0,h.jsx)(`stop`,{offset:`100%`,stopColor:`rgba(99,91,255,0.02)`})]}),(0,h.jsxs)(`linearGradient`,{id:`areaB`,x1:`0`,y1:`0`,x2:`0`,y2:`1`,children:[(0,h.jsx)(`stop`,{offset:`0%`,stopColor:`rgba(59,130,246,0.16)`}),(0,h.jsx)(`stop`,{offset:`100%`,stopColor:`rgba(59,130,246,0.02)`})]})]}),[1,2,3,4].map(e=>(0,h.jsx)(`line`,{x1:`0`,y1:e*42,x2:720,y2:e*42,stroke:`#e2e8f0`,strokeWidth:`1`},e)),(0,h.jsx)(`path`,{d:`${i} L 720 210 L 0 210 Z`,fill:`url(#areaA)`,stroke:`none`}),(0,h.jsx)(`path`,{d:`${a} L 720 210 L 0 210 Z`,fill:`url(#areaB)`,stroke:`none`}),(0,h.jsx)(`path`,{d:i,fill:`none`,stroke:`#635bff`,strokeWidth:`2.4`,strokeLinecap:`round`}),(0,h.jsx)(`path`,{d:a,fill:`none`,stroke:`#3b82f6`,strokeWidth:`2.4`,strokeLinecap:`round`})]}),(0,h.jsx)(`div`,{className:`trend-labels`,children:c.map((e,t)=>(0,h.jsx)(`span`,{children:e},`${e}-${t}`))})]})]})}function S(e){return(0,h.jsxs)(`section`,{className:`card service-card endpoint-card`,children:[(0,h.jsx)(`div`,{className:`section-head compact`,children:(0,h.jsxs)(`div`,{children:[(0,h.jsx)(`h3`,{children:`网关信息`}),(0,h.jsx)(`p`,{children:`桌面端与 CLI 共享同一套本地服务。`})]})}),(0,h.jsxs)(`div`,{className:`service-list compact-grid`,children:[(0,h.jsx)(p,{label:`管理页`,value:e.config?.adminUrl||`-`,code:!0}),(0,h.jsx)(p,{label:`Base URL`,value:e.config?.baseUrl||`-`,code:!0}),(0,h.jsx)(p,{label:`默认模型`,value:e.config?.settings.defaultModel||`-`}),(0,h.jsx)(p,{label:`生图模型`,value:`gpt-image-2`}),(0,h.jsx)(p,{label:`兼容接口`,value:e.config?.supportedEndpoints.map(e=>e.path).join(`,`)||`-`}),(0,h.jsx)(p,{label:`令牌预览`,value:e.config?.profile?.accessTokenPreview||`未登录`,code:!0}),(0,h.jsx)(p,{label:`模型来源`,value:e.config?.modelCatalog.source||`-`})]})]})}function C(e){let[t,n]=(0,m.useState)(60),s=e.requestLogs.length?e.requestLogs.reduce((e,t)=>e+t.durationMs,0)/e.requestLogs.length:0;return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsxs)(`section`,{className:`summary-grid desktop-summary-grid overview-summary-grid`,children:[(0,h.jsx)(g,{icon:f,label:`账号总数`,value:String(e.config?.status.profileCount||0),detail:`已保存到本地账号池`,tone:`blue`}),(0,h.jsx)(g,{icon:a,label:`当前账号状态`,value:(0,h.jsx)(_,{apiProfile:e.activeProfile,codexProfile:e.codexProfile,codexEmail:e.codexEmail,codexAccountId:e.codexAccountId,showEmails:e.showEmails}),detail:e.config?.status.loggedIn||e.codexProfile?``:`需要先登录或导入账号`,tone:e.config?.status.loggedIn||e.codexProfile?`green`:`orange`,compact:!0}),(0,h.jsx)(g,{icon:o,label:`今日请求数`,value:String(e.requestLogs.length),detail:`基于本页最近测试记录`,tone:`blue`}),(0,h.jsx)(g,{icon:i,label:`平均耗时`,value:e.requestLogs.length?u(s):`-`,detail:`统计最近 ${e.requestLogs.length} 次`,tone:`orange`}),(0,h.jsx)(g,{icon:d,label:`服务状态`,value:e.config?.status.loggedIn?`运行中`:`等待登录`,detail:`网关可转发请求`,tone:e.config?.status.loggedIn?`green`:`orange`}),(0,h.jsx)(g,{icon:r,label:`默认模型`,value:e.config?.settings.defaultModel||`-`,detail:`未显式指定 model 时生效`,tone:`green`})]}),(0,h.jsxs)(`section`,{className:`overview-grid`,children:[(0,h.jsx)(x,{config:e.config,requestLogs:e.requestLogs,windowMinutes:t,onWindow:n}),(0,h.jsx)(S,{config:e.config})]})]})}export{C as OverviewPage};
1
+ import{a as e,r as t,t as n}from"./jsx-runtime-DqpGtLhh.js";import{t as r}from"./circle-check-ZYtn9GqY.js";import{t as i}from"./clock-3-BzDANsVk.js";import{t as a}from"./earth-DFdZaQIi.js";import{t as o}from"./zap-B4_oDbCp.js";import{c as s,l as c,m as l,x as u}from"./profiles-DMOjJORP.js";import{g as d,h as f}from"./index-rgcJgVAu.js";import{t as p}from"./InfoRow-0ULI9iI3.js";var m=e(t(),1),h=n();function g(e){let t=e.icon;return(0,h.jsxs)(`article`,{className:`summary-card tone-${e.tone||`brand`} ${e.compact?`compact-value`:``}`,children:[(0,h.jsx)(`div`,{className:`summary-icon ${e.tone||`brand`}`,children:(0,h.jsx)(t,{size:16})}),(0,h.jsxs)(`div`,{children:[(0,h.jsx)(`span`,{children:e.label}),(0,h.jsx)(`strong`,{children:e.value}),(0,h.jsx)(`p`,{children:e.detail})]})]})}function _(e){let t=l(e.apiProfile,e.showEmails),n=e.codexProfile?l(e.codexProfile,e.showEmails):e.codexEmail?e.showEmails?e.codexEmail:s(e.codexEmail):e.codexAccountId?e.showEmails?e.codexAccountId:c(e.codexAccountId):`未应用`;return(0,h.jsxs)(`div`,{className:`usage-summary`,children:[(0,h.jsxs)(`div`,{className:`usage-summary-row`,children:[(0,h.jsx)(`span`,{children:`网关:`}),(0,h.jsx)(`strong`,{children:t})]}),(0,h.jsxs)(`div`,{className:`usage-summary-row`,children:[(0,h.jsx)(`span`,{children:`Codex:`}),(0,h.jsx)(`strong`,{children:n})]})]})}function v(e){let t=e?.quota?.primaryUsedPercent;return typeof t!=`number`||!Number.isFinite(t)?0:Math.max(0,Math.min(100,Math.round(t)))}function y(e,t,n,r){let i=Array.isArray(e?.profiles)?e.profiles:[],a=620+(e?.profile?v(e.profile):42)*7+n*90,o=i.reduce((e,t,n)=>e+v(t)*(n+1),0),s=Math.max(1,r/60);return Array.from({length:12},(e,r)=>{let i=Math.sin((r+1+n)*(.65+s*.08))*(120+s*18),c=Math.cos((r+1)*(1.05+s*.06)+n)*(72+s*10),l=t[r]?t[r].durationMs*(n===0?.24:.12):0,u=a+i+c+l+o%280;return Math.max(220,Math.min(2200,Math.round(u)))})}function b(e,t,n,r){return e.map((i,a)=>{let o=t/(e.length-1)*a,s=n-i/r*(n-16)-8;return`${a===0?`M`:`L`}${o.toFixed(2)} ${s.toFixed(2)}`}).join(` `)}function x(e){let t=y(e.config,e.requestLogs,0,e.windowMinutes),n=y(e.config,e.requestLogs,1,e.windowMinutes).map(e=>Math.max(180,e-260)),r=Math.max(...t,...n,2e3),i=b(t,720,210,r),a=b(n,720,210,r),o=Date.now(),s=Math.max(10,Math.round(e.windowMinutes/6)),c=Array.from({length:6},(e,t)=>new Date(o-(5-t)*s*60*1e3).toLocaleTimeString(`zh-CN`,{hour12:!1,hour:`2-digit`,minute:`2-digit`}));return(0,h.jsxs)(`section`,{className:`trend-card`,"aria-label":`请求耗时趋势`,children:[(0,h.jsxs)(`div`,{className:`section-head compact`,children:[(0,h.jsxs)(`div`,{children:[(0,h.jsx)(`h3`,{children:`请求耗时趋势`}),(0,h.jsx)(`p`,{children:`基于最近调试请求和账号额度状态生成的本地趋势视图。`})]}),(0,h.jsxs)(`select`,{className:`control`,value:e.windowMinutes,onChange:t=>e.onWindow(Number(t.target.value)),children:[(0,h.jsx)(`option`,{value:60,children:`近 1 小时`}),(0,h.jsx)(`option`,{value:180,children:`近 3 小时`}),(0,h.jsx)(`option`,{value:720,children:`近 12 小时`})]})]}),(0,h.jsxs)(`div`,{className:`chart-wrap`,children:[(0,h.jsxs)(`div`,{className:`chart-legend`,children:[(0,h.jsxs)(`span`,{className:`legend-item`,children:[(0,h.jsx)(`span`,{className:`legend-swatch purple`}),`网关响应`]}),(0,h.jsxs)(`span`,{className:`legend-item`,children:[(0,h.jsx)(`span`,{className:`legend-swatch blue`}),`上游响应`]})]}),(0,h.jsxs)(`svg`,{className:`trend-svg`,viewBox:`0 0 720 210`,role:`img`,"aria-label":`请求耗时趋势折线图`,children:[(0,h.jsxs)(`defs`,{children:[(0,h.jsxs)(`linearGradient`,{id:`areaA`,x1:`0`,y1:`0`,x2:`0`,y2:`1`,children:[(0,h.jsx)(`stop`,{offset:`0%`,stopColor:`rgba(99,91,255,0.18)`}),(0,h.jsx)(`stop`,{offset:`100%`,stopColor:`rgba(99,91,255,0.02)`})]}),(0,h.jsxs)(`linearGradient`,{id:`areaB`,x1:`0`,y1:`0`,x2:`0`,y2:`1`,children:[(0,h.jsx)(`stop`,{offset:`0%`,stopColor:`rgba(59,130,246,0.16)`}),(0,h.jsx)(`stop`,{offset:`100%`,stopColor:`rgba(59,130,246,0.02)`})]})]}),[1,2,3,4].map(e=>(0,h.jsx)(`line`,{x1:`0`,y1:e*42,x2:720,y2:e*42,stroke:`#e2e8f0`,strokeWidth:`1`},e)),(0,h.jsx)(`path`,{d:`${i} L 720 210 L 0 210 Z`,fill:`url(#areaA)`,stroke:`none`}),(0,h.jsx)(`path`,{d:`${a} L 720 210 L 0 210 Z`,fill:`url(#areaB)`,stroke:`none`}),(0,h.jsx)(`path`,{d:i,fill:`none`,stroke:`#635bff`,strokeWidth:`2.4`,strokeLinecap:`round`}),(0,h.jsx)(`path`,{d:a,fill:`none`,stroke:`#3b82f6`,strokeWidth:`2.4`,strokeLinecap:`round`})]}),(0,h.jsx)(`div`,{className:`trend-labels`,children:c.map((e,t)=>(0,h.jsx)(`span`,{children:e},`${e}-${t}`))})]})]})}function S(e){return(0,h.jsxs)(`section`,{className:`card service-card endpoint-card`,children:[(0,h.jsx)(`div`,{className:`section-head compact`,children:(0,h.jsxs)(`div`,{children:[(0,h.jsx)(`h3`,{children:`网关信息`}),(0,h.jsx)(`p`,{children:`桌面端与 CLI 共享同一套本地服务。`})]})}),(0,h.jsxs)(`div`,{className:`service-list compact-grid`,children:[(0,h.jsx)(p,{label:`管理页`,value:e.config?.adminUrl||`-`,code:!0}),(0,h.jsx)(p,{label:`Base URL`,value:e.config?.baseUrl||`-`,code:!0}),(0,h.jsx)(p,{label:`默认模型`,value:e.config?.settings.defaultModel||`-`}),(0,h.jsx)(p,{label:`生图模型`,value:`gpt-image-2`}),(0,h.jsx)(p,{label:`兼容接口`,value:e.config?.supportedEndpoints.map(e=>e.path).join(`,`)||`-`}),(0,h.jsx)(p,{label:`令牌预览`,value:e.config?.profile?.accessTokenPreview||`未登录`,code:!0}),(0,h.jsx)(p,{label:`模型来源`,value:e.config?.modelCatalog.source||`-`})]})]})}function C(e){let[t,n]=(0,m.useState)(60),s=e.requestLogs.length?e.requestLogs.reduce((e,t)=>e+t.durationMs,0)/e.requestLogs.length:0;return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsxs)(`section`,{className:`summary-grid desktop-summary-grid overview-summary-grid`,children:[(0,h.jsx)(g,{icon:f,label:`账号总数`,value:String(e.config?.status.profileCount||0),detail:`已保存到本地账号池`,tone:`blue`}),(0,h.jsx)(g,{icon:a,label:`当前账号状态`,value:(0,h.jsx)(_,{apiProfile:e.activeProfile,codexProfile:e.codexProfile,codexEmail:e.codexEmail,codexAccountId:e.codexAccountId,showEmails:e.showEmails}),detail:e.config?.status.loggedIn||e.codexProfile?``:`需要先登录或导入账号`,tone:e.config?.status.loggedIn||e.codexProfile?`green`:`orange`,compact:!0}),(0,h.jsx)(g,{icon:o,label:`今日请求数`,value:String(e.requestLogs.length),detail:`基于本页最近测试记录`,tone:`blue`}),(0,h.jsx)(g,{icon:i,label:`平均耗时`,value:e.requestLogs.length?u(s):`-`,detail:`统计最近 ${e.requestLogs.length} 次`,tone:`orange`}),(0,h.jsx)(g,{icon:d,label:`服务状态`,value:e.config?.status.loggedIn?`运行中`:`等待登录`,detail:`网关可转发请求`,tone:e.config?.status.loggedIn?`green`:`orange`}),(0,h.jsx)(g,{icon:r,label:`默认模型`,value:e.config?.settings.defaultModel||`-`,detail:`未显式指定 model 时生效`,tone:`green`})]}),(0,h.jsxs)(`section`,{className:`overview-grid`,children:[(0,h.jsx)(x,{config:e.config,requestLogs:e.requestLogs,windowMinutes:t,onWindow:n}),(0,h.jsx)(S,{config:e.config})]})]})}export{C as OverviewPage};
@@ -1 +1 @@
1
- import{a as e,n as t,r as n,t as r}from"./jsx-runtime-DqpGtLhh.js";import{t as i}from"./refresh-cw-CAAH2rqe.js";import{w as a}from"./profiles-DMOjJORP.js";import{_ as o,p as s,r as c}from"./index-DRe-tByu.js";var l=t(`settings-2`,[[`path`,{d:`M14 17H5`,key:`gfn3mx`}],[`path`,{d:`M19 7h-9`,key:`6i9tg`}],[`circle`,{cx:`17`,cy:`17`,r:`3`,key:`18b49y`}],[`circle`,{cx:`7`,cy:`7`,r:`3`,key:`dfmy0x`}]]),u=e(n(),1),d=r();function f(e){return{defaultModel:e.settings.defaultModel,proxyEnabled:e.settings.networkProxy.enabled,proxyUrl:e.settings.networkProxy.url,proxyNoProxy:e.settings.networkProxy.noProxy||`localhost,127.0.0.1,::1`,autoSwitchEnabled:e.settings.autoSwitch.enabled,quotaSyncConcurrency:String(e.settings.runtime?.quotaSyncConcurrency||16),serverPort:String(e.settings.server.port||8787)}}function p(e){let[t,n]=(0,u.useState)({defaultModel:``,proxyEnabled:!1,proxyUrl:``,proxyNoProxy:`localhost,127.0.0.1,::1`,autoSwitchEnabled:!1,quotaSyncConcurrency:`16`,serverPort:`8787`}),[r,p]=(0,u.useState)(!1);(0,u.useEffect)(()=>{!e.config||r||n(f(e.config))},[e.config,r]);function m(e){n(t=>({...t,...e})),p(!0)}async function h(n){let r=Number.parseInt(t.serverPort,10);if(!Number.isInteger(r)||r<1||r>65535){e.setStatus(`端口必须是 1 到 65535 之间的整数。`);return}let i=Number.parseInt(t.quotaSyncConcurrency,10);if(!Number.isInteger(i)||i<1||i>32){e.setStatus(`全局额度刷新并发数必须是 1 到 32 之间的整数。`);return}let o=n?.restart?`restart`:`settings`;e.setBusy(o);try{let o=await s(`/_gateway/admin/settings`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:a({defaultModel:t.defaultModel,networkProxy:{enabled:t.proxyEnabled,url:t.proxyUrl,noProxy:t.proxyNoProxy},autoSwitch:{enabled:t.autoSwitchEnabled},runtime:{quotaSyncConcurrency:i},server:{port:r}})});e.setConfig(o),p(!1),n?.restart?(e.setStatus(`设置已保存,正在重启本地网关...`),await s(`/_gateway/admin/restart`,{method:`POST`}),e.setStatus(`本地网关正在重启,页面会自动恢复。`)):e.setStatus(`设置已保存。`)}catch(t){e.setStatus(c(t))}finally{e.setBusy(null)}}async function g(){e.setBusy(`proxy`);try{let n=await s(`/_gateway/admin/settings/proxy-test`,{method:`POST`,headers:{"Content-Type":`application/json`},body:a({networkProxy:{enabled:t.proxyEnabled,url:t.proxyUrl,noProxy:t.proxyNoProxy}})});e.setStatus(`代理测试通过: HTTP ${n.status},耗时 ${n.elapsedMs} ms。`)}catch(t){e.setStatus(`代理测试失败: ${c(t)}`)}finally{e.setBusy(null)}}async function _(){e.setBusy(`models`);try{await s(`/_gateway/models/refresh`,{method:`POST`}),await e.refreshConfig({silent:!0}),e.setStatus(`Codex 模型列表已同步。`)}catch(t){e.setStatus(c(t))}finally{e.setBusy(null)}}return(0,d.jsxs)(`section`,{className:`settings-page`,children:[(0,d.jsxs)(`div`,{className:`settings-page-head`,children:[(0,d.jsxs)(`div`,{children:[(0,d.jsxs)(`div`,{className:`settings-page-kicker`,children:[(0,d.jsx)(l,{size:14}),`系统设置`]}),(0,d.jsx)(`h2`,{children:`本地网关和运行策略`}),(0,d.jsx)(`p`,{children:`设置会保存到本地状态目录,CLI、桌面端和本地服务共享。`})]}),(0,d.jsx)(`div`,{className:`settings-page-actions`,children:(0,d.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:_,disabled:e.busy===`models`,children:[e.busy===`models`?(0,d.jsx)(o,{className:`spin`,size:16}):(0,d.jsx)(i,{size:16}),`同步 Codex 模型`]})})]}),(0,d.jsxs)(`div`,{className:`settings-grid`,children:[(0,d.jsxs)(`section`,{className:`settings-section`,children:[(0,d.jsx)(`h4`,{children:`模型`}),(0,d.jsxs)(`label`,{className:`field`,children:[(0,d.jsx)(`span`,{children:`默认文本模型`}),(0,d.jsx)(`select`,{className:`control`,value:t.defaultModel,onChange:e=>m({defaultModel:e.target.value}),children:(e.config?.models||[]).map(e=>(0,d.jsx)(`option`,{value:e.id,children:e.id},e.id))})]}),(0,d.jsxs)(`p`,{className:`hint`,children:[`模型列表来源:`,e.config?.modelCatalog.source||`-`,`,共 `,e.config?.modelCatalog.modelCount||0,` 个。`]})]}),(0,d.jsxs)(`section`,{className:`settings-section`,children:[(0,d.jsx)(`h4`,{children:`上游代理`}),(0,d.jsxs)(`label`,{className:`switch-line`,children:[(0,d.jsx)(`input`,{type:`checkbox`,checked:t.proxyEnabled,onChange:e=>m({proxyEnabled:e.target.checked})}),(0,d.jsx)(`span`,{children:`启用 OAuth、模型刷新和接口转发代理`})]}),(0,d.jsxs)(`label`,{className:`field`,children:[(0,d.jsx)(`span`,{children:`代理地址`}),(0,d.jsx)(`input`,{className:`input`,value:t.proxyUrl,onChange:e=>m({proxyUrl:e.target.value}),placeholder:`http://127.0.0.1:7890`})]}),(0,d.jsxs)(`label`,{className:`field`,children:[(0,d.jsx)(`span`,{children:`No Proxy`}),(0,d.jsx)(`input`,{className:`input`,value:t.proxyNoProxy,onChange:e=>m({proxyNoProxy:e.target.value})})]}),(0,d.jsx)(`button`,{className:`btn-secondary`,type:`button`,onClick:g,disabled:e.busy===`proxy`,children:`测试代理`})]}),(0,d.jsxs)(`section`,{className:`settings-section`,children:[(0,d.jsx)(`h4`,{children:`端口`}),(0,d.jsxs)(`label`,{className:`field`,children:[(0,d.jsx)(`span`,{children:`网关端口`}),(0,d.jsx)(`input`,{className:`input`,inputMode:`numeric`,type:`number`,min:1,max:65535,value:t.serverPort,onChange:e=>m({serverPort:e.target.value})})]}),(0,d.jsx)(`p`,{className:`hint`,children:`修改后重启本地网关生效,桌面窗口不会退出。若端口被占用,启动时会自动顺延到下一个可用端口。`})]}),(0,d.jsxs)(`section`,{className:`settings-section`,children:[(0,d.jsx)(`h4`,{children:`账号运行策略`}),(0,d.jsxs)(`label`,{className:`switch-line`,children:[(0,d.jsx)(`input`,{type:`checkbox`,checked:t.autoSwitchEnabled,onChange:e=>m({autoSwitchEnabled:e.target.checked})}),(0,d.jsx)(`span`,{children:`当前 API 账号额度耗尽后自动切换到下一个仍有额度的账号`})]}),(0,d.jsxs)(`label`,{className:`field`,children:[(0,d.jsx)(`span`,{children:`全局额度刷新并发数`}),(0,d.jsx)(`input`,{className:`input`,inputMode:`numeric`,max:32,min:1,type:`number`,value:t.quotaSyncConcurrency,onChange:e=>m({quotaSyncConcurrency:e.target.value})})]}),(0,d.jsx)(`p`,{className:`hint`,children:`手动刷新全部账号额度时使用,默认 16。账号很多可以调高,遇到限流或失败增多时调低。`}),(0,d.jsx)(`p`,{className:`hint`,children:e.status})]}),(0,d.jsxs)(`section`,{className:`settings-section`,children:[(0,d.jsx)(`h4`,{children:`显示`}),(0,d.jsxs)(`label`,{className:`switch-line`,children:[(0,d.jsx)(`input`,{type:`checkbox`,checked:e.showEmails,onChange:t=>e.setShowEmails(t.target.checked)}),(0,d.jsx)(`span`,{children:`脱敏模式`})]}),(0,d.jsx)(`p`,{className:`hint`,children:`开启后账号邮箱将以脱敏形式展示。`})]})]}),(0,d.jsxs)(`div`,{className:`settings-page-actions settings-page-footer-actions`,children:[(0,d.jsx)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>void h(),disabled:e.busy===`settings`||e.busy===`restart`||!r,children:`保存设置`}),(0,d.jsx)(`button`,{className:`btn-primary`,type:`button`,onClick:()=>void h({restart:!0}),disabled:e.busy===`settings`||e.busy===`restart`||!r||!e.config?.restartSupported,children:`保存并重启网关`})]})]})}export{p as SettingsPage};
1
+ import{a as e,n as t,r as n,t as r}from"./jsx-runtime-DqpGtLhh.js";import{t as i}from"./refresh-cw-CAAH2rqe.js";import{w as a}from"./profiles-DMOjJORP.js";import{_ as o,p as s,r as c}from"./index-rgcJgVAu.js";var l=t(`settings-2`,[[`path`,{d:`M14 17H5`,key:`gfn3mx`}],[`path`,{d:`M19 7h-9`,key:`6i9tg`}],[`circle`,{cx:`17`,cy:`17`,r:`3`,key:`18b49y`}],[`circle`,{cx:`7`,cy:`7`,r:`3`,key:`dfmy0x`}]]),u=e(n(),1),d=r();function f(e){return{defaultModel:e.settings.defaultModel,proxyEnabled:e.settings.networkProxy.enabled,proxyUrl:e.settings.networkProxy.url,proxyNoProxy:e.settings.networkProxy.noProxy||`localhost,127.0.0.1,::1`,autoSwitchEnabled:e.settings.autoSwitch.enabled,quotaSyncConcurrency:String(e.settings.runtime?.quotaSyncConcurrency||16),serverPort:String(e.settings.server.port||8787)}}function p(e){let[t,n]=(0,u.useState)({defaultModel:``,proxyEnabled:!1,proxyUrl:``,proxyNoProxy:`localhost,127.0.0.1,::1`,autoSwitchEnabled:!1,quotaSyncConcurrency:`16`,serverPort:`8787`}),[r,p]=(0,u.useState)(!1);(0,u.useEffect)(()=>{!e.config||r||n(f(e.config))},[e.config,r]);function m(e){n(t=>({...t,...e})),p(!0)}async function h(n){let r=Number.parseInt(t.serverPort,10);if(!Number.isInteger(r)||r<1||r>65535){e.setStatus(`端口必须是 1 到 65535 之间的整数。`);return}let i=Number.parseInt(t.quotaSyncConcurrency,10);if(!Number.isInteger(i)||i<1||i>32){e.setStatus(`全局额度刷新并发数必须是 1 到 32 之间的整数。`);return}let o=n?.restart?`restart`:`settings`;e.setBusy(o);try{let o=await s(`/_gateway/admin/settings`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:a({defaultModel:t.defaultModel,networkProxy:{enabled:t.proxyEnabled,url:t.proxyUrl,noProxy:t.proxyNoProxy},autoSwitch:{enabled:t.autoSwitchEnabled},runtime:{quotaSyncConcurrency:i},server:{port:r}})});e.setConfig(o),p(!1),n?.restart?(e.setStatus(`设置已保存,正在重启本地网关...`),await s(`/_gateway/admin/restart`,{method:`POST`}),e.setStatus(`本地网关正在重启,页面会自动恢复。`)):e.setStatus(`设置已保存。`)}catch(t){e.setStatus(c(t))}finally{e.setBusy(null)}}async function g(){e.setBusy(`proxy`);try{let n=await s(`/_gateway/admin/settings/proxy-test`,{method:`POST`,headers:{"Content-Type":`application/json`},body:a({networkProxy:{enabled:t.proxyEnabled,url:t.proxyUrl,noProxy:t.proxyNoProxy}})});e.setStatus(`代理测试通过: HTTP ${n.status},耗时 ${n.elapsedMs} ms。`)}catch(t){e.setStatus(`代理测试失败: ${c(t)}`)}finally{e.setBusy(null)}}async function _(){e.setBusy(`models`);try{await s(`/_gateway/models/refresh`,{method:`POST`}),await e.refreshConfig({silent:!0}),e.setStatus(`Codex 模型列表已同步。`)}catch(t){e.setStatus(c(t))}finally{e.setBusy(null)}}return(0,d.jsxs)(`section`,{className:`settings-page`,children:[(0,d.jsxs)(`div`,{className:`settings-page-head`,children:[(0,d.jsxs)(`div`,{children:[(0,d.jsxs)(`div`,{className:`settings-page-kicker`,children:[(0,d.jsx)(l,{size:14}),`系统设置`]}),(0,d.jsx)(`h2`,{children:`本地网关和运行策略`}),(0,d.jsx)(`p`,{children:`设置会保存到本地状态目录,CLI、桌面端和本地服务共享。`})]}),(0,d.jsx)(`div`,{className:`settings-page-actions`,children:(0,d.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:_,disabled:e.busy===`models`,children:[e.busy===`models`?(0,d.jsx)(o,{className:`spin`,size:16}):(0,d.jsx)(i,{size:16}),`同步 Codex 模型`]})})]}),(0,d.jsxs)(`div`,{className:`settings-grid`,children:[(0,d.jsxs)(`section`,{className:`settings-section`,children:[(0,d.jsx)(`h4`,{children:`模型`}),(0,d.jsxs)(`label`,{className:`field`,children:[(0,d.jsx)(`span`,{children:`默认文本模型`}),(0,d.jsx)(`select`,{className:`control`,value:t.defaultModel,onChange:e=>m({defaultModel:e.target.value}),children:(e.config?.models||[]).map(e=>(0,d.jsx)(`option`,{value:e.id,children:e.id},e.id))})]}),(0,d.jsxs)(`p`,{className:`hint`,children:[`模型列表来源:`,e.config?.modelCatalog.source||`-`,`,共 `,e.config?.modelCatalog.modelCount||0,` 个。`]})]}),(0,d.jsxs)(`section`,{className:`settings-section`,children:[(0,d.jsx)(`h4`,{children:`上游代理`}),(0,d.jsxs)(`label`,{className:`switch-line`,children:[(0,d.jsx)(`input`,{type:`checkbox`,checked:t.proxyEnabled,onChange:e=>m({proxyEnabled:e.target.checked})}),(0,d.jsx)(`span`,{children:`启用 OAuth、模型刷新和接口转发代理`})]}),(0,d.jsxs)(`label`,{className:`field`,children:[(0,d.jsx)(`span`,{children:`代理地址`}),(0,d.jsx)(`input`,{className:`input`,value:t.proxyUrl,onChange:e=>m({proxyUrl:e.target.value}),placeholder:`http://127.0.0.1:7890`})]}),(0,d.jsxs)(`label`,{className:`field`,children:[(0,d.jsx)(`span`,{children:`No Proxy`}),(0,d.jsx)(`input`,{className:`input`,value:t.proxyNoProxy,onChange:e=>m({proxyNoProxy:e.target.value})})]}),(0,d.jsx)(`button`,{className:`btn-secondary`,type:`button`,onClick:g,disabled:e.busy===`proxy`,children:`测试代理`})]}),(0,d.jsxs)(`section`,{className:`settings-section`,children:[(0,d.jsx)(`h4`,{children:`端口`}),(0,d.jsxs)(`label`,{className:`field`,children:[(0,d.jsx)(`span`,{children:`网关端口`}),(0,d.jsx)(`input`,{className:`input`,inputMode:`numeric`,type:`number`,min:1,max:65535,value:t.serverPort,onChange:e=>m({serverPort:e.target.value})})]}),(0,d.jsx)(`p`,{className:`hint`,children:`修改后重启本地网关生效,桌面窗口不会退出。若端口被占用,启动时会自动顺延到下一个可用端口。`})]}),(0,d.jsxs)(`section`,{className:`settings-section`,children:[(0,d.jsx)(`h4`,{children:`账号运行策略`}),(0,d.jsxs)(`label`,{className:`switch-line`,children:[(0,d.jsx)(`input`,{type:`checkbox`,checked:t.autoSwitchEnabled,onChange:e=>m({autoSwitchEnabled:e.target.checked})}),(0,d.jsx)(`span`,{children:`当前 API 账号额度耗尽后自动切换到下一个仍有额度的账号`})]}),(0,d.jsxs)(`label`,{className:`field`,children:[(0,d.jsx)(`span`,{children:`全局额度刷新并发数`}),(0,d.jsx)(`input`,{className:`input`,inputMode:`numeric`,max:32,min:1,type:`number`,value:t.quotaSyncConcurrency,onChange:e=>m({quotaSyncConcurrency:e.target.value})})]}),(0,d.jsx)(`p`,{className:`hint`,children:`手动刷新全部账号额度时使用,默认 16。账号很多可以调高,遇到限流或失败增多时调低。`}),(0,d.jsx)(`p`,{className:`hint`,children:e.status})]}),(0,d.jsxs)(`section`,{className:`settings-section`,children:[(0,d.jsx)(`h4`,{children:`显示`}),(0,d.jsxs)(`label`,{className:`switch-line`,children:[(0,d.jsx)(`input`,{type:`checkbox`,checked:e.showEmails,onChange:t=>e.setShowEmails(t.target.checked)}),(0,d.jsx)(`span`,{children:`脱敏模式`})]}),(0,d.jsx)(`p`,{className:`hint`,children:`开启后账号邮箱将以脱敏形式展示。`})]})]}),(0,d.jsxs)(`div`,{className:`settings-page-actions settings-page-footer-actions`,children:[(0,d.jsx)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>void h(),disabled:e.busy===`settings`||e.busy===`restart`||!r,children:`保存设置`}),(0,d.jsx)(`button`,{className:`btn-primary`,type:`button`,onClick:()=>void h({restart:!0}),disabled:e.busy===`settings`||e.busy===`restart`||!r||!e.config?.restartSupported,children:`保存并重启网关`})]})]})}export{p as SettingsPage};
@@ -1,3 +1,3 @@
1
- import{a as e,n as t,r as n,t as r}from"./jsx-runtime-DqpGtLhh.js";import{t as i}from"./upload-CwXb7Q1b.js";import{t as a}from"./zap-B4_oDbCp.js";import{S as o,m as s,w as c,x as l}from"./profiles-DMOjJORP.js";import{_ as u,a as d,b as f,c as p,i as m,l as h,n as g,o as _,p as v,r as y,s as b,t as x,u as S}from"./index-DRe-tByu.js";var C=t(`rotate-ccw`,[[`path`,{d:`M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8`,key:`1357e3`}],[`path`,{d:`M3 3v5h5`,key:`1xhq8a`}]]),w=e(n(),1),T=r();function E(e){let t=e.endpoint.startsWith(`/v1/images/`);function n(t){let n=t.currentTarget.files?.[0];t.currentTarget.value=``,n&&e.onImageUpload(n,e.imageUploadMode).catch(()=>void 0)}return(0,T.jsxs)(`section`,{className:`card tester-card`,id:`tester`,children:[(0,T.jsxs)(`div`,{className:`section-head compact`,children:[(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`h2`,{children:`快速测试`}),(0,T.jsx)(`p`,{children:`页面直接调用当前网关暴露的 OpenAI 风格接口。`})]}),(0,T.jsx)(`span`,{className:`badge brand`,children:e.busy===`test`?`请求中`:`准备就绪`})]}),(0,T.jsx)(`div`,{className:`tester-tabs`,children:e.endpoints.map(t=>(0,T.jsx)(`button`,{className:`tab-btn ${e.endpoint===t.path?`is-active`:``}`,type:`button`,onClick:()=>e.onEndpoint(t.path),children:S[t.path]||t.path},t.path))}),(0,T.jsxs)(`div`,{className:`tester-workbench`,children:[(0,T.jsxs)(`div`,{className:`tester-pane tester-request-pane`,children:[(0,T.jsxs)(`label`,{className:`field`,children:[(0,T.jsx)(`span`,{children:`接口`}),(0,T.jsx)(`select`,{className:`control`,value:e.endpoint,onChange:t=>e.onEndpoint(t.target.value),children:e.endpoints.map(e=>(0,T.jsxs)(`option`,{value:e.path,children:[e.method,` `,e.path]},e.path))})]}),(0,T.jsxs)(`div`,{className:`tester-copy-row tester-copy-row-top`,children:[(0,T.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:e.onCopyRequest,children:[(0,T.jsx)(f,{size:16}),`复制请求`]}),(0,T.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:e.onCopyResponse,children:[(0,T.jsx)(f,{size:16}),`复制响应`]}),(0,T.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:e.onCopyTiming,children:[(0,T.jsx)(f,{size:16}),`复制日志`]}),(0,T.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:e.onResetExample,children:[(0,T.jsx)(C,{size:16}),`重置示例`]})]}),(0,T.jsxs)(`label`,{className:`field tester-body-field`,children:[(0,T.jsx)(`span`,{children:`请求体 JSON`}),(0,T.jsx)(`textarea`,{className:`textarea tester-textarea`,value:e.requestBody,onChange:t=>e.onRequestBody(t.target.value),disabled:e.activeEndpoint.method===`GET`,spellCheck:!1})]}),e.endpoint===`/v1/images/edits`&&(0,T.jsxs)(`div`,{className:`edit-upload-row`,children:[(0,T.jsxs)(`div`,{className:`edit-upload-mode`,role:`group`,"aria-label":`图片写入方式`,children:[(0,T.jsx)(`span`,{children:`写入方式`}),(0,T.jsxs)(`div`,{className:`edit-upload-toggle`,children:[(0,T.jsx)(`button`,{className:`tab-btn ${e.imageUploadMode===`base64`?`is-active`:``}`,type:`button`,onClick:()=>e.onImageUploadMode(`base64`),children:`Base64`}),(0,T.jsx)(`button`,{className:`tab-btn ${e.imageUploadMode===`image-bed`?`is-active`:``}`,type:`button`,onClick:()=>e.onImageUploadMode(`image-bed`),children:`图床`})]})]}),(0,T.jsxs)(`label`,{className:`btn-secondary upload-btn`,title:e.imageUploadMode===`base64`?`上传图片并写入 base64 data URL`:`上传图片到图床并写入公网链接`,children:[e.imageUploadMode===`image-bed`&&e.busy===`image-bed-upload`?(0,T.jsx)(u,{className:`spin`,size:16}):(0,T.jsx)(i,{size:16}),e.imageUploadMode===`base64`?`上传并写入 Base64`:`上传并写入图床链接`,(0,T.jsx)(`input`,{type:`file`,accept:`image/*`,onChange:n})]}),(0,T.jsxs)(`span`,{children:[`目标字段:images[0].image_url · `,e.imageUploadMode===`base64`?`直接写入 data URL`:`先上传图床再写入公网链接`]})]}),(0,T.jsx)(`p`,{className:`hint`,children:t?e.capability.detail:e.activeEndpoint.description||`GET /v1/models 无需请求体。`}),(0,T.jsxs)(`div`,{className:`tester-actions-bar`,children:[(0,T.jsx)(`div`,{className:`tester-actions-group`,children:(0,T.jsx)(`div`,{className:`example-row`,children:p.map(t=>(0,T.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>e.onEndpoint(t),disabled:!e.endpoints.some(e=>e.path===t),children:[`示例 `,S[t]||t]},t))})}),(0,T.jsxs)(`button`,{className:`btn-primary`,type:`button`,onClick:e.onRun,disabled:e.busy===`test`||t&&!e.config?.profile,children:[e.busy===`test`?(0,T.jsx)(u,{className:`spin`,size:16}):(0,T.jsx)(a,{size:16}),`发送请求`]})]})]}),(0,T.jsxs)(`div`,{className:`tester-pane tester-response-pane`,children:[(0,T.jsxs)(`div`,{className:`tester-result-head`,children:[(0,T.jsxs)(`div`,{className:`tester-result-tabs`,children:[(0,T.jsx)(`button`,{className:`tab-btn ${e.resultTab===`response`?`is-active`:``}`,type:`button`,onClick:()=>e.onResultTab(`response`),children:`响应 JSON`}),(0,T.jsx)(`button`,{className:`tab-btn ${e.resultTab===`timing`?`is-active`:``}`,type:`button`,onClick:()=>e.onResultTab(`timing`),children:`耗时日志`}),(0,T.jsx)(`button`,{className:`tab-btn ${e.resultTab===`preview`?`is-active`:``}`,type:`button`,onClick:()=>e.onResultTab(`preview`),children:`图片预览`})]}),(0,T.jsx)(`p`,{className:`status-inline`,children:e.status})]}),e.resultTab===`response`&&(0,T.jsx)(`pre`,{className:`pre`,children:e.responseBody}),e.resultTab===`timing`&&(0,T.jsx)(`pre`,{className:`pre`,children:e.timingBody}),e.resultTab===`preview`&&(0,T.jsx)(`div`,{className:`preview-panel`,children:e.previewImages.length===0?(0,T.jsx)(`div`,{className:`preview-empty`,children:`图片结果会显示在这里。点击缩略图可查看大图。`}):(0,T.jsx)(`div`,{className:`preview-grid`,children:e.previewImages.map(t=>(0,T.jsxs)(`figure`,{className:`preview-card`,children:[(0,T.jsx)(`button`,{type:`button`,onClick:()=>e.onPreview({src:t.src,meta:t.meta,filename:t.filename}),children:(0,T.jsx)(`img`,{src:t.src,alt:t.meta})}),(0,T.jsx)(`figcaption`,{children:t.meta}),(0,T.jsx)(`div`,{className:`preview-actions`,children:(0,T.jsx)(`a`,{href:t.src,download:t.filename,children:`下载`})})]},t.filename))})})]})]})]})}function D(e){let[t,n]=(0,w.useState)(`/v1/models`),[r,i]=(0,w.useState)(``),[a,u]=(0,w.useState)(`等待请求...`),[f,S]=(0,w.useState)(`等待请求...`),[C,D]=(0,w.useState)(`response`),[O,k]=(0,w.useState)([]),[A,j]=(0,w.useState)(`base64`),M=(0,w.useMemo)(()=>[...e.config?.supportedEndpoints||[]].sort(h),[e.config?.supportedEndpoints]),N=(0,w.useMemo)(()=>M.find(e=>e.path===t)||M[0]||{method:`GET`,path:`/v1/models`,description:``},[t,M]);(0,w.useEffect)(()=>{if(!e.config)return;let r=p.find(t=>e.config?.supportedEndpoints.some(e=>e.path===t)),a=e.config.supportedEndpoints.some(e=>e.path===t)?t:r||`/v1/models`;n(a),i(x(a,e.config.settings.defaultModel))},[e.config]);function P(t){n(t),i(x(t,e.config?.settings.defaultModel||`gpt-5.4`)),k([])}function F(){P(t)}function I(){g(r||x(t,e.config?.settings.defaultModel||`gpt-5.4`)).then(t=>e.setStatus(t?`请求体已复制。`:`请求体复制失败。`)).catch(()=>e.setStatus(`请求体复制失败。`))}function L(){g(a).then(t=>e.setStatus(t?`响应内容已复制。`:`响应内容复制失败。`)).catch(()=>e.setStatus(`响应内容复制失败。`))}function R(){g(f).then(t=>e.setStatus(t?`耗时日志已复制。`:`耗时日志复制失败。`)).catch(()=>e.setStatus(`耗时日志复制失败。`))}async function z(){let t=N,n=performance.now(),i=[];e.setBusy(`test`),D(`response`),u(`请求发送中...`),S(`请求发送中...`),k([]);try{let a=null,o={method:t.method,headers:{}};if(t.method!==`GET`){let e=performance.now();a=r.trim()?JSON.parse(r):{},i.push(`解析请求体: ${l(performance.now()-e)}`),o.headers[`Content-Type`]=`application/json`,o.body=c(a)}let d=performance.now(),f=await fetch(t.path,o);i.push(`等待响应头: ${l(performance.now()-d)}`);let p=performance.now(),h=await f.text();i.push(`读取响应体: ${l(performance.now()-p)}`);let g=performance.now(),_=h;try{_=h?JSON.parse(h):null}catch{_=h}i.push(`解析响应体: ${l(performance.now()-g)}`);let v=m(_);k(v),v.length>0&&D(`preview`),u(typeof _==`string`?_:c(b(_))),S([`${t.method} ${t.path}`,`HTTP 状态: ${f.status} ${f.statusText}`,...i].join(`
1
+ import{a as e,n as t,r as n,t as r}from"./jsx-runtime-DqpGtLhh.js";import{t as i}from"./upload-CwXb7Q1b.js";import{t as a}from"./zap-B4_oDbCp.js";import{S as o,m as s,w as c,x as l}from"./profiles-DMOjJORP.js";import{_ as u,a as d,b as f,c as p,i as m,l as h,n as g,o as _,p as v,r as y,s as b,t as x,u as S}from"./index-rgcJgVAu.js";var C=t(`rotate-ccw`,[[`path`,{d:`M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8`,key:`1357e3`}],[`path`,{d:`M3 3v5h5`,key:`1xhq8a`}]]),w=e(n(),1),T=r();function E(e){let t=e.endpoint.startsWith(`/v1/images/`);function n(t){let n=t.currentTarget.files?.[0];t.currentTarget.value=``,n&&e.onImageUpload(n,e.imageUploadMode).catch(()=>void 0)}return(0,T.jsxs)(`section`,{className:`card tester-card`,id:`tester`,children:[(0,T.jsxs)(`div`,{className:`section-head compact`,children:[(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`h2`,{children:`快速测试`}),(0,T.jsx)(`p`,{children:`页面直接调用当前网关暴露的 OpenAI 风格接口。`})]}),(0,T.jsx)(`span`,{className:`badge brand`,children:e.busy===`test`?`请求中`:`准备就绪`})]}),(0,T.jsx)(`div`,{className:`tester-tabs`,children:e.endpoints.map(t=>(0,T.jsx)(`button`,{className:`tab-btn ${e.endpoint===t.path?`is-active`:``}`,type:`button`,onClick:()=>e.onEndpoint(t.path),children:S[t.path]||t.path},t.path))}),(0,T.jsxs)(`div`,{className:`tester-workbench`,children:[(0,T.jsxs)(`div`,{className:`tester-pane tester-request-pane`,children:[(0,T.jsxs)(`label`,{className:`field`,children:[(0,T.jsx)(`span`,{children:`接口`}),(0,T.jsx)(`select`,{className:`control`,value:e.endpoint,onChange:t=>e.onEndpoint(t.target.value),children:e.endpoints.map(e=>(0,T.jsxs)(`option`,{value:e.path,children:[e.method,` `,e.path]},e.path))})]}),(0,T.jsxs)(`div`,{className:`tester-copy-row tester-copy-row-top`,children:[(0,T.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:e.onCopyRequest,children:[(0,T.jsx)(f,{size:16}),`复制请求`]}),(0,T.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:e.onCopyResponse,children:[(0,T.jsx)(f,{size:16}),`复制响应`]}),(0,T.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:e.onCopyTiming,children:[(0,T.jsx)(f,{size:16}),`复制日志`]}),(0,T.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:e.onResetExample,children:[(0,T.jsx)(C,{size:16}),`重置示例`]})]}),(0,T.jsxs)(`label`,{className:`field tester-body-field`,children:[(0,T.jsx)(`span`,{children:`请求体 JSON`}),(0,T.jsx)(`textarea`,{className:`textarea tester-textarea`,value:e.requestBody,onChange:t=>e.onRequestBody(t.target.value),disabled:e.activeEndpoint.method===`GET`,spellCheck:!1})]}),e.endpoint===`/v1/images/edits`&&(0,T.jsxs)(`div`,{className:`edit-upload-row`,children:[(0,T.jsxs)(`div`,{className:`edit-upload-mode`,role:`group`,"aria-label":`图片写入方式`,children:[(0,T.jsx)(`span`,{children:`写入方式`}),(0,T.jsxs)(`div`,{className:`edit-upload-toggle`,children:[(0,T.jsx)(`button`,{className:`tab-btn ${e.imageUploadMode===`base64`?`is-active`:``}`,type:`button`,onClick:()=>e.onImageUploadMode(`base64`),children:`Base64`}),(0,T.jsx)(`button`,{className:`tab-btn ${e.imageUploadMode===`image-bed`?`is-active`:``}`,type:`button`,onClick:()=>e.onImageUploadMode(`image-bed`),children:`图床`})]})]}),(0,T.jsxs)(`label`,{className:`btn-secondary upload-btn`,title:e.imageUploadMode===`base64`?`上传图片并写入 base64 data URL`:`上传图片到图床并写入公网链接`,children:[e.imageUploadMode===`image-bed`&&e.busy===`image-bed-upload`?(0,T.jsx)(u,{className:`spin`,size:16}):(0,T.jsx)(i,{size:16}),e.imageUploadMode===`base64`?`上传并写入 Base64`:`上传并写入图床链接`,(0,T.jsx)(`input`,{type:`file`,accept:`image/*`,onChange:n})]}),(0,T.jsxs)(`span`,{children:[`目标字段:images[0].image_url · `,e.imageUploadMode===`base64`?`直接写入 data URL`:`先上传图床再写入公网链接`]})]}),(0,T.jsx)(`p`,{className:`hint`,children:t?e.capability.detail:e.activeEndpoint.description||`GET /v1/models 无需请求体。`}),(0,T.jsxs)(`div`,{className:`tester-actions-bar`,children:[(0,T.jsx)(`div`,{className:`tester-actions-group`,children:(0,T.jsx)(`div`,{className:`example-row`,children:p.map(t=>(0,T.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>e.onEndpoint(t),disabled:!e.endpoints.some(e=>e.path===t),children:[`示例 `,S[t]||t]},t))})}),(0,T.jsxs)(`button`,{className:`btn-primary`,type:`button`,onClick:e.onRun,disabled:e.busy===`test`||t&&!e.config?.profile,children:[e.busy===`test`?(0,T.jsx)(u,{className:`spin`,size:16}):(0,T.jsx)(a,{size:16}),`发送请求`]})]})]}),(0,T.jsxs)(`div`,{className:`tester-pane tester-response-pane`,children:[(0,T.jsxs)(`div`,{className:`tester-result-head`,children:[(0,T.jsxs)(`div`,{className:`tester-result-tabs`,children:[(0,T.jsx)(`button`,{className:`tab-btn ${e.resultTab===`response`?`is-active`:``}`,type:`button`,onClick:()=>e.onResultTab(`response`),children:`响应 JSON`}),(0,T.jsx)(`button`,{className:`tab-btn ${e.resultTab===`timing`?`is-active`:``}`,type:`button`,onClick:()=>e.onResultTab(`timing`),children:`耗时日志`}),(0,T.jsx)(`button`,{className:`tab-btn ${e.resultTab===`preview`?`is-active`:``}`,type:`button`,onClick:()=>e.onResultTab(`preview`),children:`图片预览`})]}),(0,T.jsx)(`p`,{className:`status-inline`,children:e.status})]}),e.resultTab===`response`&&(0,T.jsx)(`pre`,{className:`pre`,children:e.responseBody}),e.resultTab===`timing`&&(0,T.jsx)(`pre`,{className:`pre`,children:e.timingBody}),e.resultTab===`preview`&&(0,T.jsx)(`div`,{className:`preview-panel`,children:e.previewImages.length===0?(0,T.jsx)(`div`,{className:`preview-empty`,children:`图片结果会显示在这里。点击缩略图可查看大图。`}):(0,T.jsx)(`div`,{className:`preview-grid`,children:e.previewImages.map(t=>(0,T.jsxs)(`figure`,{className:`preview-card`,children:[(0,T.jsx)(`button`,{type:`button`,onClick:()=>e.onPreview({src:t.src,meta:t.meta,filename:t.filename}),children:(0,T.jsx)(`img`,{src:t.src,alt:t.meta})}),(0,T.jsx)(`figcaption`,{children:t.meta}),(0,T.jsx)(`div`,{className:`preview-actions`,children:(0,T.jsx)(`a`,{href:t.src,download:t.filename,children:`下载`})})]},t.filename))})})]})]})]})}function D(e){let[t,n]=(0,w.useState)(`/v1/models`),[r,i]=(0,w.useState)(``),[a,u]=(0,w.useState)(`等待请求...`),[f,S]=(0,w.useState)(`等待请求...`),[C,D]=(0,w.useState)(`response`),[O,k]=(0,w.useState)([]),[A,j]=(0,w.useState)(`base64`),M=(0,w.useMemo)(()=>[...e.config?.supportedEndpoints||[]].sort(h),[e.config?.supportedEndpoints]),N=(0,w.useMemo)(()=>M.find(e=>e.path===t)||M[0]||{method:`GET`,path:`/v1/models`,description:``},[t,M]);(0,w.useEffect)(()=>{if(!e.config)return;let r=p.find(t=>e.config?.supportedEndpoints.some(e=>e.path===t)),a=e.config.supportedEndpoints.some(e=>e.path===t)?t:r||`/v1/models`;n(a),i(x(a,e.config.settings.defaultModel))},[e.config]);function P(t){n(t),i(x(t,e.config?.settings.defaultModel||`gpt-5.4`)),k([])}function F(){P(t)}function I(){g(r||x(t,e.config?.settings.defaultModel||`gpt-5.4`)).then(t=>e.setStatus(t?`请求体已复制。`:`请求体复制失败。`)).catch(()=>e.setStatus(`请求体复制失败。`))}function L(){g(a).then(t=>e.setStatus(t?`响应内容已复制。`:`响应内容复制失败。`)).catch(()=>e.setStatus(`响应内容复制失败。`))}function R(){g(f).then(t=>e.setStatus(t?`耗时日志已复制。`:`耗时日志复制失败。`)).catch(()=>e.setStatus(`耗时日志复制失败。`))}async function z(){let t=N,n=performance.now(),i=[];e.setBusy(`test`),D(`response`),u(`请求发送中...`),S(`请求发送中...`),k([]);try{let a=null,o={method:t.method,headers:{}};if(t.method!==`GET`){let e=performance.now();a=r.trim()?JSON.parse(r):{},i.push(`解析请求体: ${l(performance.now()-e)}`),o.headers[`Content-Type`]=`application/json`,o.body=c(a)}let d=performance.now(),f=await fetch(t.path,o);i.push(`等待响应头: ${l(performance.now()-d)}`);let p=performance.now(),h=await f.text();i.push(`读取响应体: ${l(performance.now()-p)}`);let g=performance.now(),_=h;try{_=h?JSON.parse(h):null}catch{_=h}i.push(`解析响应体: ${l(performance.now()-g)}`);let v=m(_);k(v),v.length>0&&D(`preview`),u(typeof _==`string`?_:c(b(_))),S([`${t.method} ${t.path}`,`HTTP 状态: ${f.status} ${f.statusText}`,...i].join(`
2
2
  `)),e.setStatus(`${f.ok?`成功`:`失败`}: HTTP ${f.status} ${t.method} ${t.path}`),e.setRequestLogs(r=>[{id:crypto.randomUUID(),time:Date.now(),method:t.method,endpoint:t.path,account:s(e.config?.profile,e.showEmails),model:typeof a==`object`&&a&&`model`in a?String(a.model||e.config?.settings.defaultModel||`-`):e.config?.settings.defaultModel||`-`,statusCode:f.status,durationMs:performance.now()-n,source:`管理台`},...r].slice(0,20)),e.config?.profile&&e.refreshConfig({silent:!0}).catch(()=>void 0)}catch(n){let r=y(n);u(r),S([`${t.method} ${t.path}(失败)`,...i,`错误: ${r}`].join(`
3
3
  `)),e.setStatus(`请求失败。`)}finally{e.setBusy(null)}}async function B(t,n){if(!t.type.startsWith(`image/`)){e.setStatus(`请选择图片文件。`);return}try{if(n===`image-bed`){e.setBusy(`image-bed-upload`);let n=await _(t);i(d(r,(await v(`/_gateway/image-bed/upload`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({filename:t.name,dataUrl:n})})).url,e.config?.settings.defaultModel||`gpt-image-2`)),e.setStatus(`已上传到图床并写入公网链接(${t.name},${o(t.size)})。`);return}i(d(r,await _(t),e.config?.settings.defaultModel||`gpt-image-2`)),e.setStatus(`已将 ${t.name} 转成 base64 data URL,并写入请求体 images[0].image_url(${o(t.size)})。`)}catch(t){e.setStatus(`图片写入失败: ${y(t)}`)}finally{n===`image-bed`&&e.setBusy(null)}}return(0,T.jsx)(E,{config:e.config,endpoints:M,activeEndpoint:N,endpoint:t,requestBody:r,responseBody:a,timingBody:f,resultTab:C,status:e.status,busy:e.busy,previewImages:O,capability:e.capability,imageUploadMode:A,onEndpoint:P,onRequestBody:i,onResultTab:D,onRun:z,onResetExample:F,onCopyRequest:I,onCopyResponse:L,onCopyTiming:R,onImageUploadMode:j,onPreview:e.setPreviewImage,onImageUpload:B})}export{D as TesterPage};
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="icon" type="image/svg+xml" href="/assets/app-mark-nsRs4vo7.svg" />
7
7
  <title>AI Zero Token</title>
8
- <script type="module" crossorigin src="/assets/index-DRe-tByu.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-rgcJgVAu.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/jsx-runtime-DqpGtLhh.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/profiles-DMOjJORP.js">
11
11
  <link rel="stylesheet" crossorigin href="/assets/index-By4r-wy3.css">
Binary file
@@ -138,6 +138,80 @@ function extractOutputText(payload) {
138
138
  }
139
139
  return "";
140
140
  }
141
+ function asRecord(value) {
142
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
143
+ }
144
+ function optionalString(value) {
145
+ return typeof value === "string" && value ? value : void 0;
146
+ }
147
+ function stringifyToolArguments(value) {
148
+ if (typeof value === "string") {
149
+ return value;
150
+ }
151
+ if (typeof value === "undefined" || value === null) {
152
+ return "";
153
+ }
154
+ try {
155
+ return JSON.stringify(value);
156
+ } catch {
157
+ return String(value);
158
+ }
159
+ }
160
+ function upsertFunctionCall(items, value) {
161
+ const record = asRecord(value);
162
+ if (!record || record.type !== "function_call") {
163
+ return;
164
+ }
165
+ const name = optionalString(record.name);
166
+ const id = optionalString(record.call_id) ?? optionalString(record.id);
167
+ if (!name || !id) {
168
+ return;
169
+ }
170
+ items.set(id, {
171
+ id,
172
+ type: "function",
173
+ function: {
174
+ name,
175
+ arguments: stringifyToolArguments(record.arguments)
176
+ }
177
+ });
178
+ }
179
+ function appendFunctionCallArgumentsDelta(items, argumentDeltas, event) {
180
+ if (event.type !== "response.function_call_arguments.delta") {
181
+ return;
182
+ }
183
+ const itemId = optionalString(event.item_id) ?? optionalString(event.call_id);
184
+ if (!itemId || typeof event.delta !== "string") {
185
+ return;
186
+ }
187
+ argumentDeltas.set(itemId, `${argumentDeltas.get(itemId) ?? ""}${event.delta}`);
188
+ const existing = items.get(itemId);
189
+ if (existing) {
190
+ existing.function.arguments = argumentDeltas.get(itemId) ?? existing.function.arguments;
191
+ }
192
+ }
193
+ function extractToolCalls(responsePayload, events) {
194
+ const calls = /* @__PURE__ */ new Map();
195
+ const argumentDeltas = /* @__PURE__ */ new Map();
196
+ const response = asRecord(responsePayload);
197
+ const output = Array.isArray(response?.output) ? response.output : [];
198
+ for (const item of output) {
199
+ upsertFunctionCall(calls, item);
200
+ }
201
+ for (const event of events) {
202
+ if (event.type === "response.output_item.added" || event.type === "response.output_item.done") {
203
+ upsertFunctionCall(calls, event.item);
204
+ }
205
+ appendFunctionCallArgumentsDelta(calls, argumentDeltas, event);
206
+ }
207
+ for (const [id, argumentsDelta] of argumentDeltas) {
208
+ const existing = calls.get(id);
209
+ if (existing && !existing.function.arguments) {
210
+ existing.function.arguments = argumentsDelta;
211
+ }
212
+ }
213
+ return Array.from(calls.values()).filter((call) => call.function.name);
214
+ }
141
215
  function parseSseEvents(body) {
142
216
  const events = [];
143
217
  for (const chunk of body.split("\n\n")) {
@@ -249,6 +323,7 @@ function extractCodexText(body, requestBody) {
249
323
  }
250
324
  }
251
325
  const completedText = extractOutputText(responsePayload);
326
+ const toolCalls = extractToolCalls(responsePayload, events);
252
327
  const artifacts = [
253
328
  ...collectArtifactCandidates(responsePayload, "response"),
254
329
  ...collectArtifactCandidates(events, "event")
@@ -256,6 +331,7 @@ function extractCodexText(body, requestBody) {
256
331
  if (completedText) {
257
332
  return {
258
333
  text: completedText,
334
+ toolCalls,
259
335
  raw: {
260
336
  request: requestBody,
261
337
  response: responsePayload ?? null,
@@ -266,6 +342,7 @@ function extractCodexText(body, requestBody) {
266
342
  }
267
343
  return {
268
344
  text: accumulated.trim(),
345
+ toolCalls,
269
346
  raw: {
270
347
  request: requestBody,
271
348
  response: responsePayload ?? null,
@@ -23,6 +23,7 @@ class ChatService {
23
23
  provider,
24
24
  model,
25
25
  text: result.text,
26
+ toolCalls: result.toolCalls,
26
27
  raw: result.raw,
27
28
  artifacts: result.artifacts
28
29
  };