UNPKG

@itwin/insights-client

Version:

Insights client for the iTwin platform

159 lines 6.25 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { fetch } from "cross-fetch"; import { delay } from "./Utils"; const ACCEPT = "application/vnd.bentley.itwin-platform.v1+json"; export const REPORTING_BASE_PATH = "https://api.bentley.com/insights/reporting"; export const GROUPING_AND_MAPPING_BASE_PATH = "https://api.bentley.com/grouping-and-mapping"; export const CARBON_CALCULATION_BASE_PATH = "https://api.bentley.com/insights/carbon-calculation"; export const NAMED_GROUPS_BASE_PATH = "https://api.bentley.com/named-groups"; const MAX_ATTEMPTS = 3; export class OperationsBase { constructor(basePath) { this.basePath = basePath; } /** * Creates a request body and headers * @param {string} operation string specifying which operation will be performed * @param {string} accessToken OAuth access token with scope `insights:read` * @param {string} content request body * @memberof OperationsBase */ createRequest(operation, accessToken, content, preferReturn) { const request = { method: operation, }; const header = { // eslint-disable-next-line @typescript-eslint/naming-convention Authorization: accessToken, // eslint-disable-next-line @typescript-eslint/naming-convention Accept: ACCEPT, }; if (content) { header["Content-Type"] = "application/json"; request.body = content; } if (preferReturn) // eslint-disable-next-line @typescript-eslint/dot-notation header["Prefer"] = `return=${preferReturn}`; request.headers = header; return request; } /** * retrieves specified data * @param {string} nextUrl url for the fetch * @param {RequestInit} requestOptions information about the fetch * @memberof OperationsBase */ async fetchData(nextUrl, requestOptions) { let response; for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) { try { response = await fetch(nextUrl, requestOptions); } catch (error) { if ("code" in error) { switch (error.code) { case "ETIMEDOUT": case "ECONNRESET": case "EADDRINUSE": case "ECONNREFUSED": case "EPIPE": case "ENOTFOUND": case "ENETUNREACH": case "EAI_AGAIN": case "ECONNABORTED": await delay((2 ** attempt) * 1000); continue; default: throw error; } } throw error; } if (undefined === response) throw new Error("Unknown error has occurred while executed the request."); if (response.status >= 200 && response.status < 300) { return response; } else if (attempt < MAX_ATTEMPTS) { switch (response.status) { case 429: const retryAfter = response.headers.get("Retry-After"); if (!retryAfter) { await delay((2 ** attempt) * 1000); } else { const parsedRetryAfter = parseInt(retryAfter, 10); const retryAfterSeconds = !Number.isNaN(parsedRetryAfter) ? parsedRetryAfter : (2 ** attempt); await delay(retryAfterSeconds * 1000); } break; case 408: case 500: case 502: case 503: case 504: case 521: case 522: case 524: await delay((2 ** attempt) * 1000); break; default: throw response; } } else { throw response; } } // Should be unreachable, but lint has a hard time understanding that. throw response; } /** * retrieves specified data * @param {string} nextUrl url for the fetch * @param {RequestInit} requestOptions information about the fetch * @memberof OperationsBase */ async fetchJSON(nextUrl, requestOptions) { const response = await this.fetchData(nextUrl, requestOptions); return response.status === 204 ? response : response.json(); } /** * Checks if a given string is within the maximum allowed characters * @param {string} input The string to check * @param {number} maxLength The maximum allowed length * @memberof OperationsBase */ isWithinMaxAllowedCharacters(input, maxLength) { return input.length <= maxLength; } /** * checks if given string is a simpleIdentifier * @param {string} name * @memberof OperationsBase */ isSimpleIdentifier(name) { const reg = /^[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}$/u; return name ? (this.isWithinMaxAllowedCharacters(name, 128) && reg.test(name)) : false; } /** * checks if given string is null or whitespace * @param {string} input * @memberof OperationsBase */ isNullOrWhitespace(input) { return !input || !input.trim(); } /** * checks if given number is in a range * @param {number | undefined} top * @memberof OperationsBase */ topIsValid(top) { return top !== undefined ? (top > 0 && top <= 1000) : true; } } //# sourceMappingURL=OperationsBase.js.map