UNPKG

@publidata/utils-fontawesome

Version:
262 lines (237 loc) 6.71 kB
const axios = require("axios"); const MemoryCache = require("../MemoryCache"); const { GraphQLClient, gql } = require("graphql-request"); const { FA_API_BASE_URL } = require("../constants"); /** * Class used to interact with the FontAwesome API * @class * @see https://fontawesome.com/docs/apis/graphql/get-started * @constructor {string} _faToken Token used to generate the access token */ class FontAwesomeApi { /** * Token used to generate the access token * Should never be modified after the constructor * @type {string} * @private */ #faToken; constructor(_faToken) { if (typeof _faToken !== "string") { throw new Error("Invalid token provided"); } this.#faToken = _faToken; // From here _faToken should never be use again, // this.#faToken should be used instead } /** * Instantiate a new GraphQLClient with the endpoint and the headers * Usage: * const query = gql`...`; * const data = await this._client.request(query); * @type {GraphQLClient} * @private */ _client = new GraphQLClient(FA_API_BASE_URL); /** * Cache used to store the results of the queries * @type {MemoryCache} * @private * @see MemoryCache */ _cache = new MemoryCache(500); /** * Allowing accessing the cache from outside the class * @returns {MemoryCache} * @see MemoryCache */ get cache() { return { get: this._cache.get }; } /** * Retrieve the access token from the FA API and set the headers of the client * @returns {Promise<void>} * @throws {Error} if no token is provided * @throws {Error} if the token is invalid * @private */ _connect() { return new Promise((resolve, reject) => { if (this.#faToken) { axios .post( `${FA_API_BASE_URL}/token`, {}, { headers: { Authorization: `Bearer ${this.#faToken}`, }, } ) .then((res) => { if (res.status === 200) { this._client.setHeaders({ Authorization: `Bearer ${res.data?.access_token}`, }); resolve(); } else { reject(Error("Invalid token provided")); } }) .catch((err) => { reject(err); }); } else { reject(Error("No token provided")); } }); } /** * Execute a query and retry if the token is expired * @param {String} query - GraphQL query * @returns {Promise<*>} * @throws {Error} if the second attempt fails * @private */ _queryWithToken(query) { // 1 - First attempt return new Promise((resolve, reject) => { this._client .request(query) .then(resolve) .catch(() => { // 2 - Second attempt this._connect() .then(() => { this._client.request(query).then(resolve).catch(reject); }) .catch(reject); }); }); } /** * Récupère une icône standard de FontAwesome via l'API GraphQL * @param {String} iconName - Nom de l'icône (ex: "wine-bottle") * @param {String} prefix - Préfixe de l'icône (ex: "fas", "far", "fab") * @returns {Promise<Object>} - Objet contenant les infos et le SVG de l'icône */ getIcon(iconName, prefix = "fas") { const styles = { fas: "SOLID", far: "REGULAR", fab: "BRAND", }; const query = gql` { release(version: "6.x") { icon(name: "${iconName}") { id svgs( filter: { familyStyles: [ { family: CLASSIC, style: ${styles[prefix]} } ] } ) { html } } } } `; return this._queryWithToken(query).then((res) => { return res.release?.icon?.svgs?.[0]; }); } /** * Retrieve all the kits related to the account * @returns {Promise<*>} * @throws {Error} if no token is provided */ kits() { const query = gql` { me { kits { name token version licenseSelected technologySelected } } } `; return this._queryWithToken(query); } /** * Retrieve a kit from the account including all the icons * @param {String} token - Token of the kit to retrieve * @returns {Promise<Object>} { me: { kit: { name, token, version, licenseSelected, technologySelected, iconUploads: [ { name, path, width, height, version, unicode } ] } } * @throws {Error} if no token is provided */ kit(token) { if (!token) throw new Error("No token provided to .kit($token)"); const query = gql` { me { kit(token: "${token}") { name token version licenseSelected technologySelected iconUploads { name path width height version unicode } } } }`; return this._queryWithToken(query); } /** * Retrieve all the icons of a kit and filter them by name * @param {String} token - Token of the kit to retrieve * @param {String} icons - Name of the icon to retrieve * @returns {Promise<Object>} [ { name, path, width, height, version, unicode } ] * @throws {Error} if no token is provided */ kitIcons(token, icons) { if (!token) throw new Error("No token provided to .kitIcons($token, $[icons])"); const keyCache = `kitIcons-${token}-${icons?.join("-")}`; return new Promise((resolve, reject) => { // Check if this query is already in the cache const cached = this._cache.get(keyCache); if (cached) return resolve(cached); // If not check if the requested icons are in the cache if (icons) { const cachedIcons = icons.map((icon) => this._cache.get(icon)); if (cachedIcons.every(Boolean)) { return resolve(cachedIcons); } } this.kit(token) .then((res) => { if (icons) res.me.kit.iconUploads = res.me.kit.iconUploads.filter((icon) => icons.includes(icon.name) ); const toCache = res.me.kit.iconUploads.map((icon) => ({ key: `${icon.name}`, value: icon, })); this._cache.put(keyCache, res.me.kit.iconUploads); this._cache.putAll(toCache); resolve(res.me.kit.iconUploads); }) .catch(reject); }); } } module.exports = FontAwesomeApi;