fix: прод — CORS, версия API, ошибки клиента и подсказка по прошедшим стартам
Some checks failed
CI / build-and-test (pull_request) Has been cancelled

- CORS_ORIGIN: несколько origin через запятую; комментарии в .env.example
- Версия бэкенда: APP_VERSION, безопасное чтение package.json, футер при пустой версии
- Сообщения API: unknown_error и ответы 401/403/404 без JSON; отладочный лог при !ok
- Статус «внесите результат» для прошедшей даты + блок на карточке старта и стили
This commit is contained in:
Vaka.pro
2026-04-08 01:21:11 +03:00
parent 8442c761c2
commit e0ed0b6435
11 changed files with 140 additions and 19 deletions

View File

@@ -35,7 +35,8 @@ function normalizeApiCode(value: string | undefined): ApiErrorCode {
value === "validation_error" ||
value === "not_found" ||
value === "database_unavailable" ||
value === "conflict"
value === "conflict" ||
value === "unknown_error"
) {
return value;
}
@@ -62,6 +63,17 @@ export function toApiError(status: number, payload: unknown): ApiError {
});
}
if (!hasStructuredApiError(payload) && (status === 401 || status === 403 || status === 404)) {
return new ApiError({
code: "network_error",
status,
message:
status === 404
? "API не найден по этому адресу. Проверьте прокси и префикс /api."
: "Запрос отклонён сервером. Проверьте переменную CORS_ORIGIN на бэкенде.",
});
}
const maybePayload = payload as ApiErrorPayload;
const code = normalizeApiCode(maybePayload?.error);
const details = Array.isArray(maybePayload?.details)
@@ -88,6 +100,8 @@ export function getApiErrorMessage(code: ApiErrorCode): string {
return "Запись с таким идентификатором уже существует.";
case "network_error":
return "Не удалось связаться с сервером.";
case "unknown_error":
return "Сервер не смог обработать запрос. Попробуйте позже или обновите страницу.";
default:
return "Произошла неизвестная ошибка.";
}

View File

@@ -55,6 +55,25 @@ export async function requestJson<T>(path: string, init?: RequestInit): Promise<
await delay(80 * attempt);
continue;
}
// #region agent log
fetch("http://127.0.0.1:7488/ingest/a18f912f-72c6-4a58-866b-17810a6b89d2", {
method: "POST",
headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "587ee5" },
body: JSON.stringify({
sessionId: "587ee5",
hypothesisId: "H-http-not-ok",
location: "http.ts:requestJson",
message: "HTTP error response",
data: {
path,
status: response.status,
contentType: response.headers.get("content-type"),
payloadIsObject: payload !== null && typeof payload === "object",
},
timestamp: Date.now(),
}),
}).catch(() => {});
// #endregion
throw toApiError(response.status, payload);
}