All files APIHandler.ts

83.33% Statements 60/72
71.42% Branches 5/7
100% Functions 5/5
83.33% Lines 60/72

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 731x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 5x 5x 5x 5x 5x 5x 5x                     5x     4x 4x 4x 4x 4x 4x 4x 4x 5x 5x 5x 4x 4x 4x 4x 4x 4x 4x 5x 5x 5x 5x 5x 4x  
import { DateTime } from "luxon"
 
import { SettingsJSON } from "../types/settings"
import { ApiChessData } from "../types/apidata"
 
/**
 * Utility class to handle API requests for chess data.
 */
export class APIHandler {
  private FETCH_MAX_RETRIES: number
  private FETCH_RETRY_DELAY: number
 
  /**
   * Creates an instance of APIHandler.
   * @param {SettingsJSON} settingsJSON - The JSON object containing settings.
   */
  constructor(settingsJSON: SettingsJSON) {
    this.FETCH_MAX_RETRIES = settingsJSON.FETCH_MAX_RETRIES
    this.FETCH_RETRY_DELAY = settingsJSON.FETCH_RETRY_DELAY
  }
 
  /**
   * Retrieves chess data for a given username.
   * @param {string} username - The username for which to fetch chess data.
   * @returns {Promise<ApiChessData>} A Promise that resolves to the fetched chess data.
   * @throws {string} Throws an error if the maximum number of retries is exceeded.
   */
  async getChessData(username: string): Promise<ApiChessData> {
    let retryCount = 0
 
    while (retryCount < this.FETCH_MAX_RETRIES) {
      try {
        const url = this.buildUrl(username)
        return await this.fetchChessData(url)
      } catch (error: any) {
        if (error?.code === 301) break

        if (error?.code === 404) throw `User ${username} not found`

        retryCount++
        if (retryCount < this.FETCH_MAX_RETRIES)
          await new Promise((resolve) =>
            setTimeout(resolve, this.FETCH_RETRY_DELAY)
          )
      }
    }
    throw "Max retries exceeded"
  }
 
  /**
   * Fetches chess data from a given URL.
   *
   * @param {string} url - The URL from which to fetch chess data.
   * @returns {Promise<ApiChessData>} A Promise that resolves to the fetched chess data.
   */
  async fetchChessData(url: string): Promise<ApiChessData> {
    const response = await fetch(url, { cache: "no-store" })
    return response.json()
  }
 
  /**
   * Builds the URL for fetching chess data for a given username.
   * @param {string} username - The username for which to build the URL.
   * @returns {string} The built URL for fetching chess data.
   */
  buildUrl(username: string): string {
    const date = DateTime.local().setZone("America/Los_Angeles")
    const year = date.year
    const month = date.month.toString().padStart(2, "0")
    return `https://api.chess.com/pub/player/${username}/games/${year}/${month}`
  }
}