UNPKG

tickethead-sdk

Version:

SDK for the Tickethead API

145 lines 7.61 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseUrl = void 0; exports.createBaseUrl = createBaseUrl; exports.setAxiosUpdateTokenFunction = setAxiosUpdateTokenFunction; exports.nopUpdate = nopUpdate; exports.buildClient = buildClient; const axios_retry_1 = __importDefault(require("axios-retry")); const axios_cache_interceptor_1 = require("axios-cache-interceptor"); const axios_1 = __importDefault(require("axios")); const converter_1 = require("./converter"); const errors_1 = require("./errors"); // Constants var BaseUrl; (function (BaseUrl) { BaseUrl["ThProd"] = "https://api.tickethead.io"; BaseUrl["ThStaging"] = "https://api.staging.tickethead.io"; })(BaseUrl || (exports.BaseUrl = BaseUrl = {})); function createBaseUrl(baseUrl = BaseUrl.ThProd, tenantName = undefined) { var _a; const [protocol, base] = baseUrl.split('://'); return `${protocol}://${(_a = tenantName === null || tenantName === void 0 ? void 0 : tenantName.concat('.')) !== null && _a !== void 0 ? _a : ''}${base}`; } /** * Sets the update request strategy for an axios instance */ function setAxiosUpdateTokenFunction(instance, updateToken) { ; instance.updateToken = updateToken; } /** * Does nothing. Will cause 401 requests to fail as usual. */ function nopUpdate() { return __awaiter(this, void 0, void 0, function* () { return ''; }); } /** * Builds an API client object. By default, creates a production client with cluster-wide access. * If `tenantName` is specified, the client includes the tenant name in the URL. * * @param baseUrl Base URL of the REST API (default: PROD_BASE_URL) * @param tenantName Tenant name (defaults to undefined) * @param retryOptions Configuration for the retry policy * @param cacheOptions Configuration for caching, by default no caching is done * @returns axios.AxiosInstance */ function buildClient({ baseUrl = BaseUrl.ThProd, tenantName, retryOptions = { retries: 3 }, cacheOptions, camelCaseResponse, }) { const axiosOptions = { baseURL: createBaseUrl(baseUrl, tenantName), }; let instance = axios_1.default.create(axiosOptions); if (cacheOptions) { instance = (0, axios_cache_interceptor_1.setupCache)(instance, cacheOptions); } // Add a retry mechanism to all requests (0, axios_retry_1.default)(instance, retryOptions); instance.defaults.headers.post['Content-Type'] = 'application/json'; instance.defaults.headers.patch['Content-Type'] = 'application/json'; instance.defaults.headers.put['Content-Type'] = 'application/json'; // Sets the token update strategy setAxiosUpdateTokenFunction(instance, nopUpdate); // TODO: Add expiration check and update the token if needed instance.interceptors.request.use(function (config) { if (!config.headers['Content-Type'] || config.headers['Content-Type'] === 'application/json') { config.data = (0, converter_1.stringifyDates)((0, converter_1.toSnakeCase)(config.data)); } return config; }, function (error) { Promise.reject(error); }); instance.interceptors.response.use(function (response) { // If there is no need to convert case if (!camelCaseResponse || ['stream', 'blob', 'arraybuffer'].includes(response.config.responseType)) { return response; } return Object.assign(Object.assign({}, response), { data: (0, converter_1.parseDates)((0, converter_1.toCamelCase)(response.data)) }); }, function (error) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; // Reject promise if usual error or it has been retried if (((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status) !== 401 || ((_b = error === null || error === void 0 ? void 0 : error.response) === null || _b === void 0 ? void 0 : _b.config._retry)) { // error.response.config._retry = false return Promise.reject(errorBuilder(error)); } // When response code is 401, try to refresh the token. try { // BEWARE of hack // Added updateToken function to axios instance because removing an interceptor is very hard // It enables changing of the token updating strategy on the fly const token = yield instance.updateToken(); // Sets the retry flag error.response.config._retry = true; error.response.config.headers['Authorization'] = 'Bearer ' + token; return yield instance(error.response.config); } catch (err) { return Promise.reject(errorBuilder(error)); } }); }); return instance; } /** * Builds a error instance based on the response HTTP status code * * @param error Error response from axios instance * @returns Error implementation */ function errorBuilder(error) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q; // The error is sometimes an error object and sometimes an axios error const message = (_d = (_c = (_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) !== null && _c !== void 0 ? _c : error.message) !== null && _d !== void 0 ? _d : 'Error in response from service'; const errorCode = ((_f = (_e = error.response) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.errorCode) || ((_h = (_g = error.response) === null || _g === void 0 ? void 0 : _g.data) === null || _h === void 0 ? void 0 : _h.error) || error.error || 'Error in response from service'; const status = ((_j = error.response) === null || _j === void 0 ? void 0 : _j.status) || error.statusCode || error.status; let url = error === null || error === void 0 ? void 0 : error.url; if ((_k = error.config) === null || _k === void 0 ? void 0 : _k.baseURL) { url = `${(_l = error.config) === null || _l === void 0 ? void 0 : _l.baseURL}/${(_m = error.config) === null || _m === void 0 ? void 0 : _m.url}`; } const method = (_p = (_o = error.config) === null || _o === void 0 ? void 0 : _o.method) !== null && _p !== void 0 ? _p : error === null || error === void 0 ? void 0 : error.method; const data = (_q = error.config) === null || _q === void 0 ? void 0 : _q.data; if (status) { return new errors_1.ApiError(message, errorCode, status, url, method, data); } return new errors_1.ApiError(message, JSON.stringify(error), status, url, method, data); } //# sourceMappingURL=index.js.map