UNPKG

bb-api-platforma

Version:

API module for BetBooster Platform

1,113 lines 148 kB
import { api } from './Types.js'; // #region Consts ----------------------------------------------------------------------- const locales = { /** Be careful on the backend these values may change * for chek: * https://front-test.restin.win/api/account/GetAvailableLanguages */ ar: 'en-US', en: 'en-US', de: 'en-US', pt: 'en-US', fr: 'fr-FR', ht: 'fr-FR', es: 'en-US', tr: 'tr-TR', tk: 'tr-TR', az: 'tr-TR', uk: 'en-US', cr: 'fr-FR', ru: 'ru-RU', }; // const locales: Record<string, string> = { // /** Be careful on the backend these values may change // * for chek: // * https://front-test.restin.win/api/account/GetAvailableLanguages // */ // en: 'en-US', // pt: 'pt-PT', // fr: 'fr-FR', // es: 'es-ES', // tr: 'tr-TR', // az: 'tr-TR', // uk: 'uk-UA', // cr: 'cr-HA', // ru: 'ru-RU', // } const languageIdsRemote = { /** Be careful on the backend these values may change * for chek: * https://front-test.restin.win/api/account/GetAvailableLanguages */ en: 1, pt: 1, fr: 4, es: 1, tr: 5, az: 5, uk: 1, cr: 1, ru: 0, }; // const languageIdsRemote: Record<string, number> = { // /** Be careful on the backend these values may change // * for chek: // * https://front-test.restin.win/api/account/GetAvailableLanguages // */ // en: 1, // pt: 0, // fr: 4, // es: 3, // tr: 5, // az: 5, // uk: 2, // cr: 6, // ru: 0, // } const MAX_TIME_EXECUTION_MS = 25000; const stringify = (obj) => { return JSON.stringify(obj, null, 2); }; function convertBasketToPost(betslipItem) { return { a1: betslipItem.Add1, a2: betslipItem.Add2, bId: betslipItem.BetVarID, eId: betslipItem.LinesID, fs: betslipItem.HandSize, isLive: betslipItem.IsLive, r: betslipItem.Odds, }; } export function routeNameId(id, text = '') { text !== null && text !== void 0 ? text : (text = ''); return `${text .replace(/[\s\.\,\(\)\[\]\\\/\-\~\`\"\']+/g, ' ') .trim() .replace(/\s+/g, '-') .toLowerCase()}~${id}`; } export function clearPhone(draftPhoneNumber, prefix = '', suffix = '') { return prefix + (String(draftPhoneNumber).match(/\d+/g) || []).join('') + suffix; } let IS_DEV_MODE = false; // #endregion Consts ----------------------------------------------------------------------- export class BetBoosterApi { // #endregion Class Properties -------------------------------------------------------- /** * Represents the BetBoosterApi class. * @constructor * @param {AxiosInstance} axiosInstance - The Axios instance to be used for making HTTP requests. Aka axios.create() * @param {string} baseUrl - The base URL of the API. * @param {string} [lang='en'] - The language to be used for API requests. Defaults to 'en'. * @param {number} [maxTimeExecutionMs=15000] - The maximum time allowed for API request execution in milliseconds. Defaults to 15000. * @param {boolean} [isDev=false] - Indicates whether the API is running in development mode. Defaults to false. */ constructor(axiosInstance, baseUrl, lang = 'en', maxTimeExecutionMs = 15000, isDev = false) { this._srv_tag = '19'; this._locale = 'en-EN'; this._locales = locales; this._languageIdsRemote = languageIdsRemote; this.EXIST_LANGUAGES = Object.keys(locales); this._languageId = 1; this._lang = 'en'; this._USER_DATA = {}; this.LANG_DEFAULT = 'en'; this.LOCALE_DEFAULT = 'en-EN'; this.LANG_ID_DEFAULT = 1; this.maxTimeExecutionMs = MAX_TIME_EXECUTION_MS; this.liveTimestamp = 0; this._liveTimestampReset = false; this.liveRecivedIsFullPackage = false; this.isNotActive = false; /** Приоритетные виды спорта для сортировки и отображения на странице [VidSportaRating]*/ this.primarySports = [5, 1, 3, 4, 8, 6, 263, 265, 2, 16, 17, 18]; /** Приоритетные страны по видам спорта для сортировки и отображения */ this.priorityCountries = { "1": [14, 8, 54], "5": [8, 14, 1, 2, 5, 4, 3, 43, 44, 42, 11, 54], "6": [14, 8, 54], "8": [8, 14, 54], "27": [45, 187], }; /** Приоритетные турниры по видам спорта*/ this.priorityTournaments = { "5": [201, 361, 199, 410, 200, 423, 1141, 1142, 47, 2408, 1688, 2511, 129, 193, 919, 1693, 1134, 2157, 147, 212, 1, 185, 2, 2379, 286, 1216, 99, 1266, 4, 290, 735, 1059, 1100, 1268, 5, 292, 1210, 1366, 700, 1217, 3, 186, 2209, 2431, 288, 1410, 6, 540, 1062, 1223, 1061, 1237, 40, 1235, 2230, 2370, 209, 1278, 470, 1373, 35, 1386, 2229, 2373, 737, 1383, 1412, 1857, 1505, 1858, 11, 1853, 2231, 742, 1382, 49, 1236, 1060, 2364, 624, 15, 1896, 1409, 1493, 1918, 1925, 2283, 1612, 86, 149, 2337, 8, 1213, 19, 1387], }; // const uri = new URL(baseUrl) IS_DEV_MODE = isDev; // this._ENDPOINT_DOMAIN = uri.origin; this.maxTimeExecutionMs = maxTimeExecutionMs; this.axi = axiosInstance; this.setBaseUrl(baseUrl); this.setLanguage(lang); } // #region Getters & Setters ----------------------------------------------------------- get locale() { return this._locale; } get isSinged() { return this.user !== undefined && this.user.UserId !== undefined && this.user.UserId > 0; } get user() { return this._USER_DATA; } get userMain() { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; return [ `uid: ${(_b = (_a = this._USER_DATA) === null || _a === void 0 ? void 0 : _a.UserId) !== null && _b !== void 0 ? _b : '--'}`, `unm: ${(_d = (_c = this._USER_DATA) === null || _c === void 0 ? void 0 : _c.UserName) !== null && _d !== void 0 ? _d : '--'}`, `pid: ${(_f = (_e = this._USER_DATA) === null || _e === void 0 ? void 0 : _e.PointId) !== null && _f !== void 0 ? _f : '--'}`, `ptp: ${(_h = (_g = this._USER_DATA) === null || _g === void 0 ? void 0 : _g.PlayerType) !== null && _h !== void 0 ? _h : '--'}`, `gid: ${(_k = (_j = this._USER_DATA) === null || _j === void 0 ? void 0 : _j.GroupID) !== null && _k !== void 0 ? _k : '--'}`, `bal: ${(_m = (_l = this._USER_DATA) === null || _l === void 0 ? void 0 : _l.Amount) !== null && _m !== void 0 ? _m : '--'}`, `cur: ${(_p = (_o = this._USER_DATA) === null || _o === void 0 ? void 0 : _o.CurrencyName) !== null && _p !== void 0 ? _p : '--'}`, ]; } set user(value) { this._USER_DATA = value; } get lang() { return this._lang; } get languageId() { return this._languageId; } get srvTag() { return this._srv_tag; } set srvTag(value) { this._srv_tag = String(value); } setServerTag(value) { this._srv_tag = String(value); } get token() { var _a; return (_a = this._TOKEN) !== null && _a !== void 0 ? _a : undefined; } set token(value) { if (typeof value === 'string') { this._TOKEN = value.split(/\s*,\s*/)[0]; } else { this._TOKEN = undefined; } } // #endregion Getters & Setters ----------------------------------------------------------- // #region Handlers ----------------------------------------------------------------------- /** * Processes the response data and returns an object with data, error, status and status text. * * @template T - Тип данных, возвращаемых в поле `data`. * @param {any} rawData - Сырые данные ответа. * @param {number} status - HTTP статус ответа. * @param {string} statusText - Текст статуса HTTP ответа. * @returns {{ data: T, error: string | null, status: number, statusText: string }} Объект, содержащий данные ответа, ошибку, статус и текст статуса. */ responseHandlerData(rawData, status, statusText) { var _a, _b, _c; let data = null; if (((_a = rawData === null || rawData === void 0 ? void 0 : rawData.Data) === null || _a === void 0 ? void 0 : _a.Data) !== undefined) { data = rawData.Data.Data; } else if (((_b = rawData === null || rawData === void 0 ? void 0 : rawData.Data) === null || _b === void 0 ? void 0 : _b._isSuccessful) !== undefined) { data = rawData.Data._isSuccessful; } else if ((rawData === null || rawData === void 0 ? void 0 : rawData.Data) !== undefined) { data = rawData.Data; } else if (rawData !== undefined) { data = rawData; } // const data: T = rawData?.Data?.Data ?? rawData?.Data ?? rawData ?? null as T; const error = ((_c = rawData === null || rawData === void 0 ? void 0 : rawData.Data) === null || _c === void 0 ? void 0 : _c.Error) || (rawData === null || rawData === void 0 ? void 0 : rawData.Error) || (status >= 300 ? statusText : null) || (!data && status >= 300 ? 'Unknown error' : null); if (error === 'Object reference not set to an instance of an object.') { console.log('!!!!!!!!!!! Object reference not set to an instance of an object.'); } return { data, error, status, statusText }; } /** * Processes the response data and returns an object with data, error, status and status text. * Same as `this.responseHandlerData` only corrects the nesting of `Data.Data` * * @template T - Тип данных, возвращаемых в поле `data`. * @param {any} rawData - Сырые данные ответа. * @param {number} status - HTTP статус ответа. * @param {string} statusText - Текст статуса HTTP ответа. * @returns {{ data: T, error: string | null, status: number, statusText: string }} Объект, содержащий данные ответа, ошибку, статус и текст статуса. */ responseHandlerDataData(rawData, status, statusText) { var _a, _b, _c, _d; let data = null; if (((_a = rawData === null || rawData === void 0 ? void 0 : rawData.Data) === null || _a === void 0 ? void 0 : _a.Data) !== undefined && (rawData === null || rawData === void 0 ? void 0 : rawData.Data) !== undefined) { data = rawData.Data; } else if (((_b = rawData === null || rawData === void 0 ? void 0 : rawData.Data) === null || _b === void 0 ? void 0 : _b.Data) !== undefined) { data = rawData.Data.Data; } else if (((_c = rawData === null || rawData === void 0 ? void 0 : rawData.Data) === null || _c === void 0 ? void 0 : _c._isSuccessful) !== undefined) { data = rawData.Data._isSuccessful; } else if ((rawData === null || rawData === void 0 ? void 0 : rawData.Data) !== undefined) { data = rawData.Data; } else if (rawData !== undefined) { data = rawData; } // const data: T = rawData?.Data?.Data ?? rawData?.Data ?? rawData ?? null as T; const error = ((_d = rawData === null || rawData === void 0 ? void 0 : rawData.Data) === null || _d === void 0 ? void 0 : _d.Error) || (rawData === null || rawData === void 0 ? void 0 : rawData.Error) || (status >= 300 ? statusText : null) || (!data && status >= 300 ? 'Unknown error' : null); if (error === 'Object reference not set to an instance of an object.') { console.log('!!!!!!!!!!! Object reference not set to an instance of an object.'); } return { data, error, status, statusText }; } /** * Converts rawData.Data.Data format to rawData.Data.data format * Sometimes API returns a format that is difficult to process later. * Therefore it is necessary to convert the format for proper data processing (responseHandlerData) * @param rawData * @returns */ convertDataData(rawData) { var _a; if (((_a = rawData === null || rawData === void 0 ? void 0 : rawData.Data) === null || _a === void 0 ? void 0 : _a.Data) !== undefined) { const keys = Object.keys(rawData.Data); if (keys.length > 0) { const data = {}; keys.forEach(key => { var _a; data[key.toLowerCase()] = (_a = rawData.Data[key]) !== null && _a !== void 0 ? _a : null; }); return data; } } return rawData; } setDevMode(devMode) { if (devMode === undefined) { IS_DEV_MODE = true; } else { IS_DEV_MODE = devMode; } } /** * Adds new locale keys and values to the existing locales. * Updates the list of existing languages with any new language codes found in the provided data. * * @param localesData - An object mapping locale keys to their translations * @example * // Add new translations * betBoosterApi.addLocalesConverters({ * 'en': 'en-US', * 'fr': 'fr-FR' * }); */ addLocalesConverters(localesData) { this._locales = Object.assign(Object.assign({}, this._locales), localesData); const el = new Set([...this.EXIST_LANGUAGES, ...Object.keys(this._locales)]); this.EXIST_LANGUAGES = Array.from(el); } checkLanguage(lang = 'en') { try { const _lang = lang.substring(0, 2) || this.LANG_DEFAULT; const isExistInLanguages = this.EXIST_LANGUAGES.includes(_lang); return isExistInLanguages ? _lang : this.LANG_DEFAULT; } catch (error) { return this.LANG_DEFAULT; } } /** * Sets the language for the BetBooster API. * * @param {string} [lang='en'] - The language code to set. Defaults to 'en' if not provided. * @returns {string} - The language code that was set. * @example * ``` * api.setLanguage('en'); * ``` * as result: * lang='en'; * locale='en-US'; * languageId=1; */ setLanguage(lang = 'en') { var _a, _b; this._lang = this.checkLanguage(lang); this._locale = (_a = this._locales[this._lang]) !== null && _a !== void 0 ? _a : this.LOCALE_DEFAULT; this._languageId = (_b = this._languageIdsRemote[this._lang]) !== null && _b !== void 0 ? _b : this.LANG_ID_DEFAULT; return this._lang; } /** * Sets the language and locale for the remote API. * @param lang Language (default 'en'). * @returns Returns true if the language and locale are successfully set, otherwise returns false. */ async setLanguageRemoteLocale(lang = 'en') { this.setLanguage(lang); if (this.isSinged) { const url = this.url(`/account/SetLanguage`, api.LBC); const res = await this.POST(url, { culture: this.locale }); return res || false; } return undefined; } setBaseUrl(baseUrl) { if (baseUrl.endsWith('/')) { baseUrl = baseUrl.slice(0, -1); } this._baseUrl = baseUrl; return this._baseUrl; } statusHandler(status, statusText) { if (status === 401) { this.user = {}; this.token = undefined; if (IS_DEV_MODE) console.log('Status:', status, statusText); } } /** * Query string handler. Replaces values * * `null` на `'null'` * * `false` на `'false'` * * `true` на `'true'` * * `undefined` на `''` * @param queryStringData - queryString Record<string, any> * @returns The processed data of the query string. */ queryStringHandler(queryStringData = {}) { const keys = Object.keys(queryStringData); keys.forEach(key => { if (queryStringData[key] === null) { queryStringData[key] = 'null'; } else if (queryStringData[key] === true) { queryStringData[key] = 'true'; } else if (queryStringData[key] === false) { queryStringData[key] = 'false'; } else if (queryStringData[key] === undefined) { queryStringData[key] = ''; } }); return queryStringData; } responseHandler(response) { var _a, _b, _c, _d; const xToken = (_b = (_a = response === null || response === void 0 ? void 0 : response.headers['x-token']) !== null && _a !== void 0 ? _a : response === null || response === void 0 ? void 0 : response.headers['X-token']) !== null && _b !== void 0 ? _b : null; // console.log('x-token:', response?.headers['x-token']); // console.log('X-token:', response?.headers['X-token']); if (IS_DEV_MODE && ((_c = response === null || response === void 0 ? void 0 : response.request) === null || _c === void 0 ? void 0 : _c.path)) console.log((_d = response === null || response === void 0 ? void 0 : response.request) === null || _d === void 0 ? void 0 : _d.path); if (xToken) { this.token = xToken; if (IS_DEV_MODE) console.log('isSinged:', this.isSinged + '\nX-Token:', xToken); } ; } /** * Error Handler for Axios. * * @param error - AxiosError object. * @returns An object with error data, including the status and text of the error. */ axiosErrorHandler(error) { var _a, _b, _c, _d, _e, _f, _g, _h; let errorMessage; let status = (_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status) !== null && _b !== void 0 ? _b : null; let statusText = (_d = (_c = error.response) === null || _c === void 0 ? void 0 : _c.statusText) !== null && _d !== void 0 ? _d : null; const response = (_e = error.response) !== null && _e !== void 0 ? _e : null; // const request = err.request ?? null; if (response) { // Server responded with a status other than 200 range // console.log('err.response.request.url:', response.request.url) const brMessage = [ ...(status ? [status] : []), ...(statusText ? [statusText] : []), ...(((_f = response === null || response === void 0 ? void 0 : response.data) === null || _f === void 0 ? void 0 : _f.Message) ? [response.data.Message] : []), ...(((_g = response === null || response === void 0 ? void 0 : response.data) === null || _g === void 0 ? void 0 : _g.MessageDetail) ? [response.data.MessageDetail] : []), ].join(' > '); // errorMessage = `Error: ${brMessage}`; errorMessage = brMessage; if (IS_DEV_MODE) { const requestMethod = ((_h = response.config.method) !== null && _h !== void 0 ? _h : '').toUpperCase(); const fullUrl = response.config.url; const requestData = response.config.data; console.log('```'); console.log('ERROR:', requestMethod, fullUrl); console.log('DATA:', requestData); console.log('RESPONCE:', response === null || response === void 0 ? void 0 : response.data); console.log('```'); } } else if (error.request) { // Request was made but no response was received errorMessage = `Error: No response received`; // 503 Service Unavailable status = 503; statusText = 'Service Unavailable'; } else { // Something else caused the error errorMessage = `Error: ${error === null || error === void 0 ? void 0 : error.message}`; status = 601; statusText = (error === null || error === void 0 ? void 0 : error.message) || 'Unknown error'; } console.error('Axios request error:', errorMessage); return { data: null, status, // statusText, statusText: errorMessage || statusText || 'Unknown error', }; } /** * Returns the URL for the specified API path and version. * * @param apiPath - API Pathway. * @param apiVersion - API Version. * @returns URL for the specified API path and version. */ url(apiPath, apiVersion) { if (apiPath.toLowerCase().startsWith('http')) { return apiPath; } switch (apiVersion) { case api.V2: return `${this._baseUrl}/v2/bsw/api${apiPath}`; case api.NV20: return `${this._baseUrl}/nv20${apiPath}`; // return `${this._baseUrl}${this._APIv2}${apiPath}` case api.LBC: return `${this._baseUrl}/v2/lbc/api${apiPath}`; // return `${this._baseUrl}${this._API_LBC}${apiPath}` case api.DIRECT: return `${this._baseUrl}${apiPath}`; case api.V1: default: return `${this._baseUrl}/api${apiPath}`; // return `${this._baseUrl}${this._APIv1}${apiPath}` } } /** * Сортирует данные по приоритету, указанному в массиве priorityIDs. * * @template T - Тип объектов в массиве данных * @param {Array<T>} data - Массив объектов данных для сортировки. * @param {Array<number|string>} priorityIDs - Массив приоритетных ID для сортировки. * @param {keyof T} sortField - Поле объекта, по которому будет производиться сортировка. * @returns {Array<T>} - Новый массив отсортированных данных. * * @example * ```typescript * interface Tournament { * Id: number; * Name: string; * SportID: number; * } * * const tournaments: Tournament[] = [ * { Id: 1, Name: 'Premier League', SportID: 5 }, * { Id: 2, Name: 'La Liga', SportID: 5 }, * { Id: 3, Name: 'Serie A', SportID: 5 } * ]; * * const sortedTournaments = api.sortDataByPriority( * tournaments, * [3, 1, 2], * 'Id' * ); * // Result: [Serie A, Premier League, La Liga] * ``` */ sortDataByPriority(data, priorityIDs, sortField) { const priorityIndex = new Map(); // Создаем объект для быстрого доступа к индексам приоритетных ID priorityIDs.forEach((id, index) => { priorityIndex.set(id, index); }); // Сортируем данные, используя объект индексов приоритетов return data.slice().sort((a, b) => { const aPriority = priorityIndex.has(a[sortField]) ? priorityIndex.get(a[sortField]) : Infinity; const bPriority = priorityIndex.has(b[sortField]) ? priorityIndex.get(b[sortField]) : Infinity; return aPriority - bPriority; }); } /** * Сортирует массив значений по приоритету, указанному в массиве priorityIDs. * * @template T - Тип элементов массива (number | string) * @param {Array<T>} array - Массив значений для сортировки. * @param {Array<T>} priorityIDs - Массив приоритетных ID для сортировки. * @returns {Array<T>} - Новый массив отсортированных значений. * * @example * ```typescript * const sportIds = [1, 5, 3, 8, 2]; * const prioritySports = [5, 1, 3]; * * const sortedSports = api.sortArrayByPriority(sportIds, prioritySports); * // Result: [5, 1, 3, 8, 2] * // Elements 5, 1, 3 are sorted by priority, others remain in original order * ``` */ sortArrayByPriority(array, priorityIDs) { const priorityIndex = new Map(); // Создаем объект для быстрого доступа к индексам приоритетных ID priorityIDs.forEach((id, index) => { priorityIndex.set(id, index); }); // Сортируем массив, используя объект индексов приоритетов return array.slice().sort((a, b) => { const aPriority = priorityIndex.has(a) ? priorityIndex.get(a) : Infinity; const bPriority = priorityIndex.has(b) ? priorityIndex.get(b) : Infinity; return aPriority - bPriority; }); } // #endregion Handlers -------------------------------------------------------------------- // #region AXIOS -------------------------------------------------------------------------- /** * Executes an HTTP request with the specified parameters. * @param url - The URL to execute the request. * @returns An object that contains methods for configuring the request and executing the request. */ request(url) { const queryStringHandler = this.queryStringHandler; const axi = this.axi; const axiosErrorHandler = this.axiosErrorHandler; const statusHandler = (status, statusText) => { if (status === 401) { this.user = {}; this.token = undefined; if (IS_DEV_MODE) console.log('Status:', status, statusText); } }; /** Error Handler and Notification */ const handleError = async (errorData) => { var _a, _b; try { console.error(errorData); const text = [ typeof window !== 'undefined' ? window.location.href : 'url: unknown', `Error: ${(errorData === null || errorData === void 0 ? void 0 : errorData.error) || 'Unknown error'}`, ...this.userMain, ].filter(Boolean).join('\n'); let code = ''; try { code = (_a = JSON.stringify(errorData, null, 2)) !== null && _a !== void 0 ? _a : 'Unknown error'; } catch (e) { code = (_b = errorData === null || errorData === void 0 ? void 0 : errorData.error) !== null && _b !== void 0 ? _b : 'Unknown error'; } await this.sendErrInfo(text, code); } catch (error) { } }; const responseHandler = (response) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; // console.log('responseHandler:', response); // console.log('Response body:', response.data); // console.log('Response response?.config:', response?.config); const xToken = (_a = response === null || response === void 0 ? void 0 : response.headers['x-token']) !== null && _a !== void 0 ? _a : null; const urlPath = (_c = (_b = response === null || response === void 0 ? void 0 : response.request) === null || _b === void 0 ? void 0 : _b.path) !== null && _c !== void 0 ? _c : null; // if (response?.data?.Error === 'Object reference not set to an instance of an object.') { if ((_d = response === null || response === void 0 ? void 0 : response.data) === null || _d === void 0 ? void 0 : _d.Error) { const Method = ((_f = (_e = response === null || response === void 0 ? void 0 : response.config) === null || _e === void 0 ? void 0 : _e.method) !== null && _f !== void 0 ? _f : '').toUpperCase(); const errorData = Object.assign(Object.assign(Object.assign({ method: Method, url: ((_g = response === null || response === void 0 ? void 0 : response.config) === null || _g === void 0 ? void 0 : _g.url) || '' }, (!!((_h = response === null || response === void 0 ? void 0 : response.config) === null || _h === void 0 ? void 0 : _h.params) ? { params: (_k = (_j = response === null || response === void 0 ? void 0 : response.config) === null || _j === void 0 ? void 0 : _j.params) !== null && _k !== void 0 ? _k : '' } : {})), (!!((_l = response === null || response === void 0 ? void 0 : response.config) === null || _l === void 0 ? void 0 : _l.data) ? { POST: (_o = (_m = response === null || response === void 0 ? void 0 : response.config) === null || _m === void 0 ? void 0 : _m.data) !== null && _o !== void 0 ? _o : '' } : {})), { error: (_p = response === null || response === void 0 ? void 0 : response.data) === null || _p === void 0 ? void 0 : _p.Error }); handleError(errorData); } if (IS_DEV_MODE && urlPath) console.log(urlPath); if (xToken) { this.token = xToken; if (IS_DEV_MODE) console.log('isSinged:', this.isSinged + '\nX-Token:', xToken); } ; }; const now = Date.now() + Math.random(); /** * Создает локальный AbortController с автоматическим таймаутом. * * @param customTimeout - Пользовательский таймаут в миллисекундах. Если не указан, используется значение по умолчанию. * @returns Объект с сигналом AbortSignal для отмены запроса. * * @example * ```typescript * const { signal } = setupLocalAbortController(5000); * const response = await fetch(url, { signal }); * ``` */ const setupLocalAbortController = (customTimeout) => { var _a; const timeout = (_a = customTimeout !== null && customTimeout !== void 0 ? customTimeout : this.maxTimeExecutionMs) !== null && _a !== void 0 ? _a : MAX_TIME_EXECUTION_MS; // const abortControllerTimeout = (timeout * this.maxRetryGotRequests) + 1000; const localAbortController = new AbortController(); const signalTimeout = setTimeout(() => { if (!localAbortController.signal.aborted) { localAbortController.abort(); } }, timeout); const originalClearSignal = () => clearTimeout(signalTimeout); localAbortController.signal.addEventListener('abort', () => { clearTimeout(signalTimeout); }, { once: true }); return { signal: localAbortController.signal, clearSignal: originalClearSignal, get isAborted() { return localAbortController.signal.aborted; }, }; }; let { signal, clearSignal } = setupLocalAbortController(this.maxTimeExecutionMs); const requestConfig = { url, method: 'GET', params: { _: now }, headers: Object.assign({ 'X-Tag': this.srvTag }, (this.token ? { 'X-Token': this.token } : {})), responseType: 'json', // timeout: this.maxTimeExecutionMs, // убираем, потому, что есть signal timeoutErrorMessage: `Request timed out after ${this.maxTimeExecutionMs} ms`, signal: signal, }; return { /** * Executes a query with the specified parameters. * @param queryParams - Query Parameters. * @returns An instance of BetBoosterOfficeApi class. */ query(queryParams = {}) { const query = queryStringHandler(queryParams); requestConfig.params = Object.assign(Object.assign({}, query), requestConfig.params); return this; }, /** * Sets the headers of the request.Sets the headers of the request. * @param headers - Query header object. * @returns An instance of BetBoosterOfficeApi class. */ headers(headers = {}) { requestConfig.headers = Object.assign(Object.assign({}, requestConfig.headers), headers); return this; }, deleteAllHeaders() { delete requestConfig.headers; return this; }, setTimeout(timeout = MAX_TIME_EXECUTION_MS) { clearSignal(); // Очищаем signal потому, что переназначаем его. ({ signal, clearSignal } = setupLocalAbortController(timeout)); // requestConfig.timeout = timeout; // убираем, потому, что есть signal requestConfig.timeoutErrorMessage = `Request timed out after ${timeout} ms`; requestConfig.signal = signal; requestConfig.withXSRFToken = true; return this; }, /** * Sets the method of the GET request. * @returns An instance of BetBoosterOfficeApi class. */ GET() { requestConfig.method = 'GET'; return this; }, /** * Sets the POST request method. * @param payload - The payload for the enquiry. * @returns An instance of BetBoosterOfficeApi class. */ POST(payload = {}) { requestConfig.method = 'POST'; requestConfig.data = payload; return this; }, /** * Устанавливает метод запроса PUT и устанавливает тело запроса. * @param payload - Данные, которые будут отправлены в теле запроса. * @returns Экземпляр класса BetBoosterOfficeApi с установленным методом запроса PUT и телом запроса. */ PUT(payload = {}) { requestConfig.method = 'PUT'; requestConfig.data = payload; return this; }, /** * Устанавливает метод запроса DELETE. * @param payload Данные запроса в формате объекта или записи. * @returns Экземпляр класса BetBoosterOfficeApi. */ DELETE(payload = {}) { requestConfig.method = 'DELETE'; requestConfig.data = payload; return this; }, /** * Выполняет запрос к API. * * @returns Объект, содержащий данные, статус и текст статуса ответа. * ``` * { data, status, statusText } * ``` */ async exec() { if (requestConfig.method !== 'GET') { delete requestConfig.params._; } const response = axi.request(requestConfig) .then(response => { responseHandler(response); return response; }) .catch(axiosErrorHandler) .finally(() => clearSignal()); const { data, status, statusText } = await response; statusHandler(status, statusText); return { data, status, statusText }; }, /** * Получает значение. * @returns Промис, который разрешается с данными. */ async value() { const { data } = await this.exec(); await data; } }; } /** * Sends a GET request to the specified endpoint with optional query parameters and options. * @param url - The endpoint to send the GET request to. * @param queryParams - The query parameters to include in the request URL. Defaults to an empty object. * @param headers - The options to include in the request. Defaults to an empty object. * @returns A Promise that resolves to the response body of the GET request. */ async GET(url, queryParams = {}, headers = {}) { const abortController = new AbortController(); const signal = setTimeout(() => { abortController.abort(); }, this.maxTimeExecutionMs); const requestConfig = { params: this.queryStringHandler(queryParams), headers: Object.assign(Object.assign({}, (this.token ? { 'X-Token': this.token } : {})), (headers !== null && headers !== void 0 ? headers : {})), responseType: 'json', signal: abortController.signal, }; const response = this.axi.get(url, requestConfig) .then(response => { this.responseHandler(response); return response; }) .catch(this.axiosErrorHandler) .finally(() => clearTimeout(signal)); const { data, status, statusText } = await response; this.statusHandler(status, statusText); return data; } async POST(url, payload = {}, queryParams = {}, headers = {}) { const abortController = new AbortController(); const signal = setTimeout(() => { abortController.abort(); }, this.maxTimeExecutionMs); const requestConfig = { params: this.queryStringHandler(queryParams), headers: Object.assign(Object.assign({}, (this.token ? { 'X-Token': this.token } : {})), (headers !== null && headers !== void 0 ? headers : {})), responseType: 'json', signal: abortController.signal, }; const response = this.axi.post(url, payload, requestConfig) .then(response => { this.responseHandler(response); return response; }) .catch(this.axiosErrorHandler) .finally(() => clearTimeout(signal)); const axiData = await response; // console.log(axiData); const { data, status, statusText } = axiData; this.statusHandler(status, statusText); return data; } async DELETE(url, payload = {}, queryParams = {}, headers = {}) { const abortController = new AbortController(); const signal = setTimeout(() => { abortController.abort(); }, this.maxTimeExecutionMs); const requestConfig = { params: this.queryStringHandler(queryParams), headers: Object.assign(Object.assign({}, (this.token ? { 'X-Token': this.token } : {})), (headers !== null && headers !== void 0 ? headers : {})), responseType: 'json', signal: abortController.signal, data: payload, }; const response = this.axi.delete(url, requestConfig) .then(response => { this.responseHandler(response); return response; }) .catch(this.axiosErrorHandler) .finally(() => clearTimeout(signal)); const { data, status, statusText } = await response; this.statusHandler(status, statusText); return data; } async PUT(url, payload = {}, queryParams = {}, headers = {}) { const abortController = new AbortController(); const signal = setTimeout(() => { abortController.abort(); }, this.maxTimeExecutionMs); const requestConfig = { params: this.queryStringHandler(queryParams), headers: Object.assign(Object.assign({}, (this.token ? { 'X-Token': this.token } : {})), (headers !== null && headers !== void 0 ? headers : {})), responseType: 'json', signal: abortController.signal, }; const response = this.axi.put(url, payload, requestConfig) .then(response => { this.responseHandler(response); return response; }) .catch(this.axiosErrorHandler) .finally(() => clearTimeout(signal)); const { data, status, statusText } = await response; this.statusHandler(status, statusText); return data; } // #endregion AXIOS --------------------------------------------------------------------^^^ /** * Returns the list of prematch sports * * @param minutes The number of minutes to consider for the data retrieval. Defaults to 0. * @returns {Promise<Array<any>>} A promise that resolves to an array of line sports data. * @deprecated - use this.getLineSportsMain(); */ async getLineSports(minutes = 0) { var _a; // const url = this.url(`/line/${this.locale}/sports/${minutes}`); // +TODO Включить когда обновиться продакшен const url = +minutes > 0 ? this.url(`/line/${this.locale}/sports/${minutes}`) : this.url(`/line/${this.locale}/allSports`); // console.log(url) const response = (_a = (await this.GET(url, {}, {}))) !== null && _a !== void 0 ? _a : []; // console.log(JSON.stringify(response, null, 2)); return response; } /** * Retrieves the hot prematch events * @returns {Promise<Array<any>>} A promise that resolves to an array of hot events. */ async getHotEvents() { var _a; const url = this.url(`/line/${this.locale}/hotevents`); // console.log(url) return (_a = (await this.GET(url, {}, {}))) !== null && _a !== void 0 ? _a : []; } /** * Получает список стран для указанного идентификатора спорта. * @param sportId - Идентификатор спорта. * @param minutes - Опциональный параметр, количество минут. * @returns Промис, который разрешается в массив объектов типа ICountry. * @deprecated - use this.getCountriesListMain(); */ async getCountriesList(sportId, minutes = 0) { var _a; const url = this.url(`/line/${this.locale}/countries/sport${sportId}/${minutes}`); // console.log(url) return (_a = (await this.GET(url, {}, {}))) !== null && _a !== void 0 ? _a : []; } /** * Retrieves prematch tournaments based on the specified sport ID, country ID, and minutes. * @param sportId - The ID of the sport. * @param countryId - The ID of the country. * @param minutes - The number of minutes ago for which data is to be retrieved. * @returns A promise that resolves to an array of prematch tournaments. * @deprecated - use this.getPrematchTournamentsMain(); */ async getPrematchTournaments(sportId, countryId, minutes = 0) { var _a; const url = this.url(`/line/${this.locale}/tournaments/sport${sportId}/country${countryId}/${minutes}`); // console.log(url) return (_a = (await this.GET(url, {}, {}))) !== null && _a !== void 0 ? _a : []; } /** * Retrieves prematch tournaments based on the specified sport ID and minutes. * @param sportId - The ID of the sport. * @param minutes - The number of minutes ago for which data is to be retrieved. * @returns A filtered list of prematch tournaments. */ async getPrematchTournamentsByMinutes(sportId = 0, minutes = 0) { var _a; const url = this.url(`/line/${this.locale}/events/full/sport${sportId}/${minutes}`); const list = (_a = (await this.GET(url, {}, {}))) !== null && _a !== void 0 ? _a : []; return list.filter((item) => { var _a; return ((_a = item === null || item === void 0 ? void 0 : item.EventsHeaders) !== null && _a !== void 0 ? _a : []).length > 0; }); } /** * Retrieves the headers of prematch tournaments based on the specified sport ID and minutes. * @param sportId The ID of the sport. Defaults to 0 if not provided. * @param minutes - The number of minutes ago for which data is to be retrieved. * @returns A promise that resolves to an array of tournament headers. */ async getPrematchTournamentsHeadersByMinutes(sportId, minutes = 0) { var _a; // const hours = Math.round(minutes / 60); const url = this.url(`/line/${this.locale}/tournaments/headers/sport${sportId}/${minutes}`); const list = (_a = (await this.GET(url, {}, {}))) !== null && _a !== void 0 ? _a : []; // console.log(list); return list; } /** * Retrieves prematch events based on the specified parameters. * @param sportId - The ID of the sport. * @param countryId - The ID of the country. * @param tournamentId - The ID of the tournament. * @param minutes - The number of minutes ago for which data is to be retrieved. * @returns A Promise that resolves to an array of prematch events. */ async getPrematchEvents(sportId, countryId, tournamentId, minutes) { var _a; // ?TODO Хорошо бы сделать фильтр по нескольким турнирам. const url = this.url(`/line/${this.locale}/events/sport${sportId}/country${countryId}/tourney${tournamentId}/${minutes}`); const list = (_a = (await this.GET(url, {}, {}))) !== null && _a !== void 0 ? _a : []; return list; } /** * Sets or resets the live timestamp reset flag. * * @param value - Whether to enable live timestamp reset. Defaults to true. */ liveTimestampReset(value = true) { this._liveTimestampReset = value; } /** * Retrieves an array of live event headers with main bets. * @description For interval request execution, the parameter ```this.liveTimestamp``` * stored in this class is used. After the request is executed, ```this.liveTimestamp``` * is updated from the response. * @param requestFullEventsList - Flag indicating whether to request * the full list of events or only changes since the previous request. * @param events - Array of live event IDs. In this case, the selected live events are returned with all bets. * @returns A promise that resolves to an array of live event data. */ async getLive(requestFullEventsList = false, events = []) { var _a; let liveRecivedIsFullPackage = false; if (requestFullEventsList || this._liveTimestampReset === true) { this.liveTimestamp = 0; this.liveTimestampReset(false); } const url = this.url(`/live/${this.locale}/full/${this.liveTimestamp}/0`); const { data, status /* , statusText */ } = await this.request(url).GET().query({ events }).exec(); const { TimeStamp, LEvents, IsChanges } = data !== null && data !== void 0 ? data : {}; if (IsChanges === false) { liveRecivedIsFullPackage = true; } else { liveRecivedIsFullPackage = false; } if (status === 200) { this.liveTimestamp = (_a = TimeStamp !== null && TimeStamp !== void 0 ? TimeStamp : this.liveTimestamp) !== null && _a !== void 0 ? _a : 0; } else { this.liveTimestamp = 0; } return { ts: +this.liveTimestamp, events: LEvents !== null && LEvents !== void 0 ? LEvents : [], isFullPackage: liveRecivedIsFullPackage, }; } /** * Retrieves complete data on current live events without saving the timestamp. * @returns A promise that resolves to an array of objects of type I.ILiveData. */ async getFullLiveWithoutSaveTimeStamp() { var _a; const url = this.url(`/live/${this.locale}/full/0/0`); const res = (_a = await this.GET(url, {}, {})) !== null && _a !== void 0 ? _a : {}; const { LEvents } = res !== null && res !== void 0 ? res : {}; return LEvents !== null && LEvents !== void 0 ? LEvents : []; } /** * Возвращает массив из одного полного лайв события со всеми ставками по ID . * @param eventId - ID полного live события. * @returns Массив с информацией о событии. */ async getLiveEventsAndFullEvent(eventId) { var _a; const url = this.url(`/live/${this.locale}/bets/${eventId}`); const event = (_a = (await this.GET(url, {}, {}))) !== null && _a !== void 0 ? _a : {}; // console.log(list); return [event]; } /** * Returns an array containing a single complete live event with all bets by ID. * @param eventId - The ID of the complete live event. * @returns An array with event information. */ async getLiveEventFull(eventId) { const url = this.url(`/live/${this.locale}/bets/${eventId}`); const { data /*, status , statusText */ } = await this.request(url).exec(); // console.log(data); return data !== null && data !== void 0 ? data : null; } /** * Retrieves a pre-match event by its ID. * @param eventId - The event identifier. * @returns The pre-match event object. */ async getEventPrematch(eventId) { var _a; const url = this.url(`/line/${this.locale}/event/${eventId}`); const list = (_a = (await this.GET(url, {}, {}))) !== null && _a !== void 0 ? _a : {}; // console.log(list); return list; } async verifyEmail(token) { var _a; // !TODO verifyEmail доделать верификацию пользователя. const url = this.url(`/account/userActivationByEmail/${token}/${this.locale}`); const list = (_a = (await this.GET(url, {}, {}))) !== null && _a !== void 0 ? _a : {}; // console.log(list); return list; } /** * Registers a new user. * @param payload - Data for registration. * @returns A promise that resolves with the registered user data. * @example * ``` * const payload = { * PartnerSiteUid: string; * FirstName?: string; * MiddleName?: string; * EmailOrPhone: string; * CurrencyId?: number; // <- Refer to Swagger !!! * PointId?: number; // <- Refer to Swagger !!! * Password: string; * PasswordRepeat: string; * UrlRedirect?: string; * EmailSubject?: string; * EmailBody?: string; * EmailFrom?: string; * ConfirmUrl?: string; * Culture?: string; * } * ``` */ async signUp(payload) { // !TODO signUp - Изменить. Передавать url редирикта и текст письма. // ? Сделать-то сделал. Но не понятно как регистрировать без привязки к валюте. CurrencyId = null Object.a