设置页重做:配置文件下载上传、内核参数、资源、免责声明

配置每次落盘都打顶层 patchbay: 标记(盐加版本的哈希)。内核忽略未知
顶层键(yaml.Unmarshal 没开严格模式,config/config.go:612)。刻意不对
内容做哈希:本项目只接管部分段落,手改其余段落是正常用法,内容哈希
会把合法手改判成无效。上传配置时靠标记分流:有标记的确认后替换,
没有的用更重的措辞确认导入;两者都走 config-store 完整保护链路
(新端点 POST /api/config/import)。自动备份列表从界面撤下,改成
下载当前配置 + 拖放上传。

内核参数一组编辑五个老式顶层端口和 keep-alive-interval(config.go:444,
整数秒),走带基准指纹的保存链路。资源一组接 POST /configs/geo
(同步接口,透传给了 300 秒超时)。测速地址成为本地偏好,延迟测试
读它;prefs 模块顶层的浏览器全局加了存在性守卫——api.ts 开始引用
prefs,而 bun test 环境没有 localStorage。

退出登录挪到侧栏底部;密度设置从设置页撤下(侧栏按钮还在);
免责声明和关于做成子页(左上角返回),登录页输入框下加同一份
免责声明的弹层入口。
This commit is contained in:
2026-08-12 01:01:33 +08:00
parent 013f537eaa
commit 8eb98e2e9a
12 changed files with 792 additions and 147 deletions
+30 -4
View File
@@ -7,12 +7,10 @@
import type { ConfigDiagnostic, ConfigObject } from '../vendor/config-editor/index.ts'
import type { ConnectionSnapshot } from '@shared/connections.ts'
import type { ExitProbe, HostInfo } from '@shared/host-info.ts'
import { DEFAULT_TEST_URL, testUrl } from './prefs'
const TOKEN_KEY = 'patchbay.token'
/** 测延迟用的目标。204 空响应,体积最小,全球都有部署。 */
const TEST_URL = 'https://www.gstatic.com/generate_204'
export function getToken(): string {
return localStorage.getItem(TOKEN_KEY) ?? ''
}
@@ -144,6 +142,26 @@ export const api = {
listBackups: () => request<{ backups: string[] }>('GET', '/api/config/backups'),
/** 配置文件的原文,给「下载当前配置」用。 */
configRaw: async (): Promise<string> => {
const res = await fetch('/api/config/raw', {
headers: { Authorization: `Bearer ${getToken()}` },
})
if (!res.ok) {
const text = await res.text()
const payload = text ? (JSON.parse(text) as Record<string, unknown>) : {}
throw new ApiError(res.status, payload)
}
return res.text()
},
/**
* 用上传的 YAML 原文整份替换当前配置。走服务端完整的保护链路
* (校验、备份、重载、失败回退),没有 baseRevision——整份替换本来就是覆盖语义。
*/
importConfig: (content: string) =>
request<ApplySuccess>('POST', '/api/config/import', { content }),
restoreBackup: (name: string) =>
request<ApplySuccess>('POST', `/api/config/backups/${encodeURIComponent(name)}/restore`),
@@ -170,6 +188,12 @@ export const api = {
*/
restartKernel: () => request<{ ok: true }>('POST', '/api/kernel/restart'),
/**
* 让内核更新 GEO 数据库(GEOIP、GEOSITE、MMDB、ASN)。
* 同步接口,下载完才回话,可能要等上几十秒。
*/
updateGeo: () => request<{ ok: true }>('POST', '/api/kernel/geo'),
/**
* 打开一个持续吐数据的流式接口(/traffic、/memory),每秒一行 JSON。
*
@@ -222,7 +246,9 @@ export const api = {
* 订阅线路不在表里(那正是它们无法被入站直接引用的原因),只能从所属订阅进去测。
*/
testLine: (name: string, provider?: string, timeout = 5000) => {
const q = `url=${encodeURIComponent(TEST_URL)}&timeout=${String(timeout)}`
// 测速地址是设置页里的偏好,空值退回默认
const target = testUrl.value.trim() || DEFAULT_TEST_URL
const q = `url=${encodeURIComponent(target)}&timeout=${String(timeout)}`
const path = provider
? `/api/kernel/providers/proxies/${encodeURIComponent(provider)}/${encodeURIComponent(name)}/healthcheck?${q}`
: `/api/kernel/proxies/${encodeURIComponent(name)}/delay?${q}`