All files / src/utils errorUtils.js

100% Statements 26/26
100% Branches 26/26
100% Functions 4/4
100% Lines 25/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 10510x                 10x               10x                         80x   78x 78x 78x   78x         4x     74x 7x     67x 2x     65x 2x     63x 3x     60x       71x               65x 65x   65x                             23x 7x   16x                      
const ERROR_CATEGORIES = {
  NETWORK: 'network',
  AUTH: 'auth',
  VALIDATION: 'validation',
  SERVER: 'server',
  TIMEOUT: 'timeout',
  UNKNOWN: 'unknown',
};
 
const NETWORK_ERROR_CODES = [
  'ECONNREFUSED',
  'ECONNRESET',
  'ENOTFOUND',
  'ENETUNREACH',
  'ERR_NETWORK',
];
 
const AUTH_ERROR_TYPES = [
  'authentication_failed',
  'auth_failed',
  'invalid_credentials',
  'token_expired',
  'session_expired',
  'state_mismatch',
  'invalid_callback',
  'oidc_error',
  'missing_verifier',
];
 
function categorizeError(error) {
  if (!error) return ERROR_CATEGORIES.UNKNOWN;
 
  const errorCode = error.code;
  const errorStatus = error.response?.status;
  const errorType = error.type;
 
  if (
    errorStatus === 401
    || errorStatus === 403
    || AUTH_ERROR_TYPES.includes(errorType)
  ) {
    return ERROR_CATEGORIES.AUTH;
  }
 
  if (NETWORK_ERROR_CODES.includes(errorCode)) {
    return ERROR_CATEGORIES.NETWORK;
  }
 
  if (errorCode === 'ETIMEDOUT' || errorCode === 'ECONNABORTED') {
    return ERROR_CATEGORIES.TIMEOUT;
  }
 
  if (errorStatus >= 500) {
    return ERROR_CATEGORIES.SERVER;
  }
 
  if (errorStatus >= 400 && errorStatus < 500) {
    return ERROR_CATEGORIES.VALIDATION;
  }
 
  return ERROR_CATEGORIES.UNKNOWN;
}
 
function isRetryableError(category) {
  return [
    ERROR_CATEGORIES.NETWORK,
    ERROR_CATEGORIES.TIMEOUT,
    ERROR_CATEGORIES.SERVER,
  ].includes(category);
}
 
function createErrorObject(error, fallbackMessage = 'An error occurred') {
  const category = categorizeError(error);
  const message = error?.message || fallbackMessage;
 
  return {
    message,
    category,
    timestamp: Date.now(),
    retryable: isRetryableError(category),
    details: {
      code: error?.code,
      status: error?.response?.status,
      type: error?.type,
      stack: error?.stack,
    },
  };
}
 
function getErrorMessage(errorObject) {
  if (typeof errorObject === 'string') {
    return errorObject;
  }
  return errorObject?.message || 'An error occurred';
}
 
export {
  AUTH_ERROR_TYPES,
  categorizeError,
  createErrorObject,
  ERROR_CATEGORIES,
  getErrorMessage,
  isRetryableError,
};