diff --git a/src/common/retryer.js b/src/common/retryer.js index 859e94b..77f69d3 100644 --- a/src/common/retryer.js +++ b/src/common/retryer.js @@ -45,6 +45,8 @@ const retryer = async (fetcher, variables, retries = 0) => { retries++; // directly return from the function return retryer(fetcher, variables, retries); + } else { + return err.response; } } }; diff --git a/src/common/utils.js b/src/common/utils.js index b41ed0c..33b5f03 100644 --- a/src/common/utils.js +++ b/src/common/utils.js @@ -4,6 +4,9 @@ import toEmoji from "emoji-name-map"; import wrap from "word-wrap"; import { themes } from "../../themes/index.js"; +// Script parameters. +const ERROR_CARD_LENGTH = 576.5; + /** * Renders error message on the card. * @@ -13,13 +16,15 @@ import { themes } from "../../themes/index.js"; */ const renderError = (message, secondaryMessage = "") => { return ` - + - + Something went wrong! file an issue at https://tiny.one/readme-stats ${encodeHTML(message)} @@ -241,7 +246,7 @@ function getCardColors({ * Split text over multiple lines based on the card width. * * @param {string} text Text to split. - * @param {number} width Card width. + * @param {number} width Line width in number of characters. * @param {number} maxLines Maximum number of lines. * @returns {string[]} Array of lines. */ @@ -288,6 +293,7 @@ const SECONDARY_ERROR_MESSAGES = { MAX_RETRY: "Please add an env variable called PAT_1 with your github token in vercel", USER_NOT_FOUND: "Make sure the provided username is not an organization", + GRAPHQL_ERROR: "Please try again later", }; /** @@ -306,6 +312,7 @@ class CustomError extends Error { static MAX_RETRY = "MAX_RETRY"; static USER_NOT_FOUND = "USER_NOT_FOUND"; + static GRAPHQL_ERROR = "GRAPHQL_ERROR"; } /** @@ -427,4 +434,5 @@ export { lowercaseTrim, chunkArray, parseEmojis, + ERROR_CARD_LENGTH, }; diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js index 6a5a6e9..d592b75 100644 --- a/src/fetchers/stats-fetcher.js +++ b/src/fetchers/stats-fetcher.js @@ -9,6 +9,7 @@ import { logger, MissingParamError, request, + wrapTextMultiline, } from "../common/utils.js"; dotenv.config(); @@ -207,11 +208,24 @@ async function fetchStats( let res = await retryer(fetcher, { login: username }); + // Catch GraphQL errors. if (res.data.errors) { logger.error(res.data.errors); + if (res.data.errors[0].type === "NOT_FOUND") { + throw new CustomError( + res.data.errors[0].message || "Could not fetch user.", + CustomError.USER_NOT_FOUND, + ); + } + if (res.data.errors[0].message) { + throw new CustomError( + wrapTextMultiline(res.data.errors[0].message, 90, 1)[0], + res.statusText, + ); + } throw new CustomError( - res.data.errors[0].message || "Could not fetch user", - CustomError.USER_NOT_FOUND, + "Something went while trying to retrieve the stats data using the GraphQL API.", + CustomError.GRAPHQL_ERROR, ); } diff --git a/src/fetchers/top-languages-fetcher.js b/src/fetchers/top-languages-fetcher.js index 7684213..ba3fc72 100644 --- a/src/fetchers/top-languages-fetcher.js +++ b/src/fetchers/top-languages-fetcher.js @@ -1,7 +1,13 @@ // @ts-check import * as dotenv from "dotenv"; import { retryer } from "../common/retryer.js"; -import { logger, MissingParamError, request } from "../common/utils.js"; +import { + CustomError, + logger, + MissingParamError, + request, + wrapTextMultiline, +} from "../common/utils.js"; dotenv.config(); @@ -61,6 +67,27 @@ async function fetchTopLanguages(username, exclude_repo = []) { throw Error(res.data.errors[0].message || "Could not fetch user"); } + // Catch GraphQL errors. + if (res.data.errors) { + logger.error(res.data.errors); + if (res.data.errors[0].type === "NOT_FOUND") { + throw new CustomError( + res.data.errors[0].message || "Could not fetch user.", + CustomError.USER_NOT_FOUND, + ); + } + if (res.data.errors[0].message) { + throw new CustomError( + wrapTextMultiline(res.data.errors[0].message, 90, 1)[0], + res.statusText, + ); + } + throw new CustomError( + "Something went while trying to retrieve the language data using the GraphQL API.", + CustomError.GRAPHQL_ERROR, + ); + } + let repoNodes = res.data.data.user.repositories.nodes; let repoToHide = {};