Client.js

const fetch = require('node-fetch');
const Package = require('../package.json');

const Account = require('./Account');
const Match = require('./Match').Match;
const StoreItem = require('./StoreItem');
const Challenges = require('./Challenges');

/**
 * The client for interacting with the Fortnite Tracker API
 * @class Client
 * @param {string} key Fortnite Tracker API token
 */
class Client {
    constructor(key) {

        if (!key) {
            throw new Error('No API key passed.');
        }

        this.key = key;

        this.headers = {
            'User-Agent': `fortnite.js v${Package.version} (${Package.homepage})`,
            'TRN-Api-Key': this.key
        };

        this.rateLimit = {
            limit: 30,
            remaining: 30
        };

    }

    /**
     * Makes the request to the API
     * @private
     * @param {string} link URL endpoint of API
     * @returns {Promise<Object>}
     * @memberof Client
     */
    _request(link) {
        return fetch(link, { headers: this.headers })
            .then(r => {
                this.rateLimit = {
                    limit: Number(r.headers.get('x-ratelimit-limit-minute')),
                    remaining: Number(r.headers.get('x-ratelimit-remaining-minute'))
                };

                if (!r.ok) return Promise.reject(r.statusText);

                return r.json();
            })
            .catch(e => Promise.reject(`HTTP ${e}`));
    }

    /**
     * Get user info
     * @param {string} username username of the user to search for
     * @param {string=} [platform='pc'] platform to search for user in (pc, xbl, or psn)
     * @param {boolean=} [raw=false] whether to return raw response from API
     * @returns {(Promise<Account>|Promise<Object>)}
     * @memberof Client
     */
    get(username, platform = 'pc', raw = false) {
        return this._request(`https://api.fortnitetracker.com/v1/profile/${platform}/${encodeURI(username)}`)
            .then(r => r.error ? Promise.reject(r) : r)
            .then(r => raw ? r : new Account(r))
            .catch(e => Promise.reject(e));
    }

    /**
     * Get user's matches
     * @param {string} accountId user's account ID found in user info
     * @param {boolean=} [raw=false] whether to return raw response from API
     * @returns {(Promise<Array<Match>>|Promise<Array<Object>>)}
     * @memberof Client
     */
    getMatches(accountId, raw = false) {
        return this._request(`https://api.fortnitetracker.com/v1/profile/account/${accountId}/matches`)
            .then(r => r.error ? Promise.reject(r.error) : r)
            .then(r => raw ? r : r.map(m => new Match(m)))
            .catch(e => Promise.reject(e));
    }

    /**
     * Get current store items
     * @param {boolean=} [raw=false] whether to return raw response from API
     * @returns {Promise<Array<StoreItem>>|Promise<Array<Object>>}
     * @memberof Client
     */
    getStore(raw = false) {
        return this._request('https://api.fortnitetracker.com/v1/store')
            .then(r => r.error ? Promise.reject(r.error) : r)
            .then(r => raw ? r : r.map(item => new StoreItem(item)))
            .catch(e => Promise.reject(e));
    }

    /**
     * Get currently weekly challenges
     * @param {boolean=} [raw=false] whether to return raw response from API
     * @returns {(Promise<Challenges>|Promise<Object>)}
     * @memberof Client
     */
    getChallenges(raw = false) {
        return this._request('https://api.fortnitetracker.com/v1/challenges')
            .then(r => r.error ? Promise.reject(r.error) : r)
            .then(r => raw ? r : new Challenges(r))
            .catch(e => Promise.reject(e));
    }
}

module.exports = Client;