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

配置每次落盘都打顶层 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
+38 -1
View File
@@ -30,6 +30,7 @@ import {
} from '../vendor/config-editor/index.ts'
import type { ConfigDiagnostic, ConfigObject } from '../vendor/config-editor/index.ts'
import { restoreInlineCommentAlignment } from '../shared/yaml-cosmetics.ts'
import { withMarker } from '../shared/config-marker.ts'
import { kernelVersion, validateConfigFile, reloadConfig } from './kernel.ts'
import type { Env } from './env.ts'
@@ -133,7 +134,10 @@ export async function applyConfig(
return `${stage} ${String(ms)}ms`
}
const nextYaml = rewriteYaml(current.yaml, nextData)
// 每次落盘都打上 Patchbay 标记(顶层 patchbay: 键,内核忽略未知键)。
// 上传配置时靠它认「这是 Patchbay 管理过的配置」。标记是幂等的,
// 已带标记的配置重打一遍内容不变,不影响下面的「内容没变就短路」
const nextYaml = rewriteYaml(current.yaml, withMarker(nextData))
// 内容没变就不要走后面那一串——不必要的备份和重载只会制造噪音。
if (nextYaml === current.yaml) {
@@ -282,6 +286,39 @@ async function pruneBackups(env: Env): Promise<void> {
await Promise.all(stale.map((name) => unlink(join(dir, name)).catch(() => {})))
}
/**
* 用上传的 YAML 原文整份替换当前配置。
*
* 解析用和读配置同一个引擎,之后走 applyConfig 完整的保护链路(自检、备份、
* 重载、失败回退)。没有 baseRevision——整份替换本来就是覆盖语义,同还原备份。
*/
export async function importConfig(env: Env, content: string): Promise<ApplyOutcome> {
let data: ConfigObject
try {
const doc = openDocument(content)
const broken = doc.diagnostics.filter((d) => d.severity === 'error')
if (broken.length > 0) {
return {
ok: false,
stage: 'self-check',
message: broken.map((p) => `${p.path.join('.')}:${p.message}`).join('\n'),
hint: '上传的文件解析不过,当前配置没有被改动。',
restored: false,
}
}
data = doc.data
} catch (error) {
return {
ok: false,
stage: 'self-check',
message: `上传的文件不是合法的 YAML:${String(error)}`,
hint: '当前配置没有被改动。',
restored: false,
}
}
return applyConfig(env, data)
}
/** 把某个备份恢复成当前配置。走的是和普通改动同一条保护链路。 */
export async function restoreBackup(env: Env, name: string): Promise<ApplyOutcome> {
const dir = await backupDir(env)