Split flat v0 credentials.json into version=1 schema with provider sections (asr/llm), each keyed by providerId. Add automatic migration on first load with safe backup of the original v0 file. - New types: CredentialsSchemaV1, CredentialsProviderASRVolcengine, CredentialsProviderLLMArk, CredentialsActiveSelection - New CredentialsError enum: unparseable / futureVersion / ioError / backupFailed / writeFailed - Pure migration function (CredentialsMigration.parseAndMigrate) for unit testability — no disk I/O - Vault: atomic write via tmp + replaceItemAt, mode 0600 preserved - Backup format: credentials.v0.bak.<timestamp>[-N].json - Existing public API (get/set/remove/snapshot, CredentialAccount constants) is unchanged so SettingsHubTab / Sidebar continue to work - New OpenLessPersistenceTests target with 13 migration tests covering fresh install, full v0, partial v0 (asr-only / llm-only), empty ark.endpoint default, future-version safety, damaged-JSON safety, backup-name conflict suffix, idempotent save, atomic write, and 0600 permissions
22 lines
758 B
Swift
22 lines
758 B
Swift
import Foundation
|
|
|
|
/// 凭据存储相关错误。
|
|
///
|
|
/// `unparseable` / `futureVersion` 都意味着**不要碰原文件**,让用户自己处理或上报。
|
|
public enum CredentialsError: Error, Sendable, Equatable {
|
|
/// 文件存在但 JSON 解析失败。携带文件 URL,方便给用户显示具体路径。
|
|
case unparseable(URL)
|
|
|
|
/// 文件版本号超过当前代码支持的范围。携带读到的版本号。
|
|
case futureVersion(Int)
|
|
|
|
/// 通用 IO 错误(读 / 创建目录等)。携带可读描述。
|
|
case ioError(String)
|
|
|
|
/// 备份 v0 文件失败。携带备份目标 URL。
|
|
case backupFailed(URL)
|
|
|
|
/// 写入 v1 文件失败。携带目标 URL 和失败描述。
|
|
case writeFailed(URL, String)
|
|
}
|