feat: initial release v0.3.0
This commit is contained in:
197
src/lib/errors/codes.ts
Normal file
197
src/lib/errors/codes.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
export const ERROR_CATEGORY = {
|
||||
AUTH: 'AUTH',
|
||||
BILLING: 'BILLING',
|
||||
CONTENT: 'CONTENT',
|
||||
PROVIDER: 'PROVIDER',
|
||||
SYSTEM: 'SYSTEM',
|
||||
VALIDATION: 'VALIDATION',
|
||||
} as const
|
||||
|
||||
export type ErrorCategory = (typeof ERROR_CATEGORY)[keyof typeof ERROR_CATEGORY]
|
||||
|
||||
export const ERROR_CATALOG = {
|
||||
UNAUTHORIZED: {
|
||||
httpStatus: 401,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.AUTH,
|
||||
userMessageKey: 'errors.UNAUTHORIZED',
|
||||
defaultMessage: 'Unauthorized',
|
||||
},
|
||||
FORBIDDEN: {
|
||||
httpStatus: 403,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.AUTH,
|
||||
userMessageKey: 'errors.FORBIDDEN',
|
||||
defaultMessage: 'Forbidden',
|
||||
},
|
||||
NOT_FOUND: {
|
||||
httpStatus: 404,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.VALIDATION,
|
||||
userMessageKey: 'errors.NOT_FOUND',
|
||||
defaultMessage: 'Resource not found',
|
||||
},
|
||||
INVALID_PARAMS: {
|
||||
httpStatus: 400,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.VALIDATION,
|
||||
userMessageKey: 'errors.INVALID_PARAMS',
|
||||
defaultMessage: 'Invalid parameters',
|
||||
},
|
||||
MISSING_CONFIG: {
|
||||
httpStatus: 400,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.VALIDATION,
|
||||
userMessageKey: 'errors.MISSING_CONFIG',
|
||||
defaultMessage: 'Missing required configuration',
|
||||
},
|
||||
CONFLICT: {
|
||||
httpStatus: 409,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.VALIDATION,
|
||||
userMessageKey: 'errors.CONFLICT',
|
||||
defaultMessage: 'Conflict',
|
||||
},
|
||||
TASK_NOT_READY: {
|
||||
httpStatus: 202,
|
||||
retryable: true,
|
||||
category: ERROR_CATEGORY.SYSTEM,
|
||||
userMessageKey: 'errors.TASK_NOT_READY',
|
||||
defaultMessage: 'Task is not ready',
|
||||
},
|
||||
NO_RESULT: {
|
||||
httpStatus: 404,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.SYSTEM,
|
||||
userMessageKey: 'errors.NO_RESULT',
|
||||
defaultMessage: 'No task result',
|
||||
},
|
||||
RATE_LIMIT: {
|
||||
httpStatus: 429,
|
||||
retryable: true,
|
||||
category: ERROR_CATEGORY.PROVIDER,
|
||||
userMessageKey: 'errors.RATE_LIMIT',
|
||||
defaultMessage: 'Rate limit exceeded',
|
||||
},
|
||||
MODEL_NOT_OPEN: {
|
||||
httpStatus: 403,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.PROVIDER,
|
||||
userMessageKey: 'errors.MODEL_NOT_OPEN',
|
||||
defaultMessage: 'Model is not activated for this account',
|
||||
},
|
||||
MODEL_NOT_REGISTERED: {
|
||||
httpStatus: 400,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.PROVIDER,
|
||||
userMessageKey: 'errors.MODEL_NOT_REGISTERED',
|
||||
defaultMessage: 'Model is not registered',
|
||||
},
|
||||
QUOTA_EXCEEDED: {
|
||||
httpStatus: 429,
|
||||
retryable: true,
|
||||
category: ERROR_CATEGORY.PROVIDER,
|
||||
userMessageKey: 'errors.QUOTA_EXCEEDED',
|
||||
defaultMessage: 'Quota exceeded',
|
||||
},
|
||||
EXTERNAL_ERROR: {
|
||||
httpStatus: 502,
|
||||
retryable: true,
|
||||
category: ERROR_CATEGORY.PROVIDER,
|
||||
userMessageKey: 'errors.EXTERNAL_ERROR',
|
||||
defaultMessage: 'External service failed',
|
||||
},
|
||||
NETWORK_ERROR: {
|
||||
httpStatus: 502,
|
||||
retryable: true,
|
||||
category: ERROR_CATEGORY.PROVIDER,
|
||||
userMessageKey: 'errors.NETWORK_ERROR',
|
||||
defaultMessage: 'Network request failed',
|
||||
},
|
||||
EMPTY_RESPONSE: {
|
||||
httpStatus: 502,
|
||||
retryable: true,
|
||||
category: ERROR_CATEGORY.PROVIDER,
|
||||
userMessageKey: 'errors.EMPTY_RESPONSE',
|
||||
defaultMessage: 'Model returned empty response',
|
||||
},
|
||||
INSUFFICIENT_BALANCE: {
|
||||
httpStatus: 402,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.BILLING,
|
||||
userMessageKey: 'errors.INSUFFICIENT_BALANCE',
|
||||
defaultMessage: 'Insufficient balance',
|
||||
},
|
||||
SENSITIVE_CONTENT: {
|
||||
httpStatus: 422,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.CONTENT,
|
||||
userMessageKey: 'errors.SENSITIVE_CONTENT',
|
||||
defaultMessage: 'Sensitive content detected',
|
||||
},
|
||||
GENERATION_TIMEOUT: {
|
||||
httpStatus: 504,
|
||||
retryable: true,
|
||||
category: ERROR_CATEGORY.PROVIDER,
|
||||
userMessageKey: 'errors.GENERATION_TIMEOUT',
|
||||
defaultMessage: 'Generation timed out',
|
||||
},
|
||||
VIDEO_API_FORMAT_UNSUPPORTED: {
|
||||
httpStatus: 400,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.VALIDATION,
|
||||
userMessageKey: 'errors.VIDEO_API_FORMAT_UNSUPPORTED',
|
||||
defaultMessage: 'Video API format is unsupported',
|
||||
},
|
||||
GENERATION_FAILED: {
|
||||
httpStatus: 500,
|
||||
retryable: true,
|
||||
category: ERROR_CATEGORY.PROVIDER,
|
||||
userMessageKey: 'errors.GENERATION_FAILED',
|
||||
defaultMessage: 'Generation failed',
|
||||
},
|
||||
WATCHDOG_TIMEOUT: {
|
||||
httpStatus: 500,
|
||||
retryable: true,
|
||||
category: ERROR_CATEGORY.SYSTEM,
|
||||
userMessageKey: 'errors.WATCHDOG_TIMEOUT',
|
||||
defaultMessage: 'Task heartbeat timeout',
|
||||
},
|
||||
WORKER_EXECUTION_ERROR: {
|
||||
httpStatus: 500,
|
||||
retryable: true,
|
||||
category: ERROR_CATEGORY.SYSTEM,
|
||||
userMessageKey: 'errors.WORKER_EXECUTION_ERROR',
|
||||
defaultMessage: 'Worker execution failed',
|
||||
},
|
||||
INTERNAL_ERROR: {
|
||||
httpStatus: 500,
|
||||
retryable: false,
|
||||
category: ERROR_CATEGORY.SYSTEM,
|
||||
userMessageKey: 'errors.INTERNAL_ERROR',
|
||||
defaultMessage: 'Internal server error',
|
||||
},
|
||||
} as const
|
||||
|
||||
export type UnifiedErrorCode = keyof typeof ERROR_CATALOG
|
||||
|
||||
export const DEFAULT_ERROR_CODE: UnifiedErrorCode = 'INTERNAL_ERROR'
|
||||
|
||||
export const LEGACY_ERROR_CODE_ALIASES: Record<string, UnifiedErrorCode> = {
|
||||
OPERATION_FAILED: 'INTERNAL_ERROR',
|
||||
}
|
||||
|
||||
export function isKnownErrorCode(code: unknown): code is UnifiedErrorCode {
|
||||
return typeof code === 'string' && code in ERROR_CATALOG
|
||||
}
|
||||
|
||||
export function resolveUnifiedErrorCode(code: unknown): UnifiedErrorCode | null {
|
||||
if (isKnownErrorCode(code)) return code
|
||||
if (typeof code !== 'string') return null
|
||||
const normalized = code.trim().toUpperCase()
|
||||
return LEGACY_ERROR_CODE_ALIASES[normalized] || null
|
||||
}
|
||||
|
||||
export function getErrorSpec(code: UnifiedErrorCode) {
|
||||
return ERROR_CATALOG[code]
|
||||
}
|
||||
Reference in New Issue
Block a user