diff --git a/src-tauri/locales/en.json b/src-tauri/locales/en.json
index 2c0f476..bedde3d 100644
--- a/src-tauri/locales/en.json
+++ b/src-tauri/locales/en.json
@@ -708,6 +708,37 @@
"confirm_import": "Confirm Import",
"export_import_config_description": "Export current configuration or restore configuration from file",
"confirm_import_description": "Importing configuration will overwrite all current settings and automatically restart the software. Continue?",
- "password_obscured_hint": "Password is obscured by rclone and cannot be displayed. Please re-enter to modify"
+"password_obscured_hint": "Password is obscured by rclone and cannot be displayed. Please re-enter to modify",
+
+ "error_boundary_title": "An error occurred",
+ "error_boundary_subtitle": "The application encountered a problem, but your data is safe",
+ "reload": "Reload",
+ "validation_storage_name_empty": "Storage name cannot be empty",
+ "validation_storage_name_too_long": "Storage name length cannot exceed 128 characters",
+ "validation_storage_name_invalid_chars": "Storage name contains invalid characters",
+ "validation_storage_type_empty": "Storage type cannot be empty",
+ "validation_storage_params_empty": "Storage parameters cannot be empty",
+ "validation_input_invalid": "Invalid input parameters",
+ "error_unsupported_storage_type": "Unsupported storage type",
+ "error_storage_params_serialization": "Storage parameter serialization failed",
+ "error_storage_id_not_found": "Cannot get storage ID",
+ "error_operation_failed": "Operation failed",
+ "error_unsupported_framework": "Unsupported storage framework",
+ "error_storage_network_failure": "Storage operation failed, please check network connection",
+ "error_network": "Network connection failed, please check network settings",
+ "error_api": "Server request failed, please try again later",
+ "error_validation": "Invalid input data, please check and try again",
+ "error_auth": "Login expired, please login again",
+ "error_forbidden": "No permission to perform this operation",
+ "error_not_found": "Requested resource not found",
+ "error_timeout": "Request timeout, please try again later",
+ "error_file_system": "File operation failed",
+ "error_config": "Configuration error",
+ "error_unknown": "An unknown error occurred, please try again later",
+ "error_auth_failed": "Authentication failed",
+ "error_no_permission": "No permission",
+ "error_resource_not_found": "{{resource}} not found",
+ "error_operation_timeout": "{{operation}} operation timeout",
+ "no_logs": "No logs"
}
diff --git a/src-tauri/locales/zh-cn.json b/src-tauri/locales/zh-cn.json
index a29c7ca..960f467 100644
--- a/src-tauri/locales/zh-cn.json
+++ b/src-tauri/locales/zh-cn.json
@@ -718,5 +718,36 @@
"proxy_range": "Proxy Range",
"app_id": "App ID",
"sign_key": "Sign Key",
- "password_obscured_hint": "密码已被rclone混淆存储,无法显示原始值,如需修改请重新输入"
+ "password_obscured_hint": "密码已被rclone混淆存储,无法显示原始值,如需修改请重新输入",
+
+ "error_boundary_title": "出现错误",
+ "error_boundary_subtitle": "应用遇到了问题,但别担心,数据是安全的",
+ "reload": "重新加载",
+ "validation_storage_name_empty": "存储名称不能为空",
+ "validation_storage_name_too_long": "存储名称长度不能超过128字符",
+ "validation_storage_name_invalid_chars": "存储名称包含非法字符",
+ "validation_storage_type_empty": "存储类型不能为空",
+ "validation_storage_params_empty": "存储参数不能为空",
+ "validation_input_invalid": "输入参数无效",
+ "error_unsupported_storage_type": "不支持的存储类型",
+ "error_storage_params_serialization": "存储参数序列化失败",
+ "error_storage_id_not_found": "无法获取存储 ID",
+ "error_operation_failed": "操作失败",
+ "error_unsupported_framework": "不支持的存储框架",
+ "error_storage_network_failure": "存储操作失败,请检查网络连接",
+ "error_network": "网络连接失败,请检查网络设置",
+ "error_api": "服务器请求失败,请稍后重试",
+ "error_validation": "输入数据有误,请检查后重试",
+ "error_auth": "登录已过期,请重新登录",
+ "error_forbidden": "没有权限执行此操作",
+ "error_not_found": "请求的资源不存在",
+ "error_timeout": "请求超时,请稍后重试",
+ "error_file_system": "文件操作失败",
+ "error_config": "配置错误",
+ "error_unknown": "发生未知错误,请稍后重试",
+ "error_auth_failed": "认证失败",
+ "error_no_permission": "没有权限",
+ "error_resource_not_found": "{{resource}} 不存在",
+ "error_operation_timeout": "{{operation}} 操作超时",
+ "no_logs": "暂无日志"
}
\ No newline at end of file
diff --git a/src-tauri/locales/zh-hant.json b/src-tauri/locales/zh-hant.json
index 88e95ed..7d937d2 100644
--- a/src-tauri/locales/zh-hant.json
+++ b/src-tauri/locales/zh-hant.json
@@ -708,6 +708,37 @@
"confirm_import": "確認導入",
"export_import_config_description": "導出當前配置或者從文件恢復配置",
"confirm_import_description": "導入配置將覆蓋當前所有配置並自動重啓軟件,是否繼續?",
- "password_obscured_hint": "密碼已被rclone混淆存儲,無法顯示原始值,如需修改請重新輸入"
+"password_obscured_hint": "密碼已被rclone混淆存儲,無法顯示原始值,如需修改請重新輸入",
+
+ "error_boundary_title": "出現錯誤",
+ "error_boundary_subtitle": "應用遇到了問題,但不用擔心,數據是安全的",
+ "reload": "重新載入",
+ "validation_storage_name_empty": "存儲名稱不能為空",
+ "validation_storage_name_too_long": "存儲名稱長度不能超過128字符",
+ "validation_storage_name_invalid_chars": "存儲名稱包含非法字符",
+ "validation_storage_type_empty": "存儲類型不能為空",
+ "validation_storage_params_empty": "存儲參數不能為空",
+ "validation_input_invalid": "輸入參數無效",
+ "error_unsupported_storage_type": "不支持的存儲類型",
+ "error_storage_params_serialization": "存儲參數序列化失敗",
+ "error_storage_id_not_found": "無法獲取存儲 ID",
+ "error_operation_failed": "操作失敗",
+ "error_unsupported_framework": "不支持的存儲框架",
+ "error_storage_network_failure": "存儲操作失敗,請檢查網絡連接",
+ "error_network": "網絡連接失敗,請檢查網絡設置",
+ "error_api": "服務器請求失敗,請稍後重試",
+ "error_validation": "輸入數據有誤,請檢查後重試",
+ "error_auth": "登錄已過期,請重新登錄",
+ "error_forbidden": "沒有權限執行此操作",
+ "error_not_found": "請求的資源不存在",
+ "error_timeout": "請求超時,請稍後重試",
+ "error_file_system": "文件操作失敗",
+ "error_config": "配置錯誤",
+ "error_unknown": "發生未知錯誤,請稍後重試",
+ "error_auth_failed": "認證失敗",
+ "error_no_permission": "沒有權限",
+ "error_resource_not_found": "{{resource}} 不存在",
+ "error_operation_timeout": "{{operation}} 操作超時",
+ "no_logs": "暫無日誌"
}
diff --git a/src/components/ErrorBoundary.tsx b/src/components/ErrorBoundary.tsx
index 9fc1d74..de89301 100644
--- a/src/components/ErrorBoundary.tsx
+++ b/src/components/ErrorBoundary.tsx
@@ -17,6 +17,7 @@
*/
import { Component, ErrorInfo, ReactNode, JSX } from 'react'
+import { useTranslation } from 'react-i18next'
import { Button, Card, Result, Space, Typography } from '@arco-design/web-react'
import { IconRefresh, IconBug } from '@arco-design/web-react/icon'
import { logger } from '../services/LoggerService'
@@ -54,6 +55,7 @@ interface DefaultErrorFallbackProps {
}
function DefaultErrorFallback({ error, onReset }: DefaultErrorFallbackProps): JSX.Element {
+ const { t } = useTranslation()
return (
}
- title="出现错误"
- subTitle="应用遇到了问题,但别担心,数据是安全的"
+ title={t('error_boundary_title')}
+ subTitle={t('error_boundary_subtitle')}
>
} onClick={onReset}>
- 重新加载
+ {t('reload')}
diff --git a/src/controller/storage/create.ts b/src/controller/storage/create.ts
index b7668bb..5a7dc92 100644
--- a/src/controller/storage/create.ts
+++ b/src/controller/storage/create.ts
@@ -1,4 +1,5 @@
import { Message } from '@arco-design/web-react'
+import { t } from 'i18next'
import { ParametersType } from '../../type/defaults'
import { openlist_api_post } from '../../utils/openlist/request'
import { rclone_api_post } from '../../utils/rclone/request'
@@ -12,17 +13,16 @@ import { logger } from '../../services/LoggerService'
*/
function validateStorageName(name: string): string | null {
if (!name || typeof name !== 'string') {
- return '存储名称不能为空'
+ return t('validation_storage_name_empty')
}
if (name.trim().length === 0) {
- return '存储名称不能为空'
+ return t('validation_storage_name_empty')
}
if (name.length > 128) {
- return '存储名称长度不能超过128字符'
+ return t('validation_storage_name_too_long')
}
- // 检查非法字符
if (/[<>:"|?*/\\]/.test(name)) {
- return '存储名称包含非法字符'
+ return t('validation_storage_name_invalid_chars')
}
return null
}
@@ -32,7 +32,7 @@ function validateStorageName(name: string): string | null {
*/
function validateStorageType(type: string): string | null {
if (!type || typeof type !== 'string') {
- return '存储类型不能为空'
+ return t('validation_storage_type_empty')
}
return null
}
@@ -42,7 +42,7 @@ function validateStorageType(type: string): string | null {
*/
function validateParameters(parameters: ParametersType): string | null {
if (!parameters || typeof parameters !== 'object') {
- return '存储参数不能为空'
+ return t('validation_storage_params_empty')
}
return null
}
@@ -77,14 +77,14 @@ async function createStorage(
// 输入验证
const validation = validateStorageInput(name, type, parameters)
if (!validation.valid) {
- Message.error(validation.error || '输入参数无效')
+ Message.error(validation.error || t('validation_input_invalid'))
logger.error('Storage validation failed', undefined, 'StorageCreate', { error: validation.error })
return false
}
const storageInfo = searchStorageInfo(type)
if (!storageInfo) {
- Message.error('不支持的存储类型: ' + type)
+ Message.error(t('error_unsupported_storage_type') + ': ' + type)
logger.error('Storage type not found', undefined, 'StorageCreate', { type })
return false
}
@@ -117,7 +117,7 @@ async function createStorage(
serializedAddition = JSON.stringify(parameters.addition)
} catch (e) {
logger.error('Failed to serialize addition', e as Error, 'StorageCreate')
- Message.error('存储参数序列化失败')
+ Message.error(t('error_storage_params_serialization'))
return false
}
@@ -135,7 +135,7 @@ async function createStorage(
// 更新现有存储
const storageId = storage.other?.openlist?.id
if (!storageId) {
- Message.error('无法获取存储 ID')
+ Message.error(t('error_storage_id_not_found'))
return false
}
backData = await openlist_api_post('/api/admin/storage/update', {
@@ -145,7 +145,7 @@ async function createStorage(
}
if (backData.code !== 200) {
- Message.error(backData.message || '操作失败')
+ Message.error(backData.message || t('error_operation_failed'))
return false
}
@@ -154,12 +154,12 @@ async function createStorage(
}
default:
- Message.error('不支持的存储框架: ' + storageInfo.framework)
+ Message.error(t('error_unsupported_framework') + ': ' + storageInfo.framework)
return false
}
} catch (error) {
logger.error('Storage operation failed', error as Error, 'StorageCreate')
- Message.error('存储操作失败,请检查网络连接')
+ Message.error(t('error_storage_network_failure'))
return false
}
}
diff --git a/src/page/setting/setting.tsx b/src/page/setting/setting.tsx
index 8ba5204..f59a238 100644
--- a/src/page/setting/setting.tsx
+++ b/src/page/setting/setting.tsx
@@ -23,7 +23,7 @@ export default function Setting_page() {
const showLogFromFileTail = async (path: string) => {
try {
const content = await readTextFileTail(path, { maxBytes: 256 * 1024, allowMissing: true })
- showLog(modal, (content || '').trim() ? content : '暂无日志')
+ showLog(modal, (content || '').trim() ? content : t('no_logs'))
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
Message.error(msg)
diff --git a/src/services/ErrorService.ts b/src/services/ErrorService.ts
index 1c0fa0d..0b2cc2c 100644
--- a/src/services/ErrorService.ts
+++ b/src/services/ErrorService.ts
@@ -2,239 +2,18 @@
* Error Service - 统一的错误处理服务
*
* 特性:
- * 1. 统一的错误类型和分类
- * 2. 错误转换和包装
- * 3. 用户友好的错误消息(支持i18n)
- * 4. 自动UI提示(Message/Notification)
- * 5. 内存错误日志
- * 6. 与 LoggerService 集成
+ * 1. 统一的错误处理
+ * 2. 自动UI提示(Message/Notification)
+ * 3. 内存错误日志
+ * 4. 与 LoggerService 集成
*/
import { Message, Notification } from '@arco-design/web-react'
import { t } from 'i18next'
import { logger } from './LoggerService'
+import { AppError, ErrorCategory, ErrorSeverity } from './AppError'
-// ============================================
-// 错误类型枚举
-// ============================================
-export enum ErrorCategory {
- NETWORK = 'NETWORK', // 网络错误
- API = 'API', // API 错误
- VALIDATION = 'VALIDATION', // 验证错误
- AUTHENTICATION = 'AUTH', // 认证错误
- AUTHORIZATION = 'FORBIDDEN', // 权限错误
- NOT_FOUND = 'NOT_FOUND', // 资源不存在
- TIMEOUT = 'TIMEOUT', // 超时错误
- FILE_SYSTEM = 'FILE_SYSTEM', // 文件系统错误
- CONFIGURATION = 'CONFIG', // 配置错误
- UNKNOWN = 'UNKNOWN', // 未知错误
-}
-
-// ============================================
-// 错误严重级别
-// ============================================
-export enum ErrorSeverity {
- LOW = 'low', // 轻微问题,可忽略
- MEDIUM = 'medium', // 一般问题,需要关注
- HIGH = 'high', // 严重问题,需要处理
- CRITICAL = 'critical', // 关键问题,影响核心功能
-}
-
-// ============================================
-// 应用错误类
-// ============================================
-export class AppError extends Error {
- readonly category: ErrorCategory
- readonly severity: ErrorSeverity
- readonly code: string
- readonly context?: Record
- readonly timestamp: Date
- readonly originalError?: Error
-
- constructor(
- message: string,
- category: ErrorCategory = ErrorCategory.UNKNOWN,
- severity: ErrorSeverity = ErrorSeverity.MEDIUM,
- code: string = 'UNKNOWN_ERROR',
- context?: Record,
- originalError?: Error
- ) {
- super(message)
- this.name = 'AppError'
- this.category = category
- this.severity = severity
- this.code = code
- this.context = context
- this.timestamp = new Date()
- this.originalError = originalError
-
- // 保持堆栈跟踪
- if ('captureStackTrace' in Error && typeof Error.captureStackTrace === 'function') {
- Error.captureStackTrace(this, AppError)
- }
- }
-
- /**
- * 获取用户友好的错误消息(支持 i18n)
- */
- getUserMessage(): string {
- // 尝试使用国际化消息
- const i18nKey = `errors.${this.code}`
- const i18nMessage = t(i18nKey, { defaultValue: '' })
- if (i18nMessage) {
- return i18nMessage
- }
-
- // 开发环境:记录缺失的 i18n key
- if (import.meta.env.DEV && !i18nMessage) {
- logger.warn(`Missing i18n key: ${i18nKey}`, 'ErrorService', { code: this.code, category: this.category })
- }
-
- // 回退到默认分类消息
- const messages: Record = {
- [ErrorCategory.NETWORK]: '网络连接失败,请检查网络设置',
- [ErrorCategory.API]: '服务器请求失败,请稍后重试',
- [ErrorCategory.VALIDATION]: '输入数据有误,请检查后重试',
- [ErrorCategory.AUTHENTICATION]: '登录已过期,请重新登录',
- [ErrorCategory.AUTHORIZATION]: '没有权限执行此操作',
- [ErrorCategory.NOT_FOUND]: '请求的资源不存在',
- [ErrorCategory.TIMEOUT]: '请求超时,请稍后重试',
- [ErrorCategory.FILE_SYSTEM]: '文件操作失败',
- [ErrorCategory.CONFIGURATION]: '配置错误',
- [ErrorCategory.UNKNOWN]: '发生未知错误,请稍后重试',
- }
-
- return messages[this.category] || this.message
- }
-
- /**
- * 是否应该显示给用户
- */
- shouldShowToUser(): boolean {
- return this.severity !== ErrorSeverity.LOW
- }
-
- /**
- * 是否应该上报
- */
- shouldReport(): boolean {
- return this.severity === ErrorSeverity.HIGH || this.severity === ErrorSeverity.CRITICAL
- }
-
- /**
- * 转换为 JSON 对象(生产环境不包含 stack trace)
- */
- toJSON(): Record {
- return {
- name: this.name,
- message: this.message,
- category: this.category,
- severity: this.severity,
- code: this.code,
- // 仅在开发环境包含 context,生产环境可能包含敏感数据
- context: import.meta.env.DEV ? this.context : undefined,
- timestamp: this.timestamp.toISOString(),
- // 仅在开发环境包含 stack trace,生产环境不暴露内部实现细节
- stack: import.meta.env.DEV ? this.stack : undefined,
- }
- }
-
- // ==========================================
- // 工厂方法
- // ==========================================
-
- static network(message: string, original?: Error, context?: Record): AppError {
- return new AppError(
- message,
- ErrorCategory.NETWORK,
- ErrorSeverity.HIGH,
- 'NETWORK_ERROR',
- context,
- original
- )
- }
-
- static api(
- message: string,
- code: string = 'API_ERROR',
- context?: Record,
- original?: Error
- ): AppError {
- return new AppError(message, ErrorCategory.API, ErrorSeverity.HIGH, code, context, original)
- }
-
- static validation(
- message: string,
- field?: string,
- context?: Record
- ): AppError {
- return new AppError(
- message,
- ErrorCategory.VALIDATION,
- ErrorSeverity.MEDIUM,
- 'VALIDATION_ERROR',
- { ...context, field }
- )
- }
-
- static auth(message: string = '认证失败'): AppError {
- return new AppError(message, ErrorCategory.AUTHENTICATION, ErrorSeverity.HIGH, 'AUTH_ERROR')
- }
-
- static forbidden(message: string = '没有权限'): AppError {
- return new AppError(
- message,
- ErrorCategory.AUTHORIZATION,
- ErrorSeverity.HIGH,
- 'FORBIDDEN_ERROR'
- )
- }
-
- static notFound(resource: string, context?: Record): AppError {
- return new AppError(
- `${resource} 不存在`,
- ErrorCategory.NOT_FOUND,
- ErrorSeverity.MEDIUM,
- 'NOT_FOUND_ERROR',
- context
- )
- }
-
- static timeout(operation: string, timeoutMs: number): AppError {
- return new AppError(
- `${operation} 操作超时`,
- ErrorCategory.TIMEOUT,
- ErrorSeverity.HIGH,
- 'TIMEOUT_ERROR',
- { timeout: timeoutMs }
- )
- }
-
- static fileSystem(message: string, original?: Error): AppError {
- return new AppError(
- message,
- ErrorCategory.FILE_SYSTEM,
- ErrorSeverity.HIGH,
- 'FILE_SYSTEM_ERROR',
- undefined,
- original
- )
- }
-
- static config(message: string): AppError {
- return new AppError(
- message,
- ErrorCategory.CONFIGURATION,
- ErrorSeverity.CRITICAL,
- 'CONFIG_ERROR'
- )
- }
-}
-
-// ============================================
-// 错误处理器类型
-// ============================================
-type ErrorHandler = (error: AppError) => void | Promise
+export { AppError, ErrorCategory, ErrorSeverity }
// ============================================
// 错误处理配置
@@ -257,15 +36,12 @@ const DEFAULT_HANDLER_CONFIG: ErrorHandlerConfig = {
// Error Service
// ============================================
class ErrorService {
- private handlers: ErrorHandler[] = []
+ private handlers: Array<(error: AppError) => void | Promise> = []
private globalHandler?: (error: AppError) => void
private errorLog: AppError[] = []
private maxLogSize = 100
- /**
- * 注册错误处理器
- */
- onError(handler: ErrorHandler): () => void {
+ onError(handler: (error: AppError) => void | Promise): () => void {
this.handlers.push(handler)
return () => {
const index = this.handlers.indexOf(handler)
@@ -275,16 +51,10 @@ class ErrorService {
}
}
- /**
- * 设置全局错误处理器
- */
setGlobalHandler(handler: (error: AppError) => void): void {
this.globalHandler = handler
}
- /**
- * 处理错误
- */
async handle(
error: unknown,
context?: string,
@@ -293,35 +63,25 @@ class ErrorService {
const mergedConfig = { ...DEFAULT_HANDLER_CONFIG, ...config }
const appError = this.normalize(error)
- // 记录错误到日志服务
- logger.error(
- appError.message,
- appError.originalError,
- context || 'ErrorService',
- {
- category: appError.category,
- severity: appError.severity,
- code: appError.code,
- ...appError.context,
- }
- )
+ logger.error(appError.message, appError.originalError, context || 'ErrorService', {
+ category: appError.category,
+ severity: appError.severity,
+ code: appError.code,
+ ...appError.context,
+ })
- // 记录到内存日志
if (mergedConfig.logToMemory) {
this.logToMemory(appError)
}
- // 显示UI提示
if (mergedConfig.showMessage) {
this.showMessage(appError)
}
- // 显示通知(仅严重错误)
if (mergedConfig.showNotification && appError.severity === ErrorSeverity.CRITICAL) {
this.showNotification(appError)
}
- // 调用注册的处理器
for (const handler of this.handlers) {
try {
await handler(appError)
@@ -330,12 +90,10 @@ class ErrorService {
}
}
- // 调用全局处理器
if (this.globalHandler) {
this.globalHandler(appError)
}
- // 是否重新抛出
if (mergedConfig.rethrow) {
throw appError
}
@@ -343,9 +101,6 @@ class ErrorService {
return appError
}
- /**
- * 记录到内存日志
- */
private logToMemory(error: AppError): void {
this.errorLog.unshift(error)
if (this.errorLog.length > this.maxLogSize) {
@@ -353,9 +108,6 @@ class ErrorService {
}
}
- /**
- * 显示消息提示
- */
private showMessage(error: AppError): void {
if (error.severity === ErrorSeverity.CRITICAL || error.severity === ErrorSeverity.HIGH) {
Message.error(error.getUserMessage())
@@ -364,9 +116,6 @@ class ErrorService {
}
}
- /**
- * 显示通知
- */
private showNotification(error: AppError): void {
Notification.error({
title: t('error'),
@@ -375,54 +124,29 @@ class ErrorService {
})
}
- /**
- * 获取错误日志
- */
getErrorLog(): AppError[] {
return [...this.errorLog]
}
- /**
- * 清除错误日志
- */
clearErrorLog(): void {
this.errorLog = []
}
- /**
- * 标准化错误为 AppError
- */
normalize(error: unknown): AppError {
if (error instanceof AppError) {
return error
}
if (error instanceof Error) {
- return new AppError(
- error.message,
- ErrorCategory.UNKNOWN,
- ErrorSeverity.MEDIUM,
- 'UNKNOWN_ERROR',
- { name: error.name },
- error
- )
+ return new AppError(error.message, ErrorCategory.UNKNOWN, ErrorSeverity.MEDIUM, 'UNKNOWN_ERROR', {
+ name: error.name,
+ }, error)
}
- return new AppError(
- String(error),
- ErrorCategory.UNKNOWN,
- ErrorSeverity.MEDIUM,
- 'UNKNOWN_ERROR'
- )
+ return new AppError(String(error), ErrorCategory.UNKNOWN, ErrorSeverity.MEDIUM, 'UNKNOWN_ERROR')
}
- /**
- * 包装异步函数,自动处理错误
- */
- wrap(
- fn: () => Promise,
- errorHandler?: (error: AppError) => void
- ): Promise {
+ wrap(fn: () => Promise, errorHandler?: (error: AppError) => void): Promise {
return fn().catch((error: unknown) => {
const appError = this.normalize(error)
this.handle(appError)
@@ -433,9 +157,6 @@ class ErrorService {
})
}
- /**
- * 创建安全的异步函数包装器
- */
safe Promise>(
fn: T,
context?: string
@@ -450,23 +171,12 @@ class ErrorService {
}
}
- /**
- * 验证条件,失败时抛出错误
- */
assert(condition: boolean, message: string, category?: ErrorCategory): void {
if (!condition) {
- throw new AppError(
- message,
- category || ErrorCategory.VALIDATION,
- ErrorSeverity.MEDIUM,
- 'ASSERTION_ERROR'
- )
+ throw new AppError(message, category || ErrorCategory.VALIDATION, ErrorSeverity.MEDIUM, 'ASSERTION_ERROR')
}
}
- /**
- * 验证值是否存在,不存在时抛出错误
- */
assertExists(value: T | null | undefined, name: string): T {
if (value === null || value === undefined) {
throw AppError.notFound(name)
@@ -486,10 +196,8 @@ export const errorService = new ErrorService()
export const handleError = (error: unknown, context?: string): Promise =>
errorService.handle(error, context)
-export const safe = Promise>(
- fn: T,
- context?: string
-) => errorService.safe(fn, context)
+export const safe = Promise>(fn: T, context?: string) =>
+ errorService.safe(fn, context)
export const assert = (condition: boolean, message: string, category?: ErrorCategory): void =>
errorService.assert(condition, message, category)