feat(web): token 数以 K 输入显示,已存凭证显示掩码占位(FIX-8)

- 新增 UnitInput 与 kind=tokens:上下文预算、单次 token 上限、自定义模型上下文窗口以 K 输入(允许小数),存储仍为原始 token 数;校验与提示用 K 表述;列表/详情 token 数统一 K/M 简写(formatTokens)
- 新增 SecretInput 与 kind=secret:已保存时显示「已设置 ••••••••」(有服务端掩码时带末 4 位),聚焦直接输入替换,留空保持,「清除」确认后保存生效;替换模型服务、TMDB、网页搜索、下载器、媒体服务器、浏览器服务、站点账号、Passkey、本机 Token 各处
- 统一只写凭证服务端语义:省略或空串 = 不变,null = 清除(contracts secretInput);下载器/媒体服务器新增清除;站点凭证同类更新可留空保持密码/Cookie/API Key/TOTP,TOTP 可 null 清除,不再误删 TOTP 与 UA
- contextBudget 最小值 4096→4000、contextWindow 1024→1000,便于按 K 填写
- 测试:换算与校验、SecretInput 渲染与状态、各接口留空不变/显式清除

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-30 00:10:46 +08:00
1 parent 68f53390f6
commit fa344a7184
39 files changed
+1175 -232

No files matched your search

+15
View File
@@ -8,6 +8,21 @@ export type Id = z.infer<typeof Id>;
export const Timestamp = z.iso.datetime({ offset: true });
export type Timestamp = z.infer<typeof Timestamp>;
/**
* 只写凭证输入(API Key、密码、Cookie、令牌)。全站统一语义:
* 省略或空串(含纯空白)= 保持原值;null = 清除(只在允许清除的更新接口上);非空 = 替换。
* 明文只在请求里出现,服务端加密为 secret 后丢弃,响应只给是否已设置(和个别接口的掩码)。
*/
export const WriteOnlySecret = (max = 4096) => z.string().max(max);
/** 归一只写凭证输入:空串 → undefined(不改);null 原样(清除);其余去首尾空白 */
export function secretInput(v: string | null | undefined): string | null | undefined {
if (v === null) return null;
if (v === undefined) return undefined;
const s = v.trim();
return s === "" ? undefined : s;
}
/** 游标分页请求:cursor 为不透明字符串,由服务端编码 */
export const CursorQuery = z.object({
cursor: z.string().min(1).optional(),