UNPKG

iracing-data-api

Version:
1 lines 57.9 kB
{"version":3,"sources":["../src/index.ts","../src/consts.ts","../src/helpers.ts","../src/logger.ts","../src/rate-limiter.ts","../src/api/api.ts","../src/exceptions.ts","../src/api/car.ts","../src/api/carclass.ts","../src/api/constants.ts","../src/api/driver_stats_by_category.ts","../src/api/hosted.ts","../src/api/league.ts","../src/api/lookup.ts","../src/api/member.ts","../src/api/results.ts","../src/api/season.ts","../src/api/series.ts","../src/api/stats.ts","../src/api/team.ts","../src/api/time_attack.ts","../src/api/track.ts"],"sourcesContent":["import makeFetchCookie from \"fetch-cookie\"\n\nimport { API_URL, DEFAULT_OPTIONS } from \"./consts\"\nimport { encryptPassword } from \"./helpers\"\nimport { createLogger } from \"./logger\"\nimport { RateLimiter } from \"./rate-limiter\"\nimport type { FetchCookie, Options } from \"./types\"\n\nimport { CarAPI } from \"./api/car\"\nimport { CarclassAPI } from \"./api/carclass\"\nimport { ConstantsAPI } from \"./api/constants\"\nimport { DriverStatsByCategoryAPI } from \"./api/driver_stats_by_category\"\nimport { HostedAPI } from \"./api/hosted\"\nimport { LeagueAPI } from \"./api/league\"\nimport { LookupAPI } from \"./api/lookup\"\nimport { MemberAPI } from \"./api/member\"\nimport { ResultsAPI } from \"./api/results\"\nimport { SeasonAPI } from \"./api/season\"\nimport { SeriesAPI } from \"./api/series\"\nimport { StatsAPI } from \"./api/stats\"\nimport { TeamAPI } from \"./api/team\"\nimport { TimeAttackAPI } from \"./api/time_attack\"\nimport { TrackAPI } from \"./api/track\"\n\nexport * from \"./types\"\nexport * from \"./api/types\"\nexport * from \"./consts\"\nexport * from \"./exceptions\"\n\nexport default class IracingAPI {\n //\n fetchCookie: FetchCookie\n options: Options\n rateLimiter: RateLimiter\n logger: (...args: unknown[]) => void\n\n // API\n car: CarAPI\n carclass: CarclassAPI\n constants: ConstantsAPI\n driverStatsByCategory: DriverStatsByCategoryAPI\n hosted: HostedAPI\n league: LeagueAPI\n lookup: LookupAPI\n member: MemberAPI\n results: ResultsAPI\n season: SeasonAPI\n series: SeriesAPI\n stats: StatsAPI\n team: TeamAPI\n timeAttack: TimeAttackAPI\n track: TrackAPI\n\n /**\n *\n * @param {Options} [options]\n * @param {boolean} [options.throttleToRateLimit] - If true, will throttle requests to the rate limit.\n */\n constructor(options?: Options) {\n this.fetchCookie = makeFetchCookie(fetch)\n this.options = options ?? DEFAULT_OPTIONS\n this.rateLimiter = new RateLimiter(this.options)\n\n this.car = new CarAPI(this.fetchCookie, this.options, this.rateLimiter)\n this.carclass = new CarclassAPI(\n this.fetchCookie,\n this.options,\n this.rateLimiter\n )\n this.constants = new ConstantsAPI(\n this.fetchCookie,\n this.options,\n this.rateLimiter\n )\n this.driverStatsByCategory = new DriverStatsByCategoryAPI(\n this.fetchCookie,\n this.options,\n this.rateLimiter\n )\n this.hosted = new HostedAPI(\n this.fetchCookie,\n this.options,\n this.rateLimiter\n )\n this.league = new LeagueAPI(\n this.fetchCookie,\n this.options,\n this.rateLimiter\n )\n this.lookup = new LookupAPI(\n this.fetchCookie,\n this.options,\n this.rateLimiter\n )\n this.member = new MemberAPI(\n this.fetchCookie,\n this.options,\n this.rateLimiter\n )\n this.results = new ResultsAPI(\n this.fetchCookie,\n this.options,\n this.rateLimiter\n )\n this.season = new SeasonAPI(\n this.fetchCookie,\n this.options,\n this.rateLimiter\n )\n this.series = new SeriesAPI(\n this.fetchCookie,\n this.options,\n this.rateLimiter\n )\n this.stats = new StatsAPI(this.fetchCookie, this.options, this.rateLimiter)\n this.team = new TeamAPI(this.fetchCookie, this.options, this.rateLimiter)\n this.timeAttack = new TimeAttackAPI(\n this.fetchCookie,\n this.options,\n this.rateLimiter\n )\n this.track = new TrackAPI(this.fetchCookie, this.options, this.rateLimiter)\n\n this.logger = createLogger(this.options)\n }\n\n /**\n *\n * @param email - iRacing account email\n * @param password - iRacing account password\n *\n * @returns\n */\n login = async (email: string, password: string) => {\n const hashPassword = encryptPassword(email, password)\n\n const response = await this.fetchCookie(`${API_URL}auth`, {\n body: JSON.stringify({ email, password: hashPassword }),\n cache: \"no-cache\",\n credentials: \"include\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n method: \"POST\",\n })\n\n if (response.status !== 200) {\n this.logger(\"Login failed...\")\n return {\n error: response.statusText ?? \"Failed to login to iracing-data-api\",\n }\n }\n\n this.logger(\"Login successful...\")\n\n return await response.json()\n }\n}\n","export const API_URL = \"https://members-ng.iracing.com/\"\n\nexport const DEFAULT_OPTIONS = {\n logger: false,\n manageRateLimit: false,\n rateLimitPadding: 5,\n}\n","import { createHash } from \"crypto\"\n\nexport const encryptPassword = (email: string, password: string) =>\n createHash(\"sha256\")\n .update(password + email.toLowerCase())\n .digest(\"base64\")\n","import { Options } from \"./types\"\n\n// TODO: replace with actual logger\nexport const createLogger = (options: Options) => {\n if (options.logger) {\n return (...args: unknown[]) =>\n console.log(`\\x1b[34m[iracing-data-api]\\x1b[0m`, ...args)\n } else {\n return () => {}\n }\n}\n","import { DEFAULT_OPTIONS } from \"./consts\"\nimport { createLogger } from \"./logger\"\nimport { Options } from \"./types\"\n\nexport interface RateLimit {\n limit: number\n remaining: number\n reset: Date\n}\n\nexport class RateLimiter {\n isActive: boolean\n rateLimit: RateLimit | undefined\n limitPadding: number\n logger: (...args: unknown[]) => void\n\n constructor(options: Options) {\n this.logger = createLogger(options)\n\n if (options.manageRateLimit) {\n this.isActive = true\n this.limitPadding =\n options.rateLimitPadding ?? DEFAULT_OPTIONS.rateLimitPadding\n } else {\n this.isActive = false\n this.limitPadding = 0\n }\n }\n\n updateRateLimit = (response: Response) => {\n if (!this.isActive) return\n\n this.rateLimit = this._getRateLimit(response)\n }\n\n checkRateLimit = (): boolean => {\n if (!this.isActive) return true\n if (!this.rateLimit) return true\n if (this.rateLimit.remaining > this.limitPadding) return true\n if (this.rateLimit.reset < new Date()) {\n this.rateLimit = undefined\n return true\n }\n\n return false\n }\n\n waitForReset = async () => {\n if (!this.isActive || !this.rateLimit) return\n\n const timeToReset =\n this.rateLimit.reset.getTime() - new Date().getTime() + 1000\n\n this.logger(\n `Rate limit exceeded. Waiting for reset at ${this.rateLimit.reset.toLocaleString()}...`\n )\n\n await new Promise((resolve) => setTimeout(resolve, timeToReset))\n }\n\n _getRateLimit = (response: Response): RateLimit => {\n const limit = +response.headers.get(\"x-ratelimit-limit\")! ?? 0\n const remaining = +response.headers.get(\"x-ratelimit-remaining\")! ?? 0\n const reset = new Date(\n (+response.headers.get(\"x-ratelimit-reset\")! ?? 0) * 1000\n )\n\n return { limit, remaining, reset }\n }\n}\n","import humps from \"humps\"\n\nimport { API_URL } from \"../consts\"\nimport { createLogger } from \"../logger\"\nimport { RateLimiter } from \"../rate-limiter\"\nimport type { FetchCookie, Options } from \"../types\"\nimport { IracingDataApiException } from \"../exceptions\"\n\nconst { camelizeKeys, decamelizeKeys } = humps\n\nexport class API {\n fetchCookie: FetchCookie\n options: Options\n rateLimiter: RateLimiter\n logger: (...args: unknown[]) => void\n\n constructor(\n fetchCookie: FetchCookie,\n options: Options,\n rateLimiter: RateLimiter\n ) {\n this.fetchCookie = fetchCookie\n this.options = options\n this.rateLimiter = rateLimiter\n this.logger = createLogger(options)\n }\n\n _getData = async <Data = Record<string, unknown>, Parameters = void>(\n endpoint: string,\n params?: Parameters | Record<string, unknown>\n ): Promise<Data | undefined> => {\n try {\n const canProceed = this.rateLimiter.checkRateLimit()\n\n if (!canProceed) {\n await this.rateLimiter.waitForReset()\n }\n\n const url = this._getUrl(endpoint, params)\n\n this.logger(`Getting data from '${url}'`)\n\n const response = await this.fetchCookie(url, {\n cache: \"no-cache\",\n credentials: \"include\",\n })\n this.rateLimiter.updateRateLimit(response)\n\n const data = await response.json()\n\n if (!data || response.status !== 200) {\n throw new IracingDataApiException(response.status, url, data)\n }\n\n return (await this._getLinkData(data.link)) as Data\n } catch (error) {\n this.logger(`Error getting data from '${endpoint}'`)\n throw error\n }\n }\n\n _getLinkData = async (link: string) => {\n const response = await fetch(link)\n const data = await response.json()\n\n if (!data || response.status !== 200) {\n throw new IracingDataApiException(response.status, link, data)\n }\n\n if (data[\"chunk_info\"]) {\n data.data = await this._getChunks(data[\"chunk_info\"])\n }\n\n return camelizeKeys(data)\n }\n\n _getUrl = <Parameters = Record<string, unknown>>(\n endpoint: string,\n params?: Parameters\n ) => {\n const searchParams =\n params &&\n new URLSearchParams(\n decamelizeKeys(params) as Record<string, string>\n ).toString()\n\n return `${API_URL}${endpoint}${searchParams ? `?${searchParams}` : \"\"}`\n }\n\n _getChunks = async (chunks: Record<string, any>) => {\n const baseUrl = chunks[\"base_download_url\"]\n const urls = chunks[\"chunk_file_names\"].map(\n (chunkFileName: string) => `${baseUrl}${chunkFileName}`\n )\n\n const listOfChunks = await Promise.all(\n urls.map(async (url: string) => {\n const response = await fetch(url)\n return response.json()\n })\n )\n\n return listOfChunks.flat()\n }\n}\n","export class IracingDataApiException extends Error {\n constructor(\n public statusCode: number,\n public endpoint: string,\n message: string\n ) {\n super(message)\n }\n}\n","import { API } from \"./api\"\n\nexport class CarAPI extends API {\n /**\n * image paths are relative to https://images-static.iracing.com/.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n assets = () => this._getData<any>(\"data/car/assets\")\n\n /**\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n get = () => this._getData<any>(\"data/car/get\")\n}\n","import { API } from \"./api\"\n\nexport class CarclassAPI extends API {\n /**\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n get = () => this._getData<any>(\"data/carclass/get\")\n}\n","import { API } from \"./api\"\n\nexport class ConstantsAPI extends API {\n /**\n * Constant; returned directly as an array of objects.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n categories = () => this._getData<any>(\"data/constants/categories\")\n\n /**\n * Constant; returned directly as an array of objects.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n divisions = () => this._getData<any>(\"data/constants/divisions\")\n\n /**\n * Constant; returned directly as an array of objects.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n eventTypes = () => this._getData<any>(\"data/constants/event_types\")\n}\n","import { API } from \"./api\"\n\nexport class DriverStatsByCategoryAPI extends API {\n /**\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n oval = () => this._getData<any>(\"data/driver_stats_by_category/oval\")\n\n /**\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n sportsCar = () =>\n this._getData<any>(\"data/driver_stats_by_category/sports_car\")\n\n /**\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n formulaCar = () =>\n this._getData<any>(\"data/driver_stats_by_category/formula_car\")\n\n /**\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n road = () => this._getData<any>(\"data/driver_stats_by_category/road\")\n\n /**\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n dirtOval = () => this._getData<any>(\"data/driver_stats_by_category/dirt_oval\")\n\n /**\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n dirtRoad = () => this._getData<any>(\"data/driver_stats_by_category/dirt_road\")\n}\n","import { API } from \"./api\"\nimport { HostedCombinedSessionsParams } from \"./types/hosted\"\n\nexport class HostedAPI extends API {\n /**\n * Sessions that can be joined as a driver or spectator, and also includes non-league pending sessions for the user.\n * @param {HostedCombinedSessionsParams} params - The params required by the API.\n * @param {number} [params.packageId] - If set, return only sessions using this car or track package ID.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n combinedSessions = (params: HostedCombinedSessionsParams) =>\n this._getData<any>(\"data/hosted/combined_sessions\", params)\n\n /**\n * Sessions that can be joined as a driver.\n * Without spectator and non-league pending sessions for the user.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n sessions = () => this._getData<any>(\"data/hosted/sessions\")\n}\n","import { API } from \"./api\"\nimport {\n LeagueCustLeagueSessionsParams,\n LeagueDirectoryParams,\n LeagueGetParams,\n LeagueGetPointsSystemsParams,\n LeagueMembershipParams,\n LeagueRosterParams,\n LeagueSeasonsParams,\n LeagueSeasonStandingsParams,\n LeagueSeasonSessionsParams,\n} from \"./types/league\"\n\nexport class LeagueAPI extends API {\n /**\n * @param {LeagueCustLeagueSessionsParams} params - The params required by the API.\n * @param {boolean} [params.mine] - If true, return only sessions created by this user.\n * @param {number} [params.packageId] - If set, return only sessions using this car or track package ID.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n custLeagueSessions = (params: LeagueCustLeagueSessionsParams) =>\n this._getData<any>(\"data/league/cust_league_sessions\", params)\n\n /**\n * @param {LeagueDirectoryParams} params - The params required by the API.\n * @param {string} [params.search] - Will search against league name, description, owner, and league ID.\n * @param {string} [params.tag] - One or more tags, comma-separated.\n * @param {boolean} [params.restrictToMember] - If true include only leagues for which customer is a member.\n * @param {boolean} [params.restrictToRecruiting] - If true include only leagues which are recruiting.\n * @param {boolean} [params.restrictToFriends] - If true include only leagues owned by a friend.\n * @param {boolean} [params.restrictToWatched] - If true include only leagues owned by a watched member.\n * @param {number} [params.minimumRosterCount] - If set include leagues with at least this number of members.\n * @param {number} [params.maximumRosterCount] - If set include leagues with no more than this number of members.\n * @param {number} [params.lowerbound] - First row of results to return. Defaults to 1.\n * @param {number} [params.upperbound] - Last row of results to return. Defaults to lowerbound + 39.\n * @param {string} [params.sort] - One of relevance, leaguename, displayname, rostercount. displayname is owners's name. Defaults to relevance.\n * @param {string} [params.order] - One of asc or desc. Defaults to asc.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n directory = (params: LeagueDirectoryParams) =>\n this._getData<any>(\"data/league/directory\", params)\n\n /**\n * @param {LeagueGetParams} params - The params required by the API.\n * @param {number} params.leagueId\n * @param {boolean} [params.includeLicenses] - For faster responses, only request when necessary.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n get = (params: LeagueGetParams) =>\n this._getData<any>(\"data/league/get\", params)\n\n /**\n * @param {LeagueGetPointsSystemsParams} params - The params required by the API.\n * @param {number} params.leagueId\n * @param {number} [params.seasonId] - If included and the season is using custom points (points_system_id:2) then the custom points option is included in the returned list. Otherwise the custom points option is not returned.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n getPointsSystems = (params: LeagueGetPointsSystemsParams) =>\n this._getData<any>(\"data/league/get_points_systems\", params)\n\n /**\n * @param {LeagueMembershipParams} params - The params required by the API.\n * @param {number} [params.custId] - If different from the authenticated member, the following resrictions apply: - Caller cannot be on requested customer's block list or an empty list will result; - Requested customer cannot have their online activity prefrence set to hidden or an empty list will result; - Only leagues for which the requested customer is an admin and the league roster is not private are returned.\n * @param {boolean} [params.includeLeague]\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n membership = (params: LeagueMembershipParams) =>\n this._getData<any>(\"data/league/membership\", params)\n\n /**\n * @param {LeagueRosterParams} params - The params required by the API.\n * @param {number} params.leagueId\n * @param {boolean} [params.includeLicenses] - For faster responses, only request when necessary.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n roster = (params: LeagueRosterParams) =>\n this._getData<any>(\"data/league/roster\", params)\n\n /**\n * @param {LeagueSeasonsParams} params - The params required by the API.\n * @param {number} params.leagueId\n * @param {boolean} [params.retired] - If true include seasons which are no longer active.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n seasons = (params: LeagueSeasonsParams) =>\n this._getData<any>(\"data/league/seasons\", params)\n\n /**\n * @param {LeagueSeasonStandingsParams} params - The params required by the API.\n * @param {number} params.leagueId\n * @param {number} params.seasonId\n * @param {number} [params.carClassId]\n * @param {number} [params.carId] - If car_class_id is included then the standings are for the car in that car class, otherwise they are for the car across car classes.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n seasonStandings = (params: LeagueSeasonStandingsParams) =>\n this._getData<any>(\"data/league/season_standings\", params)\n\n /**\n * @param {LeagueSeasonSessionsParams} params - The params required by the API.\n * @param {number} params.leagueId\n * @param {number} params.seasonId\n * @param {boolean} [params.resultsOnly] - If true include only sessions for which results are available.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n seasonSessions = (params: LeagueSeasonSessionsParams) =>\n this._getData<any>(\"data/league/season_sessions\", params)\n}\n","import { API } from \"./api\"\nimport { LookupClubHistoryParams, LookupDriversParams } from \"./types/lookup\"\n\nexport class LookupAPI extends API {\n /**\n * Returns an earlier history if requested quarter does not have a club history.\n * @param {LookupClubHistoryParams} params - The params required by the API.\n * @param {number} params.seasonYear\n * @param {number} params.seasonQuarter\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n clubHistory = (params: LookupClubHistoryParams) =>\n this._getData<any>(\"data/lookup/club_history\", params)\n\n /**\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n countries = () => this._getData<any>(\"data/lookup/countries\")\n\n /**\n * @param {LookupDriversParams} params - The params required by the API.\n * @param {string} params.searchTerm - A cust_id or partial name for which to search.\n * @param {number} [params.leagueId] - Narrow the search to the roster of the given league.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n drivers = (params: LookupDriversParams) =>\n this._getData<any>(\"data/lookup/drivers\", params)\n\n /**\n * ?weather=weather_wind_speed_units&weather=weather_wind_speed_max&weather=weather_wind_speed_min&licenselevels=licenselevels.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n get = () => this._getData<any>(\"data/lookup/get\")\n\n /**\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n licenses = () => this._getData<any>(\"data/lookup/licenses\")\n}\n","import { API } from \"./api\"\nimport {\n MemberAwardsParams,\n MemberChartDataParams,\n MemberGetParams,\n MemberProfileParams,\n} from \"./types/member\"\n\nexport class MemberAPI extends API {\n /**\n * @param {MemberAwardsParams} params - The params required by the API.\n * @param {number} [params.custId] - Defaults to the authenticated member.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n awards = (params: MemberAwardsParams) =>\n this._getData<any>(\"data/member/awards\", params)\n\n /**\n * @param {MemberChartDataParams} params - The params required by the API.\n * @param {number} [params.custId] - Defaults to the authenticated member.\n * @param {number} params.categoryId - 1 - Oval; 2 - Road; 3 - Dirt oval; 4 - Dirt road\n * @param {number} params.chartType - 1 - iRating; 2 - TT Rating; 3 - License/SR\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n chartData = (params: MemberChartDataParams) =>\n this._getData<any>(\"data/member/chart_data\", params)\n\n /**\n * @param {MemberGetParams} params - The params required by the API.\n * @param {number[]} params.custIds - ?cust_ids=2,3,4\n * @param {boolean} [params.includeLicenses]\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n get = (params: MemberGetParams) =>\n this._getData<any>(\"data/member/get\", params)\n\n /**\n * Always the authenticated member.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n info = () => this._getData<any>(\"data/member/info\")\n\n /**\n * Always the authenticated member.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n participationCredits = () =>\n this._getData<any>(\"data/member/participation_credits\")\n\n /**\n * @param {MemberProfileParams} params - The params required by the API.\n * @param {number} [params.custId] - Defaults to the authenticated member.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n profile = (params: MemberProfileParams) =>\n this._getData<any>(\"data/member/profile\", params)\n}\n","import { API } from \"./api\"\nimport {\n ResultsGetParams,\n ResultsEventLogParams,\n ResultsLapChartDataParams,\n ResultsLapDataParams,\n ResultsSearchHostedParams,\n ResultsSearchSeriesParams,\n ResultsSeasonResultsParams,\n} from \"./types/results\"\n\nexport class ResultsAPI extends API {\n /**\n * Get the results of a subsession, if authorized to view them.\n * series_logo image paths are relative to https://images-static.iracing.com/img/logos/series/.\n * @param {ResultsGetParams} params - The params required by the API.\n * @param {number} params.subsessionId\n * @param {boolean} [params.includeLicenses]\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n get = (params: ResultsGetParams) =>\n this._getData<any>(\"data/results/get\", params)\n\n /**\n * @param {ResultsEventLogParams} params - The params required by the API.\n * @param {number} params.subsessionId\n * @param {number} params.simsessionNumber - The main event is 0; the preceding event is -1, and so on.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n eventLog = (params: ResultsEventLogParams) =>\n this._getData<any>(\"data/results/event_log\", params)\n\n /**\n * @param {ResultsLapChartDataParams} params - The params required by the API.\n * @param {number} params.subsessionId\n * @param {number} params.simsessionNumber - The main event is 0; the preceding event is -1, and so on.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n lapChartData = (params: ResultsLapChartDataParams) =>\n this._getData<any>(\"data/results/lap_chart_data\", params)\n\n /**\n * @param {ResultsLapDataParams} params - The params required by the API.\n * @param {number} params.subsessionId\n * @param {number} params.simsessionNumber - The main event is 0; the preceding event is -1, and so on.\n * @param {number} [params.custId] - Required if the subsession was a single-driver event. Optional for team events. If omitted for a team event then the laps driven by all the team's drivers will be included.\n * @param {number} [params.teamId] - Required if the subsession was a team event.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n lapData = (params: ResultsLapDataParams) =>\n this._getData<any>(\"data/results/lap_data\", params)\n\n /**\n * Hosted and league sessions.\n * Maximum time frame of 90 days.\n * Results split into one or more files with chunks of results.\n * For scraping results the most effective approach is to keep track of the maximum end_time found during a search then make the subsequent call using that date/time as the finish_range_begin and skip any subsessions that are duplicated.\n * Results are ordered by subsessionid which is a proxy for start time.\n * Requires one of: start_range_begin, finish_range_begin.\n * Requires one of: cust_id, team_id, host_cust_id, session_name.\n * @param {ResultsSearchHostedParams} params - The params required by the API.\n * @param {string} [params.startRangeBegin] - Session start times. ISO-8601 UTC time zero offset: \"2022-04-01T15:45Z\".\n * @param {string} [params.startRangeEnd] - ISO-8601 UTC time zero offset: \"2022-04-01T15:45Z\". Exclusive. May be omitted if start_range_begin is less than 90 days in the past.\n * @param {string} [params.finishRangeBegin] - Session finish times. ISO-8601 UTC time zero offset: \"2022-04-01T15:45Z\".\n * @param {string} [params.finishRangeEnd] - ISO-8601 UTC time zero offset: \"2022-04-01T15:45Z\". Exclusive. May be omitted if finish_range_begin is less than 90 days in the past.\n * @param {number} [params.custId] - The participant's customer ID. Ignored if team_id is supplied.\n * @param {number} [params.teamId] - The team ID to search for. Takes priority over cust_id if both are supplied.\n * @param {number} [params.hostCustId] - The host's customer ID.\n * @param {string} [params.sessionName] - Part or all of the session's name.\n * @param {number} [params.leagueId] - Include only results for the league with this ID.\n * @param {number} [params.leagueSeasonId] - Include only results for the league season with this ID.\n * @param {number} [params.carId] - One of the cars used by the session.\n * @param {number} [params.trackId] - The ID of the track used by the session.\n * @param {number[]} [params.categoryIds] - Track categories to include in the search. Defaults to all. ?category_ids=1,2,3,4\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n searchHosted = (params: ResultsSearchHostedParams) =>\n this._getData<any>(\"data/results/search_hosted\", params)\n\n /**\n * Official series.\n * Maximum time frame of 90 days.\n * Results split into one or more files with chunks of results.\n * For scraping results the most effective approach is to keep track of the maximum end_time found during a search then make the subsequent call using that date/time as the finish_range_begin and skip any subsessions that are duplicated.\n * Results are ordered by subsessionid which is a proxy for start time but groups together multiple splits of a series when multiple series launch sessions at the same time.\n * Requires at least one of: season_year and season_quarter, start_range_begin, finish_range_begin.\n * @param {ResultsSearchSeriesParams} params - The params required by the API.\n * @param {number} [params.seasonYear] - Required when using season_quarter.\n * @param {number} [params.seasonQuarter] - Required when using season_year.\n * @param {string} [params.startRangeBegin] - Session start times. ISO-8601 UTC time zero offset: \"2022-04-01T15:45Z\".\n * @param {string} [params.startRangeEnd] - ISO-8601 UTC time zero offset: \"2022-04-01T15:45Z\". Exclusive. May be omitted if start_range_begin is less than 90 days in the past.\n * @param {string} [params.finishRangeBegin] - Session finish times. ISO-8601 UTC time zero offset: \"2022-04-01T15:45Z\".\n * @param {string} [params.finishRangeEnd] - ISO-8601 UTC time zero offset: \"2022-04-01T15:45Z\". Exclusive. May be omitted if finish_range_begin is less than 90 days in the past.\n * @param {number} [params.custId] - Include only sessions in which this customer participated. Ignored if team_id is supplied.\n * @param {number} [params.teamId] - Include only sessions in which this team participated. Takes priority over cust_id if both are supplied.\n * @param {number} [params.seriesId] - Include only sessions for series with this ID.\n * @param {number} [params.raceWeekNum] - Include only sessions with this race week number.\n * @param {boolean} [params.officialOnly] - If true, include only sessions earning championship points. Defaults to all.\n * @param {number[]} [params.eventTypes] - Types of events to include in the search. Defaults to all. ?event_types=2,3,4,5\n * @param {number[]} [params.categoryIds] - License categories to include in the search. Defaults to all. ?category_ids=1,2,3,4\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n searchSeries = (params: ResultsSearchSeriesParams) =>\n this._getData<any>(\"data/results/search_series\", params)\n\n /**\n * @param {ResultsSeasonResultsParams} params - The params required by the API.\n * @param {number} params.seasonId\n * @param {number} [params.eventType] - Retrict to one event type: 2 - Practice; 3 - Qualify; 4 - Time Trial; 5 - Race\n * @param {number} [params.raceWeekNum] - The first race week of a season is 0.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n seasonResults = (params: ResultsSeasonResultsParams) =>\n this._getData<any>(\"data/results/season_results\", params)\n}\n","import { API } from \"./api\"\nimport {\n SeasonListParams,\n SeasonRaceGuideParams,\n SeasonSpectatorSubsessionidsParams,\n SeasonSpectatorSubsessionidsDetailParams,\n} from \"./types/season\"\n\nexport class SeasonAPI extends API {\n /**\n * @param {SeasonListParams} params - The params required by the API.\n * @param {number} params.seasonYear\n * @param {number} params.seasonQuarter\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n list = (params: SeasonListParams) =>\n this._getData<any>(\"data/season/list\", params)\n\n /**\n * @param {SeasonRaceGuideParams} params - The params required by the API.\n * @param {string} [params.from] - ISO-8601 offset format. Defaults to the current time. Include sessions with start times up to 3 hours after this time. Times in the past will be rewritten to the current time.\n * @param {boolean} [params.includeEndAfterFrom] - Include sessions which start before 'from' but end after.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n raceGuide = (params: SeasonRaceGuideParams) =>\n this._getData<any>(\"data/season/race_guide\", params)\n\n /**\n * @param {SeasonSpectatorSubsessionidsParams} params - The params required by the API.\n * @param {number[]} [params.eventTypes] - Types of events to include in the search. Defaults to all. ?event_types=2,3,4,5\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n spectatorSubsessionids = (params: SeasonSpectatorSubsessionidsParams) =>\n this._getData<any>(\"data/season/spectator_subsessionids\", params)\n\n /**\n * @param {SeasonSpectatorSubsessionidsDetailParams} params - The params required by the API.\n * @param {number[]} [params.eventTypes] - Types of events to include in the search. Defaults to all. ?event_types=2,3,4,5\n * @param {number[]} [params.seasonIds] - Seasons to include in the search. Defaults to all. ?season_ids=513,937\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n spectatorSubsessionidsDetail = (\n params: SeasonSpectatorSubsessionidsDetailParams\n ) => this._getData<any>(\"data/season/spectator_subsessionids_detail\", params)\n}\n","import { API } from \"./api\"\nimport { SeriesPastSeasonsParams, SeriesSeasonsParams } from \"./types/series\"\n\nexport class SeriesAPI extends API {\n /**\n * image paths are relative to https://images-static.iracing.com/.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n assets = () => this._getData<any>(\"data/series/assets\")\n\n /**\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n get = () => this._getData<any>(\"data/series/get\")\n\n /**\n * Get all seasons for a series.\n * Filter list by official:true for seasons with standings.\n * @param {SeriesPastSeasonsParams} params - The params required by the API.\n * @param {number} params.seriesId\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n pastSeasons = (params: SeriesPastSeasonsParams) =>\n this._getData<any>(\"data/series/past_seasons\", params)\n\n /**\n * @param {SeriesSeasonsParams} params - The params required by the API.\n * @param {boolean} [params.includeSeries]\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n seasons = (params: SeriesSeasonsParams) =>\n this._getData<any>(\"data/series/seasons\", params)\n\n /**\n * To get series and seasons for which standings should be available, filter the list by official: true.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n statsSeries = () => this._getData<any>(\"data/series/stats_series\")\n}\n","import { API } from \"./api\"\nimport {\n StatsMemberBestsParams,\n StatsMemberCareerParams,\n StatsMemberDivisionParams,\n StatsMemberRecapParams,\n StatsMemberRecentRacesParams,\n StatsMemberSummaryParams,\n StatsMemberYearlyParams,\n StatsSeasonDriverStandingsParams,\n StatsSeasonSupersessionStandingsParams,\n StatsSeasonTeamStandingsParams,\n StatsSeasonTtStandingsParams,\n StatsSeasonTtResultsParams,\n StatsSeasonQualifyResultsParams,\n StatsWorldRecordsParams,\n} from \"./types/stats\"\n\nexport class StatsAPI extends API {\n /**\n * @param {StatsMemberBestsParams} params - The params required by the API.\n * @param {number} [params.custId] - Defaults to the authenticated member.\n * @param {number} [params.carId] - First call should exclude car_id; use cars_driven list in return for subsequent calls.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n memberBests = (params: StatsMemberBestsParams) =>\n this._getData<any>(\"data/stats/member_bests\", params)\n\n /**\n * @param {StatsMemberCareerParams} params - The params required by the API.\n * @param {number} [params.custId] - Defaults to the authenticated member.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n memberCareer = (params: StatsMemberCareerParams) =>\n this._getData<any>(\"data/stats/member_career\", params)\n\n /**\n * Divisions are 0-based: 0 is Division 1, 10 is Rookie.\n * See /data/constants/divisons for more information.\n * Always for the authenticated member.\n * @param {StatsMemberDivisionParams} params - The params required by the API.\n * @param {number} params.seasonId\n * @param {number} params.eventType - The event type code for the division type: 4 - Time Trial; 5 - Race\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n memberDivision = (params: StatsMemberDivisionParams) =>\n this._getData<any>(\"data/stats/member_division\", params)\n\n /**\n * @param {StatsMemberRecapParams} params - The params required by the API.\n * @param {number} [params.custId] - Defaults to the authenticated member.\n * @param {number} [params.year] - Season year; if not supplied the current calendar year (UTC) is used.\n * @param {number} [params.season] - Season (quarter) within the year; if not supplied the recap will be fore the entire year.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n memberRecap = (params: StatsMemberRecapParams) =>\n this._getData<any>(\"data/stats/member_recap\", params)\n\n /**\n * @param {StatsMemberRecentRacesParams} params - The params required by the API.\n * @param {number} [params.custId] - Defaults to the authenticated member.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n memberRecentRaces = (params: StatsMemberRecentRacesParams) =>\n this._getData<any>(\"data/stats/member_recent_races\", params)\n\n /**\n * @param {StatsMemberSummaryParams} params - The params required by the API.\n * @param {number} [params.custId] - Defaults to the authenticated member.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n memberSummary = (params: StatsMemberSummaryParams) =>\n this._getData<any>(\"data/stats/member_summary\", params)\n\n /**\n * @param {StatsMemberYearlyParams} params - The params required by the API.\n * @param {number} [params.custId] - Defaults to the authenticated member.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n memberYearly = (params: StatsMemberYearlyParams) =>\n this._getData<any>(\"data/stats/member_yearly\", params)\n\n /**\n * @param {StatsSeasonDriverStandingsParams} params - The params required by the API.\n * @param {number} params.seasonId\n * @param {number} params.carClassId\n * @param {number} [params.clubId] - Defaults to all (-1).\n * @param {number} [params.division] - Divisions are 0-based: 0 is Division 1, 10 is Rookie. See /data/constants/divisons for more information. Defaults to all.\n * @param {number} [params.raceWeekNum] - The first race week of a season is 0.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n seasonDriverStandings = (params: StatsSeasonDriverStandingsParams) =>\n this._getData<any>(\"data/stats/season_driver_standings\", params)\n\n /**\n * @param {StatsSeasonSupersessionStandingsParams} params - The params required by the API.\n * @param {number} params.seasonId\n * @param {number} params.carClassId\n * @param {number} [params.clubId] - Defaults to all (-1).\n * @param {number} [params.division] - Divisions are 0-based: 0 is Division 1, 10 is Rookie. See /data/constants/divisons for more information. Defaults to all.\n * @param {number} [params.raceWeekNum] - The first race week of a season is 0.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n seasonSupersessionStandings = (\n params: StatsSeasonSupersessionStandingsParams\n ) => this._getData<any>(\"data/stats/season_supersession_standings\", params)\n\n /**\n * @param {StatsSeasonTeamStandingsParams} params - The params required by the API.\n * @param {number} params.seasonId\n * @param {number} params.carClassId\n * @param {number} [params.raceWeekNum] - The first race week of a season is 0.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n seasonTeamStandings = (params: StatsSeasonTeamStandingsParams) =>\n this._getData<any>(\"data/stats/season_team_standings\", params)\n\n /**\n * @param {StatsSeasonTtStandingsParams} params - The params required by the API.\n * @param {number} params.seasonId\n * @param {number} params.carClassId\n * @param {number} [params.clubId] - Defaults to all (-1).\n * @param {number} [params.division] - Divisions are 0-based: 0 is Division 1, 10 is Rookie. See /data/constants/divisons for more information. Defaults to all.\n * @param {number} [params.raceWeekNum] - The first race week of a season is 0.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n seasonTtStandings = (params: StatsSeasonTtStandingsParams) =>\n this._getData<any>(\"data/stats/season_tt_standings\", params)\n\n /**\n * @param {StatsSeasonTtResultsParams} params - The params required by the API.\n * @param {number} params.seasonId\n * @param {number} params.carClassId\n * @param {number} params.raceWeekNum - The first race week of a season is 0.\n * @param {number} [params.clubId] - Defaults to all (-1).\n * @param {number} [params.division] - Divisions are 0-based: 0 is Division 1, 10 is Rookie. See /data/constants/divisons for more information. Defaults to all.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n seasonTtResults = (params: StatsSeasonTtResultsParams) =>\n this._getData<any>(\"data/stats/season_tt_results\", params)\n\n /**\n * @param {StatsSeasonQualifyResultsParams} params - The params required by the API.\n * @param {number} params.seasonId\n * @param {number} params.carClassId\n * @param {number} params.raceWeekNum - The first race week of a season is 0.\n * @param {number} [params.clubId] - Defaults to all (-1).\n * @param {number} [params.division] - Divisions are 0-based: 0 is Division 1, 10 is Rookie. See /data/constants/divisons for more information. Defaults to all.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n seasonQualifyResults = (params: StatsSeasonQualifyResultsParams) =>\n this._getData<any>(\"data/stats/season_qualify_results\", params)\n\n /**\n * @param {StatsWorldRecordsParams} params - The params required by the API.\n * @param {number} params.carId\n * @param {number} params.trackId\n * @param {number} [params.seasonYear] - Limit best times to a given year.\n * @param {number} [params.seasonQuarter] - Limit best times to a given quarter; only applicable when year is used.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n worldRecords = (params: StatsWorldRecordsParams) =>\n this._getData<any>(\"data/stats/world_records\", params)\n}\n","import { API } from \"./api\"\nimport { TeamGetParams } from \"./types/team\"\n\nexport class TeamAPI extends API {\n /**\n * @param {TeamGetParams} params - The params required by the API.\n * @param {number} params.teamId\n * @param {boolean} [params.includeLicenses] - For faster responses, only request when necessary.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n get = (params: TeamGetParams) => this._getData<any>(\"data/team/get\", params)\n}\n","import { API } from \"./api\"\nimport { TimeAttackMemberSeasonResultsParams } from \"./types/time_attack\"\n\nexport class TimeAttackAPI extends API {\n /**\n * Results for the authenticated member, if any.\n * @param {TimeAttackMemberSeasonResultsParams} params - The params required by the API.\n * @param {number} params.taCompSeasonId\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n memberSeasonResults = (params: TimeAttackMemberSeasonResultsParams) =>\n this._getData<any>(\"data/time_attack/member_season_results\", params)\n}\n","import { API } from \"./api\"\n\nexport class TrackAPI extends API {\n /**\n * image paths are relative to https://images-static.iracing.com/.\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n assets = () => this._getData<any>(\"data/track/assets\")\n\n /**\n * @returns {Promise<any>}\n * @throws {Error} - Throws an exception if the API call fails.\n */\n get = () => this._getData<any>(\"data/track/get\")\n}\n"],"mappings":"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