mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-04 11:43:57 +08:00
refactor: remove superseded dead code (#5916)
This commit is contained in:
@@ -1,98 +0,0 @@
|
||||
import { z } from "zod";
|
||||
import { validateToml, tomlToMcpServer } from "@/utils/tomlUtils";
|
||||
|
||||
/**
|
||||
* 解析 JSON 语法错误,返回更友好的位置信息。
|
||||
*/
|
||||
function parseJsonError(error: unknown): string {
|
||||
if (!(error instanceof SyntaxError)) {
|
||||
return "JSON 格式错误";
|
||||
}
|
||||
|
||||
const message = error.message || "JSON 解析失败";
|
||||
|
||||
// Chrome/V8: "Unexpected token ... in JSON at position 123"
|
||||
const positionMatch = message.match(/at position (\d+)/i);
|
||||
if (positionMatch) {
|
||||
const position = parseInt(positionMatch[1], 10);
|
||||
return `JSON 格式错误(位置:${position})`;
|
||||
}
|
||||
|
||||
// Firefox: "JSON.parse: unexpected character at line 1 column 23"
|
||||
const lineColumnMatch = message.match(/line (\d+) column (\d+)/i);
|
||||
if (lineColumnMatch) {
|
||||
const line = lineColumnMatch[1];
|
||||
const column = lineColumnMatch[2];
|
||||
return `JSON 格式错误:第 ${line} 行,第 ${column} 列`;
|
||||
}
|
||||
|
||||
return `JSON 格式错误:${message}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的 JSON 配置文本校验:
|
||||
* - 非空
|
||||
* - 可解析且为对象(非数组)
|
||||
*/
|
||||
export const jsonConfigSchema = z
|
||||
.string()
|
||||
.min(1, "配置不能为空")
|
||||
.superRefine((value, ctx) => {
|
||||
try {
|
||||
const obj = JSON.parse(value);
|
||||
if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "需为单个对象配置",
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: parseJsonError(e),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 通用的 TOML 配置文本校验:
|
||||
* - 允许为空(由上层业务决定是否必填)
|
||||
* - 语法与结构有效
|
||||
* - 针对 stdio/http/sse 的必填字段(command/url)进行提示
|
||||
*/
|
||||
export const tomlConfigSchema = z.string().superRefine((value, ctx) => {
|
||||
const err = validateToml(value);
|
||||
if (err) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: `TOML 无效:${err}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!value.trim()) return;
|
||||
|
||||
try {
|
||||
const server = tomlToMcpServer(value);
|
||||
if (server.type === "stdio" && !server.command?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "stdio 类型需填写 command",
|
||||
});
|
||||
}
|
||||
if (
|
||||
(server.type === "http" || server.type === "sse") &&
|
||||
!server.url?.trim()
|
||||
) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: `${server.type} 类型需填写 url`,
|
||||
});
|
||||
}
|
||||
} catch (e: any) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: e?.message || "TOML 解析失败",
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,42 +0,0 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const mcpServerSpecSchema = z
|
||||
.object({
|
||||
type: z.enum(["stdio", "http", "sse"]).optional(),
|
||||
command: z.string().trim().optional(),
|
||||
args: z.array(z.string()).optional(),
|
||||
env: z.record(z.string(), z.string()).optional(),
|
||||
cwd: z.string().optional(),
|
||||
url: z.string().trim().url("请输入有效的 URL").optional(),
|
||||
headers: z.record(z.string(), z.string()).optional(),
|
||||
})
|
||||
.superRefine((server, ctx) => {
|
||||
const type = server.type ?? "stdio";
|
||||
if (type === "stdio" && !server.command?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "stdio 类型需填写 command",
|
||||
path: ["command"],
|
||||
});
|
||||
}
|
||||
if ((type === "http" || type === "sse") && !server.url?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: `${type} 类型需填写 url`,
|
||||
path: ["url"],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export const mcpServerSchema = z.object({
|
||||
id: z.string().min(1, "请输入服务器 ID"),
|
||||
name: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
tags: z.array(z.string()).optional(),
|
||||
homepage: z.string().url().optional(),
|
||||
docs: z.string().url().optional(),
|
||||
enabled: z.boolean().optional(),
|
||||
server: mcpServerSpecSchema,
|
||||
});
|
||||
|
||||
export type McpServerFormData = z.infer<typeof mcpServerSchema>;
|
||||
@@ -1,80 +0,0 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const directorySchema = z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, "路径不能为空")
|
||||
.optional()
|
||||
.or(z.literal(""));
|
||||
|
||||
export const settingsSchema = z.object({
|
||||
// 设备级 UI 设置
|
||||
showInTray: z.boolean(),
|
||||
minimizeToTrayOnClose: z.boolean(),
|
||||
enableClaudePluginIntegration: z.boolean().optional(),
|
||||
skipClaudeOnboarding: z.boolean().optional(),
|
||||
launchOnStartup: z.boolean().optional(),
|
||||
enableLocalProxy: z.boolean().optional(),
|
||||
usageDashboardRefreshIntervalMs: z.number().optional(),
|
||||
preserveCodexOfficialAuthOnSwitch: z.boolean().optional(),
|
||||
unifyCodexSessionHistory: z.boolean().optional(),
|
||||
language: z.enum(["en", "zh", "zh-TW", "ja"]).optional(),
|
||||
|
||||
// 设备级目录覆盖
|
||||
claudeConfigDir: directorySchema.nullable().optional(),
|
||||
codexConfigDir: directorySchema.nullable().optional(),
|
||||
geminiConfigDir: directorySchema.nullable().optional(),
|
||||
grokConfigDir: directorySchema.nullable().optional(),
|
||||
opencodeConfigDir: directorySchema.nullable().optional(),
|
||||
openclawConfigDir: directorySchema.nullable().optional(),
|
||||
|
||||
// 当前供应商 ID(设备级)
|
||||
currentProviderClaude: z.string().optional(),
|
||||
currentProviderClaudeDesktop: z.string().optional(),
|
||||
currentProviderCodex: z.string().optional(),
|
||||
currentProviderGemini: z.string().optional(),
|
||||
|
||||
// Skill 同步设置
|
||||
skillSyncMethod: z.enum(["auto", "symlink", "copy"]).optional(),
|
||||
skillStorageLocation: z.enum(["cc_switch", "unified"]).optional(),
|
||||
|
||||
// WebDAV v2 同步设置(通过专用命令保存,schema 仅用于读取)
|
||||
webdavSync: z
|
||||
.object({
|
||||
enabled: z.boolean().optional(),
|
||||
autoSync: z.boolean().optional(),
|
||||
baseUrl: z.string().trim().optional().or(z.literal("")),
|
||||
username: z.string().trim().optional().or(z.literal("")),
|
||||
password: z.string().optional(),
|
||||
remoteRoot: z.string().trim().optional().or(z.literal("")),
|
||||
profile: z.string().trim().optional().or(z.literal("")),
|
||||
status: z
|
||||
.object({
|
||||
lastSyncAt: z.number().nullable().optional(),
|
||||
lastError: z.string().nullable().optional(),
|
||||
lastErrorSource: z.string().nullable().optional(),
|
||||
lastRemoteEtag: z.string().nullable().optional(),
|
||||
lastLocalManifestHash: z.string().nullable().optional(),
|
||||
lastRemoteManifestHash: z.string().nullable().optional(),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
.optional(),
|
||||
|
||||
// 本机自动迁移状态(后端维护且保存时后端忽略前端值,仅供读取展示)
|
||||
localMigrations: z
|
||||
.object({
|
||||
codexThirdPartyHistoryProviderBucketV1: z
|
||||
.object({
|
||||
completedAt: z.string(),
|
||||
targetProviderId: z.string(),
|
||||
sourceProviderIds: z.array(z.string()).optional(),
|
||||
migratedJsonlFiles: z.number().optional(),
|
||||
migratedStateRows: z.number().optional(),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export type SettingsFormData = z.infer<typeof settingsSchema>;
|
||||
Reference in New Issue
Block a user