import {RivendellApi} from './RivendellApi'; import {MoriaApi} from './MoriaApi'; import RivendellApiError = RivendellApi.ApiError; import MoriaApiError = MoriaApi.ApiError; export function formatError(error: Error) { if (error instanceof RivendellApiError) { if (error.response?.status === 403) { return 'Could not authenticate with the credential configured in ~/.ocp/credentials.json.'; } else { return sanitize(errorMessageFromJsonResponse(error)); } } else if (error instanceof MoriaApiError) { return sanitize(errorMessageFromJsonResponse(error)); } else { let message = `${error.name}: ${error.message}`; if ('cause' in error && error.cause instanceof Error) { message += ` [Cause: ${error.cause.name}: ${error.cause.message}]`; } return sanitize(message); } } function errorMessageFromJsonResponse(error: MoriaApiError | RivendellApiError) { const contentType = error.response?.headers?.get('content-type'); if (contentType?.includes('application/json') && error.responseText) { let response; try { response = JSON.parse(error.responseText); } catch (e: any) { return error.message; } // protocol is that detail will have either a `message` or an `invalids` child if (response.detail) { return response.detail.message ? response.detail.message : response.detail.invalids .map((violation: { [key: string]: string }) => `* ${violation.field} ${violation.reason}`) .join('\n'); } } return error.message; } function sanitize(body: any) { return body.replace('FAILED_PRECONDITION: ', '').replace('INTERNAL: ', ''); }