This commit is contained in:
2026-10-18 04:32:58 +07:00
parent e85d899fd7
commit c36d3fd314
14 changed files with 446 additions and 50 deletions
+77
View File
@@ -0,0 +1,77 @@
export const NETWORK_ERROR_CODES = [
'NETWORK',
'TIMEOUT',
'ABORTED',
'ENOTFOUND',
'EAI_AGAIN',
'ECONNREFUSED',
'ECONNRESET',
'ETIMEDOUT',
'UND_ERR_CONNECT_TIMEOUT',
'CERT_HAS_EXPIRED',
'DEPTH_ZERO_SELF_SIGNED_CERT',
'UNABLE_TO_VERIFY_LEAF_SIGNATURE',
'ERR_TLS_CERT_ALTNAME_INVALID',
] as const
export type NetworkErrorCode = (typeof NETWORK_ERROR_CODES)[number]
export class NetworkError extends Error {
constructor(
message: string,
public code: NetworkErrorCode = 'NETWORK',
) {
super(message)
}
}
export class SessionChangedError extends Error {
constructor() {
super('Сессия изменилась. Повторите подключение игры')
}
}
export class ApiError extends Error {
constructor(public status: number) {
super(
status === 401
? 'Сессия истекла. Войдите снова'
: status === 403
? 'Нет доступа к действию'
: status === 400
? 'Действие пока недоступно для этой игры'
: `Ошибка сервера: HTTP ${status}`,
)
}
}
function causeCode(error: unknown, depth = 0): NetworkErrorCode | undefined {
if (!error || typeof error !== 'object' || depth > 3) return
const value = error as { code?: unknown; cause?: unknown; errors?: unknown[] }
if (NETWORK_ERROR_CODES.includes(value.code as NetworkErrorCode))
return value.code as NetworkErrorCode
return (
causeCode(value.cause, depth + 1) ??
(Array.isArray(value.errors)
? value.errors.map((e) => causeCode(e, depth + 1)).find(Boolean)
: undefined)
)
}
export function networkFailure(error: unknown, signal: AbortSignal): NetworkError {
if (signal.aborted) {
return signal.reason?.name === 'TimeoutError'
? new NetworkError('Превышено время ожидания ответа сервера', 'TIMEOUT')
: new NetworkError('Подготовка отменена', 'ABORTED')
}
if (error instanceof NetworkError) return error
const code = causeCode(error) ?? 'NETWORK'
const message =
code === 'ENOTFOUND' || code === 'EAI_AGAIN'
? 'Не удалось определить адрес сервера'
: code.includes('CERT') || code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'
? 'Ошибка защищённого соединения с сервером'
: code === 'ETIMEDOUT' || code === 'UND_ERR_CONNECT_TIMEOUT'
? 'Превышено время ожидания соединения с сервером'
: code === 'ECONNREFUSED'
? 'Сервер отклонил соединение'
: code === 'ECONNRESET'
? 'Соединение с сервером прервано'
: 'Сервер недоступен'
return new NetworkError(message, code)
}