├── docs ├── .gitignore ├── .vitepress │ ├── cache │ │ └── deps │ │ │ ├── package.json │ │ │ ├── vue.js.map │ │ │ ├── _metadata.json │ │ │ └── vue.js │ ├── theme │ │ ├── index.ts │ │ └── style.css │ └── config.mts ├── package.json ├── api │ ├── car-class.md │ ├── team.md │ ├── car.md │ ├── time-attack.md │ ├── track.md │ ├── how-to-use.md │ ├── constants.md │ ├── hosted.md │ ├── lookup.md │ ├── series.md │ ├── season.md │ ├── member.md │ ├── results.md │ ├── league.md │ └── stats.md ├── index.md └── getting-started.md ├── .gitignore ├── packages └── iracing-api │ ├── .gitignore │ ├── .prettierrc │ ├── src │ ├── helpers.ts │ ├── consts.ts │ ├── types │ │ ├── time-attack.ts │ │ ├── constants.ts │ │ ├── car-class.ts │ │ ├── index.ts │ │ ├── lookup.ts │ │ ├── team.ts │ │ ├── season.ts │ │ ├── track.ts │ │ ├── car.ts │ │ ├── hosted.ts │ │ ├── common.ts │ │ ├── league.ts │ │ ├── series.ts │ │ ├── stats.ts │ │ └── member.ts │ ├── logger.ts │ ├── api │ │ ├── car-class.ts │ │ ├── track.ts │ │ ├── car.ts │ │ ├── team.ts │ │ ├── time-attack.ts │ │ ├── constants.ts │ │ ├── hosted.ts │ │ ├── lookup.ts │ │ ├── series.ts │ │ ├── season.ts │ │ ├── api.ts │ │ ├── member.ts │ │ ├── league.ts │ │ ├── stats.ts │ │ └── results.ts │ ├── rate-limiter.ts │ └── index.ts │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── package.json │ └── README.md ├── pnpm-workspace.yaml ├── package.json ├── README.md └── TODO.md /docs/.gitignore: -------------------------------------------------------------------------------- 1 | .vitepress/cache -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | .vscode -------------------------------------------------------------------------------- /packages/iracing-api/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /lib -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | - 'docs' -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /packages/iracing-api/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 4, 4 | "semi": false, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/vue.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [], 4 | "sourcesContent": [], 5 | "mappings": "", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /packages/iracing-api/src/helpers.ts: -------------------------------------------------------------------------------- 1 | import CryptoJS from 'crypto-js' 2 | 3 | export const encryptPassword = (email: string, password: string) => 4 | CryptoJS.enc.Base64.stringify( 5 | CryptoJS.SHA256(password + email.toLowerCase()) 6 | ) 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iracing-api-root", 3 | "private": true, 4 | "scripts": { 5 | "docs:dev": "pnpm --filter iracing-api-docs dev", 6 | "docs:build": "pnpm --filter iracing-api-docs build", 7 | "docs:serve": "pnpm --filter iracing-api-docs serve" 8 | } 9 | } -------------------------------------------------------------------------------- /packages/iracing-api/src/consts.ts: -------------------------------------------------------------------------------- 1 | export const API_URL = 'https://members-ng.iracing.com/' 2 | 3 | export const DEFAULT_RATE_LIMIT_PADDING = 5 4 | export const DEFAULT_OPTIONS = { 5 | logger: false, 6 | manageRateLimit: false, 7 | rateLimitPadding: DEFAULT_RATE_LIMIT_PADDING, 8 | } 9 | -------------------------------------------------------------------------------- /packages/iracing-api/src/types/time-attack.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | 3 | // Params 4 | // 5 | export const GetTimeAttackSeasonParamsSchema = z.object({ 6 | seasonId: z.number(), 7 | }) 8 | export type GetTimeAttackSeasonParams = z.infer< 9 | typeof GetTimeAttackSeasonParamsSchema 10 | > 11 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iracing-api-docs", 3 | "version": "1.0.0", 4 | "devDependencies": { 5 | "vitepress": "^1.0.2", 6 | "vue": "^3.4.21" 7 | }, 8 | "scripts": { 9 | "dev": "vitepress dev", 10 | "build": "vitepress build", 11 | "preview": "vitepress preview" 12 | } 13 | } -------------------------------------------------------------------------------- /docs/api/car-class.md: -------------------------------------------------------------------------------- 1 | # Car Class API 2 | 3 | All methods in the `Car Class` API are available through the `carClass` property of the `iRacingAPI` instance. 4 | 5 | ## Car Classes 6 | 7 | Get the car classes. 8 | 9 | ```ts 10 | const carClasses = await ir.carClass.getCarClasses(); 11 | ``` 12 | https://members-ng.iracing.com/data/carclass/get -------------------------------------------------------------------------------- /packages/iracing-api/src/logger.ts: -------------------------------------------------------------------------------- 1 | import { Options } from './types' 2 | 3 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 4 | export let logger = (..._args: unknown[]) => {} 5 | 6 | export const createLogger = (options: Options) => { 7 | if (options.logger) { 8 | logger = (...args: unknown[]) => 9 | console.log(`\x1b[34m[iracing-api]\x1b[0m`, ...args) 10 | } else { 11 | logger = () => {} 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | // https://vitepress.dev/guide/custom-theme 2 | import { h } from 'vue' 3 | import type { Theme } from 'vitepress' 4 | import DefaultTheme from 'vitepress/theme' 5 | import './style.css' 6 | 7 | export default { 8 | extends: DefaultTheme, 9 | Layout: () => { 10 | return h(DefaultTheme.Layout, null, { 11 | // https://vitepress.dev/guide/extending-default-theme#layout-slots 12 | }) 13 | }, 14 | enhanceApp({ app, router, siteData }) { 15 | // ... 16 | } 17 | } satisfies Theme 18 | -------------------------------------------------------------------------------- /docs/api/team.md: -------------------------------------------------------------------------------- 1 | # Team API 2 | 3 | All methods in the `Team` API are available through the `team` property of the `iRacingAPI` instance. 4 | 5 | ## Data 6 | 7 | Get the team data. 8 | 9 | ```ts 10 | const teamData = await ir.team.getTeamData(params); 11 | ``` 12 | 13 | Available parameters: 14 | * `teamId: number` - The team ID of the team to get the data for. 15 | * `includeMembers?: boolean` - Include the members in the data. 16 | * For faster responses, only request when necessary. 17 | 18 | https://members-ng.iracing.com/data/team/get -------------------------------------------------------------------------------- /packages/iracing-api/src/api/car-class.ts: -------------------------------------------------------------------------------- 1 | import { CarClass } from '../types/car-class' 2 | import { API } from './api' 3 | 4 | /** 5 | * Provides methods for interacting with car class endpoints. 6 | */ 7 | export class CarClassAPI extends API { 8 | /** 9 | * Get a list of all available car classes. 10 | * 11 | * @returns A promise resolving to an array of car class objects, or undefined on error. 12 | */ 13 | getCarClasses = async () => { 14 | return await this._getData('data/carclass/get') 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /docs/api/car.md: -------------------------------------------------------------------------------- 1 | # Car API 2 | 3 | All methods in the `Car` API are available through the `car` property of the `iRacingAPI` instance. 4 | 5 | ## Cars 6 | 7 | Get the cars. 8 | 9 | ```ts 10 | const cars = await ir.car.getCars(); 11 | ``` 12 | https://members-ng.iracing.com/data/car/get 13 | 14 | ## Car Assets 15 | 16 | Get the car assets. 17 | 18 | * Image paths are relative to https://images-static.iracing.com/ 19 | 20 | ```ts 21 | const carAssets = await ir.car.getCarAssets(); 22 | ``` 23 | https://members-ng.iracing.com/data/car/assets 24 | 25 | -------------------------------------------------------------------------------- /docs/api/time-attack.md: -------------------------------------------------------------------------------- 1 | # Time Attack API 2 | 3 | All methods in the `Time Attack` API are available through the `timeAttack` property of the `iRacingAPI` instance. 4 | 5 | ## Season Results 6 | 7 | Get the time attack season results. 8 | 9 | * Results for the authenticated member, if any. 10 | 11 | ```ts 12 | const seasonResults = await ir.timeAttack.getTimeAttackSeasonResults(params); 13 | ``` 14 | 15 | Available parameters: 16 | * `seasonId: number` - The season ID to get the results for. 17 | 18 | https://members-ng.iracing.com/data/time_attack/member_season_results -------------------------------------------------------------------------------- /docs/api/track.md: -------------------------------------------------------------------------------- 1 | # Track API 2 | 3 | All methods in the `Track` API are available through the `track` property of the `iRacingAPI` instance. 4 | 5 | ## Assets 6 | 7 | Get the track assets. 8 | 9 | * Image paths are relative to https://images-static.iracing.com/ 10 | 11 | ```ts 12 | const trackAssets = await ir.track.getTrackAssets(); 13 | ``` 14 | https://members-ng.iracing.com/data/track/assets 15 | 16 | ## Tracks 17 | 18 | Get the tracks. 19 | 20 | ```ts 21 | const tracks = await ir.track.getTracks(); 22 | ``` 23 | https://members-ng.iracing.com/data/track/get -------------------------------------------------------------------------------- /packages/iracing-api/src/types/constants.ts: -------------------------------------------------------------------------------- 1 | import * as z from 'zod' 2 | 3 | export const ConstantCategorySchema = z.object({ 4 | label: z.string(), 5 | value: z.number(), 6 | }) 7 | export type Category = z.infer 8 | 9 | export const DivisionSchema = z.object({ 10 | label: z.string(), 11 | value: z.number(), 12 | }) 13 | export type Division = z.infer 14 | 15 | export const EventSchema = z.object({ 16 | label: z.string(), 17 | value: z.number(), 18 | }) 19 | export type Event = z.infer 20 | -------------------------------------------------------------------------------- /packages/iracing-api/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:@typescript-eslint/eslint-recommended", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "parser": "@typescript-eslint/parser", 12 | "parserOptions": { 13 | "ecmaVersion": "latest", 14 | "sourceType": "module" 15 | }, 16 | "plugins": ["@typescript-eslint"], 17 | "root": true, 18 | "rules": { 19 | "@typescript-eslint/no-explicit-any": "warn" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/iracing-api/src/types/car-class.ts: -------------------------------------------------------------------------------- 1 | import * as z from 'zod' 2 | 3 | export const CarsInClassSchema = z.object({ 4 | carDirpath: z.string(), 5 | carId: z.number(), 6 | rainEnabled: z.boolean(), 7 | retired: z.boolean(), 8 | }) 9 | export type CarsInClass = z.infer 10 | 11 | export const CarClassSchema = z.object({ 12 | carClassId: z.number(), 13 | carsInClass: z.array(CarsInClassSchema), 14 | custId: z.number(), 15 | name: z.string(), 16 | rainEnabled: z.boolean(), 17 | relativeSpeed: z.number(), 18 | shortName: z.string(), 19 | }) 20 | export type CarClass = z.infer 21 | -------------------------------------------------------------------------------- /docs/api/how-to-use.md: -------------------------------------------------------------------------------- 1 | # How to use 2 | 3 | ## API Client 4 | 5 | ```ts 6 | import { iRacingAPI } from 'iracing-api'; 7 | 8 | const ir = new iRacingAPI(options); 9 | ``` 10 | 11 | ### Options 12 | 13 | * logger: `boolean` - Enable logging of requests and responses. Default is `false`. 14 | * manageRateLimits: `boolean` - Enable rate limit management. Default is `false`. 15 | * rateLimitPadding: `number` - Add a padding to the rate limit to avoid hitting the limit. Default is `5`. 16 | 17 | ### Login 18 | 19 | ```ts 20 | const email = 'email@domain.com'; 21 | const password = 'password'; 22 | 23 | await ir.login(email, password); 24 | ``` 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iRacing API 2 | 3 | ## Installation 4 | 5 | ```bash 6 | npm install iracing-api 7 | yarn add iracing-api 8 | pnpm i iracing-api 9 | bun i iracing-api 10 | ``` 11 | 12 | ## Basic Usage 13 | 14 | 15 | ```typescript 16 | import IracingAPI from 'iracing-api' 17 | 18 | const irUser = 'FOO@gmail.com' 19 | const irPass = 'BAR' 20 | 21 | const main = async () => { 22 | const ir = new IracingAPI() 23 | 24 | // First you have to login to iracing using your credentials to be able to use the API. 25 | await ir.login(irUser, irPass) 26 | 27 | // Now you can use any endpoint, e.g. getCars 28 | const cars = await ir.car.getCars() 29 | 30 | console.log(cars) 31 | } 32 | 33 | main().then(() => 'Done') 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "iRacing API" 7 | text: "A wrapper for iRacing API" 8 | # tagline: My great project tagline 9 | actions: 10 | - theme: brand 11 | text: Get Started 12 | link: /getting-started 13 | - theme: alt 14 | text: View on GitHub 15 | link: https://github.com/themich4/iracing-api 16 | 17 | features: 18 | - title: Type safe 19 | details: Responses are typed using TypeScript. 20 | - title: Handle rate limits 21 | details: Rate limits are handled automatically, so you don't have to worry about them. 22 | - title: Easy to use 23 | details: The API is designed to be easy to use and understand. 24 | --- 25 | 26 | -------------------------------------------------------------------------------- /docs/api/constants.md: -------------------------------------------------------------------------------- 1 | # Constants API 2 | 3 | All methods in the `Constants` API are available through the `constants` property of the `iRacingAPI` instance. 4 | 5 | ## Categories 6 | 7 | Get the categories. 8 | 9 | ```ts 10 | const categories = await ir.constants.getCategories(); 11 | ``` 12 | https://members-ng.iracing.com/data/constants/categories 13 | 14 | ## Divisions 15 | 16 | Get the divisions. 17 | 18 | ```ts 19 | const divisions = await ir.constants.getDivisions(); 20 | ``` 21 | https://members-ng.iracing.com/data/constants/divisions 22 | 23 | ## Event Types 24 | 25 | Get the event types. 26 | 27 | ```ts 28 | const eventTypes = await ir.constants.getEventTypes(); 29 | ``` 30 | https://members-ng.iracing.com/data/constants/eventtypes -------------------------------------------------------------------------------- /packages/iracing-api/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './car' 2 | export * from './car-class' 3 | export * from './common' 4 | export * from './constants' 5 | export * from './hosted' 6 | export * from './league' 7 | export * from './lookup' 8 | export * from './member' 9 | export * from './results' 10 | export * from './season' 11 | export * from './series' 12 | export * from './stats' 13 | export * from './team' 14 | export * from './time-attack' 15 | export * from './track' 16 | 17 | export interface FetchCookie { 18 | ( 19 | input: RequestInfo | URL, 20 | init?: RequestInit | undefined 21 | ): Promise 22 | } 23 | 24 | export interface Options { 25 | logger?: boolean 26 | manageRateLimit?: boolean 27 | rateLimitPadding?: number 28 | } 29 | 30 | export interface RateLimit { 31 | limit: number 32 | remaining: number 33 | reset: Date 34 | } 35 | -------------------------------------------------------------------------------- /packages/iracing-api/src/api/track.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import { Track, TrackAssets } from '../types' 3 | 4 | /** 5 | * Provides methods for interacting with track-related endpoints. 6 | */ 7 | export class TrackAPI extends API { 8 | /** 9 | * Get assets for all tracks (logos, images, map layers, etc.). 10 | * 11 | * Note: Image paths are relative to `https://images-static.iracing.com/`. 12 | * 13 | * @returns A promise resolving to the track assets data, or undefined on error. 14 | */ 15 | getTrackAssets = async () => 16 | await this._getData('data/track/assets') 17 | /** 18 | * Get a list of all available tracks and their configurations. 19 | * 20 | * @returns A promise resolving to an array of track objects, or undefined on error. 21 | */ 22 | getTracks = async () => await this._getData('data/track/get') 23 | } 24 | -------------------------------------------------------------------------------- /docs/api/hosted.md: -------------------------------------------------------------------------------- 1 | # Hosted API 2 | 3 | All methods in the `Hosted` API are available through the `hosted` property of the `iRacingAPI` instance. 4 | 5 | ## Combined Sessions 6 | 7 | Get the combined sessions. 8 | 9 | * Sessions that can be joined as a driver or spectator, and also includes non-league pending sessions for the user. 10 | 11 | ```ts 12 | const combinedSessions = await ir.hosted.getCombinedSessions(params); 13 | ``` 14 | 15 | Available parameters: 16 | * `packageId?: number` - If set, return only sessions using this car or track package ID. 17 | 18 | https://members-ng.iracing.com/data/hosted/combined_sessions 19 | 20 | ## Hosted Sessions 21 | 22 | Get the hosted sessions. 23 | 24 | * Sessions that can be joined as a driver. Without spectator and non-league pending sessions for the user. 25 | 26 | ```ts 27 | const hostedSessions = await ir.hosted.getHostedSessions(); 28 | ``` 29 | 30 | https://members-ng.iracing.com/data/hosted/sessions 31 | -------------------------------------------------------------------------------- /packages/iracing-api/src/api/car.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import { type Car } from '../types/car' 3 | import { type CarAssetsResponse } from '../types/car' 4 | 5 | /** 6 | * Provides methods for interacting with car-related endpoints. 7 | */ 8 | export class CarAPI extends API { 9 | /** 10 | * Get car assets, including images and details. 11 | * 12 | * Note: Image paths in the response are relative to `https://images-static.iracing.com/`. 13 | * 14 | * @returns A promise resolving to the car assets data, or undefined on error. 15 | */ 16 | getCarAssets = async () => { 17 | return await this._getData('data/car/assets') 18 | } 19 | /** 20 | * Get a list of all available cars. 21 | * 22 | * @returns A promise resolving to an array of car objects, or undefined on error. 23 | */ 24 | getCars = async () => { 25 | return await this._getData('data/car/get') 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/iracing-api/src/api/team.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import { GetTeamDataParams, GetTeamDataResponse } from '../types' 3 | 4 | /** 5 | * Provides methods for interacting with team-related endpoints. 6 | */ 7 | export class TeamAPI extends API { 8 | /** 9 | * Get detailed information about a specific team. 10 | * 11 | * @param {GetTeamDataParams} params - Parameters for the request. 12 | * @param {number} params.teamId - The ID of the team to retrieve. 13 | * @param {boolean} [params.includeLicenses=false] - Include license information for members (can slow down response). 14 | * 15 | * @returns A promise resolving to the team data, or undefined on error. 16 | */ 17 | getTeamData = async ( 18 | params: GetTeamDataParams 19 | ): Promise => 20 | await this._getData('data/team/get', { 21 | team_id: params.teamId, 22 | include_licenses: params.includeLicenses, 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /docs/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## Installation 4 | 5 | Add **iracing-api** to your project by running the following command: 6 | 7 | ::: code-group 8 | 9 | ```sh [npm] 10 | $ npm add iracing-api 11 | ``` 12 | 13 | ```sh [pnpm] 14 | $ pnpm add iracing-api 15 | ``` 16 | 17 | ```sh [yarn] 18 | $ yarn add iracing-api 19 | ``` 20 | 21 | ```sh [bun] 22 | $ bun add iracing-api 23 | ``` 24 | 25 | ::: 26 | 27 | ## Basic usage 28 | 29 | To use the iRacing API, you have to log in first, and then you can request data. Here is a basic example: 30 | 31 | ```ts 32 | import IracingAPI from 'iracing-api' 33 | 34 | const irUser = 'FOO@gmail.com' 35 | const irPass = 'BAR' 36 | 37 | const main = async () => { 38 | const ir = new IracingAPI() 39 | 40 | // First you have to login to iracing using your credentials to be able to use the API. 41 | await ir.login(irUser, irPass) 42 | 43 | // Now you can use any endpoint, e.g. getCars 44 | const cars = await ir.car.getCars() 45 | 46 | console.log(cars) 47 | } 48 | 49 | main().then(() => 'Done') 50 | ``` -------------------------------------------------------------------------------- /packages/iracing-api/src/api/time-attack.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import { GetTimeAttackSeasonParams } from '../types/time-attack' 3 | 4 | /** 5 | * Provides methods for interacting with time attack competition endpoints. 6 | */ 7 | export class TimeAttackAPI extends API { 8 | /** 9 | * Get the time attack season results for the **authenticated** member. 10 | * 11 | * @param {GetTimeAttackSeasonParams} params - Parameters for the request. 12 | * @param {number} params.seasonId - The ID of the time attack competition season (`ta_comp_season_id`). 13 | * 14 | * @returns A promise resolving to the member's time attack season results, or undefined on error. 15 | * Note: The specific type for the results array is not fully defined yet. 16 | */ 17 | getTimeAttackSeasonResults = async (params: GetTimeAttackSeasonParams) => 18 | await this._getData>( 19 | 'data/time_attack/member_season_results', 20 | { 21 | ta_comp_season_id: params.seasonId, 22 | } 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "hash": "86f99711", 3 | "configHash": "fa783255", 4 | "lockfileHash": "1ad3f5e2", 5 | "browserHash": "c6a42194", 6 | "optimized": { 7 | "vue": { 8 | "src": "../../../../node_modules/.pnpm/vue@3.4.21/node_modules/vue/dist/vue.runtime.esm-bundler.js", 9 | "file": "vue.js", 10 | "fileHash": "172d343f", 11 | "needsInterop": false 12 | }, 13 | "vitepress > @vue/devtools-api": { 14 | "src": "../../../../node_modules/.pnpm/@vue+devtools-api@7.0.25_vue@3.4.21/node_modules/@vue/devtools-api/dist/index.js", 15 | "file": "vitepress___@vue_devtools-api.js", 16 | "fileHash": "82d6a55b", 17 | "needsInterop": false 18 | }, 19 | "vitepress > @vueuse/core": { 20 | "src": "../../../../node_modules/.pnpm/@vueuse+core@10.9.0_vue@3.4.21/node_modules/@vueuse/core/index.mjs", 21 | "file": "vitepress___@vueuse_core.js", 22 | "fileHash": "0f1cea27", 23 | "needsInterop": false 24 | } 25 | }, 26 | "chunks": { 27 | "chunk-KJTOLQBP": { 28 | "file": "chunk-KJTOLQBP.js" 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /packages/iracing-api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 4 | "module": "ESNext" /* Specify what module code is generated. */, 5 | "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, 6 | "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, 7 | "outDir": "./lib" /* Specify an output folder for all emitted files. */, 8 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */, 9 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 10 | "strict": true /* Enable all strict type-checking options. */ 11 | }, 12 | "include": ["src"], 13 | "exclude": ["node_modules", "**/__tests__/*"] 14 | } 15 | -------------------------------------------------------------------------------- /packages/iracing-api/src/api/constants.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import { Category, Division, Event } from '../types/index' 3 | 4 | /** 5 | * Provides methods for retrieving constant data like categories, divisions, and event types. 6 | */ 7 | export class ConstantsAPI extends API { 8 | /** 9 | * Get the list of iRacing racing categories (e.g., Oval, Road). 10 | * 11 | * @returns A promise resolving to an array of category objects, or undefined on error. 12 | */ 13 | getCategories = async () => { 14 | return await this._getData('data/constants/categories') 15 | } 16 | /** 17 | * Get the list of iRacing divisions (e.g., Division 1, Rookie). 18 | * 19 | * @returns A promise resolving to an array of division objects, or undefined on error. 20 | */ 21 | getDivisions = async () => { 22 | return await this._getData('data/constants/divisions') 23 | } 24 | /** 25 | * Get the list of iRacing event types (e.g., Practice, Race). 26 | * 27 | * @returns A promise resolving to an array of event type objects, or undefined on error. 28 | */ 29 | getEventTypes = async () => { 30 | return await this._getData('data/constants/event_types') 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/iracing-api/src/types/lookup.ts: -------------------------------------------------------------------------------- 1 | import * as z from 'zod' 2 | 3 | export const CountrySchema = z.object({ 4 | countryName: z.string(), 5 | countryCode: z.string(), 6 | }) 7 | export type Country = z.infer 8 | 9 | export const LevelSchema = z.object({ 10 | licenseId: z.number(), 11 | licenseGroup: z.number(), 12 | license: z.string(), 13 | shortName: z.string(), 14 | licenseLetter: z.string(), 15 | color: z.string(), 16 | }) 17 | export type Level = z.infer 18 | 19 | export const LicenseSchema = z.object({ 20 | licenseGroup: z.number(), 21 | groupName: z.string(), 22 | minNumRaces: z.union([z.number(), z.null()]), 23 | participationCredits: z.number(), 24 | minSrToFastTrack: z.union([z.number(), z.null()]), 25 | levels: z.array(LevelSchema), 26 | minNumTt: z.union([z.number(), z.null()]), 27 | }) 28 | export type License = z.infer 29 | 30 | // Params 31 | export const GetClubHistoryParamsSchema = z.object({ 32 | seasonYear: z.number(), 33 | seasonQuarter: z.number(), 34 | }) 35 | export type GetClubHistoryParams = z.infer 36 | 37 | export const GetDriversParamsSchema = z.object({ 38 | searchTerm: z.string(), 39 | leagueId: z.number().optional(), 40 | }) 41 | export type GetDriversParams = z.infer 42 | -------------------------------------------------------------------------------- /docs/api/lookup.md: -------------------------------------------------------------------------------- 1 | # Lookup API 2 | 3 | All methods in the `Lookup` API are available through the `lookup` property of the `iRacingAPI` instance. 4 | 5 | ## Club History 6 | 7 | Get the club history. 8 | 9 | * Returns an earlier history if requested quarter does not have a club history. 10 | 11 | ```ts 12 | const clubHistory = await ir.lookup.getClubHistory(params); 13 | ``` 14 | 15 | Available parameters: 16 | * `seasonYear: number` - The season year to get the club history for. 17 | * `seasonQuarter: number` - The season quarter to get the club history for. 18 | 19 | https://members-ng.iracing.com/data/lookup/club_history 20 | 21 | ## Countries 22 | 23 | Get the countries. 24 | 25 | ```ts 26 | const countries = await ir.lookup.getCountries(); 27 | ``` 28 | 29 | https://members-ng.iracing.com/data/lookup/countries 30 | 31 | ## Drivers 32 | 33 | Get the drivers. 34 | 35 | ```ts 36 | const drivers = await ir.lookup.getDrivers(params); 37 | ``` 38 | 39 | Available parameters: 40 | * `searchTerm: string` - The search string to filter the drivers by. 41 | * A customer ID or partial name for which to search. 42 | * `leagueId?: number` - The league id to filter the drivers by. 43 | * Narrow the search to the roster of the given league. 44 | 45 | https://members-ng.iracing.com/data/lookup/drivers 46 | 47 | ## Licenses 48 | 49 | Get the licenses. 50 | 51 | ```ts 52 | const licenses = await ir.lookup.getLicenses(); 53 | ``` 54 | https://members-ng.iracing.com/data/lookup/licenses -------------------------------------------------------------------------------- /docs/api/series.md: -------------------------------------------------------------------------------- 1 | # Series API 2 | 3 | All methods in the `Series` API are available through the `series` property of the `iRacingAPI` instance. 4 | 5 | ## Assets 6 | 7 | Get the series assets. 8 | 9 | * Image paths are relative to https://images-static.iracing.com/ 10 | 11 | ```ts 12 | const seriesAssets = await ir.series.getSeriesAssets(); 13 | ``` 14 | 15 | https://members-ng.iracing.com/data/series/assets 16 | 17 | ## Series 18 | 19 | Get the series data. 20 | 21 | ```ts 22 | const seriesData = await ir.series.getSeriesData(); 23 | ``` 24 | 25 | https://members-ng.iracing.com/data/series/get 26 | 27 | ## Past Seasons 28 | 29 | Get all seasons for the series. 30 | 31 | * Filter list by `official: true` for seasons with standings. 32 | 33 | ```ts 34 | const pastSeasons = await ir.series.getSeriesPastSeasons(params); 35 | ``` 36 | 37 | Available parameters: 38 | * `seriesId: number` - The series ID to get the past seasons for. 39 | 40 | https://members-ng.iracing.com/data/series/past_seasons 41 | 42 | ## Seasons 43 | 44 | ```ts 45 | const seasons = await ir.series.getSeriesSeasons(params); 46 | ``` 47 | 48 | Available parameters: 49 | * `includeSeries?: boolean` - Include the series in the data. 50 | 51 | ## Stats 52 | 53 | Get the series stats. 54 | 55 | * To get series and seasons for which standings should be available, filter the list by `official: true`. 56 | 57 | ```ts 58 | const seriesStats = await ir.series.getSeriesStats(); 59 | ``` 60 | https://members-ng.iracing.com/data/series/stats_series -------------------------------------------------------------------------------- /docs/api/season.md: -------------------------------------------------------------------------------- 1 | # Season API 2 | 3 | All methods in the `Season` API are available through the `season` property of the `iRacingAPI` instance. 4 | 5 | ## List 6 | 7 | Get the seasons. 8 | 9 | ```ts 10 | const seasons = await ir.season.getSeasonList(params); 11 | ``` 12 | 13 | Available parameters: 14 | * `seasonYear: number` - The season year to get the seasons for. 15 | * `seasonQuarter: number` - The season quarter to get the seasons for. 16 | 17 | https://members-ng.iracing.com/data/season/list 18 | 19 | ## Race Guide 20 | 21 | Get the season race guide. 22 | 23 | ```ts 24 | const raceGuide = await ir.season.getSeasonRaceGuide(params); 25 | ``` 26 | 27 | Available parameters: 28 | * `from?: string` - The start date 29 | * [`ISO-8601`](https://en.wikipedia.org/wiki/ISO_8601) offset format. 30 | * Defaults to the current time. 31 | * Include sessions with start times up to 3 hours after this time. 32 | * Times in the past will be rewritten to the current time. 33 | * `includeEndAfterFrom?: boolean` - Include sessions which start before `from` but end after. 34 | 35 | https://members-ng.iracing.com/data/season/race_guide 36 | 37 | ## Spectator Subsession Ids 38 | 39 | Get the season spectator subsession ids. 40 | 41 | ```ts 42 | const spectatorSubsessionIds = await ir.season.getSpectatorSubsessionIds(params); 43 | ``` 44 | 45 | Available parameters: 46 | * `eventTypes?: number[]` - Types of events to include in the search. 47 | * Defaults to all. 48 | 49 | 50 | https://members-ng.iracing.com/data/season/spectator_subsession_ids -------------------------------------------------------------------------------- /packages/iracing-api/src/api/hosted.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import type { 3 | GetHostedCombinedSessionsParams, 4 | HostedCombinedSessions, 5 | HostedSessions, 6 | } from '../types' 7 | 8 | /** 9 | * Provides methods for interacting with hosted session endpoints. 10 | */ 11 | export class HostedAPI extends API { 12 | /** 13 | * Get a list of combined hosted sessions. 14 | * 15 | * Includes sessions that can be joined as a driver or spectator, 16 | * and also includes non-league pending sessions for the user. 17 | * 18 | * @param {GetHostedCombinedSessionsParams} [params] - Optional parameters to filter the sessions. 19 | * @param {number} [params.packageId] - If set, return only sessions using this car or track package ID. 20 | * 21 | * @returns A promise resolving to the combined hosted sessions data, or undefined on error. 22 | */ 23 | getHostedCombinedSessions = async ( 24 | params?: GetHostedCombinedSessionsParams 25 | ) => { 26 | return await this._getData( 27 | 'data/hosted/combined_sessions', 28 | { 29 | package_id: params?.packageId, 30 | } 31 | ) 32 | } 33 | /** 34 | * Get a list of hosted sessions that can be joined as a driver. 35 | * 36 | * Excludes spectator sessions and non-league pending sessions. 37 | * 38 | * @returns A promise resolving to the hosted sessions data, or undefined on error. 39 | */ 40 | getHostedSessions = async () => { 41 | return await this._getData('data/hosted/sessions') 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /docs/.vitepress/config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | 3 | // https://vitepress.dev/reference/site-config 4 | export default defineConfig({ 5 | title: "iRacing API", 6 | description: "A wrapper for the iRacing API", 7 | themeConfig: { 8 | // https://vitepress.dev/reference/default-theme-config 9 | nav: [ 10 | { text: 'Home', link: '/' }, 11 | { text: 'Docs', link: '/getting-started' } 12 | ], 13 | 14 | sidebar: [ 15 | { 16 | text: 'Introduction', 17 | items: [ 18 | { text: 'Getting started', link: '/getting-started' }, 19 | ] 20 | }, 21 | { 22 | text: 'API', 23 | items: [ 24 | { text: 'How to use', link: '/api/how-to-use' }, 25 | { text: 'Car', link: '/api/car' }, 26 | { text: 'Car Class', link: '/api/car-class' }, 27 | { text: 'Constants', link: '/api/constants' }, 28 | { text: 'Hosted', link: '/api/hosted' }, 29 | { text: 'League', link: '/api/league' }, 30 | { text: 'Lookup', link: '/api/lookup' }, 31 | { text: 'Member', link: '/api/member' }, 32 | { text: 'Results', link: '/api/results' }, 33 | { text: 'Season', link: '/api/season' }, 34 | { text: 'Series', link: '/api/series' }, 35 | { text: 'Stats', link: '/api/stats' }, 36 | { text: 'Team', link: '/api/team' }, 37 | { text: 'Time Attack', link: '/api/time-attack' }, 38 | { text: 'Track', link: '/api/track' }, 39 | ] 40 | } 41 | ], 42 | 43 | socialLinks: [ 44 | { icon: 'github', link: 'https://github.com/themich4/iracing-api' } 45 | ] 46 | } 47 | }) 48 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO - Missing iRacing API Types and Endpoints 2 | 3 | This file lists the API endpoints where parameter or response types are currently missing or incomplete, and endpoints that are not implemented at all. 4 | 5 | ## Missing Types for Implemented Endpoints 6 | 7 | ### `api/car-class.ts` 8 | 9 | - `getCarClasses`: Missing response type. 10 | 11 | ### `api/car.ts` 12 | 13 | - `getCarAssets`: Missing response type. 14 | 15 | ### `api/constants.ts` 16 | 17 | - `getEventTypes`: Missing response type (`Event[]`). 18 | 19 | ### `api/league.ts` 20 | 21 | - `getLeagueData`: Missing response type. 22 | - `getLeaguePointSystem`: Missing response type. 23 | - `getLeagueMembership`: Missing response type. 24 | - `getLeagueSeasons`: Missing response type. 25 | - `getLeagueSeasonStandings`: Missing response type. 26 | - `getLeagueSeasonSessions`: Missing response type. 27 | - `getLeagueRoster`: Missing response type. 28 | 29 | ### `api/lookup.ts` 30 | 31 | - `getDrivers`: Missing response type. 32 | - `getLookupData`: Missing response type. 33 | 34 | ### `api/results.ts` 35 | 36 | - `getResultsEventLog`: Missing response type. 37 | - `getResultsLapChartData`: Missing response type. 38 | 39 | ### `api/time-attack.ts` 40 | 41 | - `getTimeAttackSeasonResults`: Missing response type (`Array`). 42 | 43 | ### `api/driver-stats.ts` 44 | 45 | - All methods: Missing response types. 46 | 47 | ### `api/member.ts` 48 | 49 | - `getMemberAwardInstances`: Missing response type. 50 | 51 | ### `api/season.ts` 52 | 53 | - `getSpectatorSubsessionIdsDetail`: Missing response type. 54 | 55 | ## Missing Endpoint Implementations 56 | 57 | No endpoints are currently missing implementation. All endpoints mentioned in api.json are now implemented. -------------------------------------------------------------------------------- /packages/iracing-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iracing-api", 3 | "version": "0.5.2", 4 | "description": "Javascript client for iracing API", 5 | "exports": "./lib/index.js", 6 | "types": "./lib/index.d.ts", 7 | "type": "module", 8 | "scripts": { 9 | "build": "tsc", 10 | "format": "eslint --ext .js,.ts src/ --fix; prettier . --write", 11 | "prepare": "pnpm run build", 12 | "prepublishOnly": "pnpm run format", 13 | "version": "pnpm run format && git add -A src", 14 | "postversion": "git push && git push --tags", 15 | "patch": "version patch" 16 | }, 17 | "files": [ 18 | "lib/**/*" 19 | ], 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/TheMich4/iracing-api.git" 23 | }, 24 | "author": "Michal Dyczkowski", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/TheMich4/iracing-api/issues" 28 | }, 29 | "homepage": "https://iracing-api.dyczkowski.dev/", 30 | "dependencies": { 31 | "crypto-js": "^4.1.1", 32 | "fetch-cookie": "^2.1.0", 33 | "humps": "^2.0.1", 34 | "zod": "^3.22.4" 35 | }, 36 | "devDependencies": { 37 | "@types/crypto-js": "^4.1.1", 38 | "@types/humps": "^2.0.2", 39 | "@types/node": "^18.13.0", 40 | "@types/tough-cookie": "^4.0.2", 41 | "@typescript-eslint/eslint-plugin": "^6.6.0", 42 | "@typescript-eslint/parser": "^6.6.0", 43 | "eslint": "^8.49.0", 44 | "prettier": "3.1.0", 45 | "typescript": "^4.9.5" 46 | }, 47 | "keywords": [ 48 | "iracing", 49 | "api", 50 | "client", 51 | "javascript", 52 | "typescript", 53 | "iracing-api", 54 | "iracing-api-client" 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /packages/iracing-api/src/rate-limiter.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_RATE_LIMIT_PADDING } from './consts' 2 | import { logger } from './logger' 3 | import { type Options, type RateLimit } from './types' 4 | 5 | export class RateLimiter { 6 | static instance: RateLimiter 7 | 8 | isActive: boolean = false 9 | rateLimit: RateLimit | undefined = undefined 10 | limitPadding: number = DEFAULT_RATE_LIMIT_PADDING 11 | 12 | constructor(options: Options) { 13 | if (RateLimiter.instance) { 14 | return RateLimiter.instance 15 | } 16 | 17 | if (options.manageRateLimit) { 18 | this.isActive = true 19 | this.limitPadding = 20 | options.rateLimitPadding ?? DEFAULT_RATE_LIMIT_PADDING 21 | } 22 | 23 | RateLimiter.instance = this 24 | } 25 | 26 | updateRateLimit = (response: Response) => { 27 | if (!this.isActive) return 28 | 29 | this.rateLimit = this._getRateLimit(response) 30 | } 31 | 32 | checkRateLimit = (): boolean => { 33 | if (!this.isActive) return true 34 | if (!this.rateLimit) return true 35 | if (this.rateLimit.remaining > this.limitPadding) return true 36 | if (this.rateLimit.reset < new Date()) { 37 | this.rateLimit = undefined 38 | return true 39 | } 40 | 41 | return false 42 | } 43 | 44 | waitForReset = async () => { 45 | if (!this.isActive || !this.rateLimit) return 46 | 47 | const timeToReset = 48 | this.rateLimit.reset.getTime() - new Date().getTime() + 1000 49 | 50 | logger( 51 | `Rate limit exceeded. Waiting for reset at ${this.rateLimit.reset.toLocaleString()}...` 52 | ) 53 | 54 | await new Promise((resolve) => setTimeout(resolve, timeToReset)) 55 | } 56 | 57 | _getRateLimit = (response: Response): RateLimit => { 58 | const limit = +response.headers.get('x-ratelimit-limit')! ?? 0 59 | const remaining = +response.headers.get('x-ratelimit-remaining')! ?? 0 60 | const reset = new Date( 61 | (+response.headers.get('x-ratelimit-reset')! ?? 0) * 1000 62 | ) 63 | 64 | return { limit, remaining, reset } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /packages/iracing-api/src/types/team.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | 3 | // Params 4 | 5 | export const GetTeamDataParamsSchema = z.object({ 6 | teamId: z.number(), 7 | includeLicenses: z.boolean().optional(), 8 | }) 9 | export type GetTeamDataParams = z.infer 10 | 11 | // Response 12 | export const GetTeamDataResponseSchema = z.object({ 13 | teamId: z.number(), 14 | ownerId: z.number(), 15 | teamName: z.string(), 16 | created: z.string(), 17 | hidden: z.boolean(), 18 | about: z.string(), 19 | url: z.string(), 20 | rosterCount: z.number(), 21 | recruiting: z.boolean(), 22 | privateWall: z.boolean(), 23 | isDefault: z.boolean(), 24 | isOwner: z.boolean(), 25 | isAdmin: z.boolean(), 26 | suit: z.object({ 27 | pattern: z.number(), 28 | color1: z.string(), 29 | color2: z.string(), 30 | color3: z.string(), 31 | }), 32 | owner: z.object({ 33 | custId: z.number(), 34 | displayName: z.string(), 35 | helmet: z.object({ 36 | pattern: z.number(), 37 | color1: z.string(), 38 | color2: z.string(), 39 | color3: z.string(), 40 | faceType: z.number(), 41 | helmetType: z.number(), 42 | }), 43 | owner: z.boolean(), 44 | admin: z.boolean(), 45 | }), 46 | tags: z.object({ 47 | categorized: z.array(z.string()), 48 | notCategorized: z.array(z.string()), 49 | }), 50 | teamApplications: z.array(z.unknown()), 51 | pendingRequests: z.array(z.unknown()), 52 | isMember: z.boolean(), 53 | isApplicant: z.boolean(), 54 | isInvite: z.boolean(), 55 | isIgnored: z.boolean(), 56 | roster: z.array( 57 | z.object({ 58 | custId: z.number(), 59 | displayName: z.string(), 60 | helmet: z.object({ 61 | pattern: z.number(), 62 | color1: z.string(), 63 | color2: z.string(), 64 | color3: z.string(), 65 | faceType: z.number(), 66 | helmetType: z.number(), 67 | }), 68 | owner: z.boolean(), 69 | admin: z.boolean(), 70 | }) 71 | ), 72 | }) 73 | export type GetTeamDataResponse = z.infer 74 | -------------------------------------------------------------------------------- /docs/api/member.md: -------------------------------------------------------------------------------- 1 | # Member API 2 | 3 | All methods in the `Member` API are available through the `member` property of the `iRacingAPI` instance. 4 | 5 | ## Awards 6 | 7 | Get the awards. 8 | 9 | ```ts 10 | const awards = await ir.member.getAwards(); 11 | ``` 12 | 13 | Available parameters: 14 | * `customerId?: number` - The customer ID of the member to get the awards for. 15 | * Defaults to the authenticated member. 16 | 17 | https://members-ng.iracing.com/data/member/awards 18 | 19 | ## Chart Data 20 | 21 | Get the chart data. 22 | 23 | ```ts 24 | const chartData = await ir.member.getChartData(); 25 | ``` 26 | 27 | Available parameters: 28 | * `customerId?: number` - The customer ID of the member to get the chart data for. 29 | * Defaults to the authenticated member. 30 | * `categoryId: number` - The category ID 31 | * `1` - Oval 32 | * `2` - Road 33 | * `3` - Dirt Oval 34 | * `4` - Dirt Road 35 | * `chartType: number` - The chart type 36 | * `1` - iRating 37 | * `2` - TT Rating 38 | * `3` - License/SR 39 | 40 | https://members-ng.iracing.com/data/member/chart_data 41 | 42 | ## Data 43 | 44 | Get the member data. 45 | 46 | ```ts 47 | const memberData = await ir.member.getMemberData(params); 48 | ``` 49 | 50 | Available parameters: 51 | * `customerIds: number[]` - The customer IDs of the members to get the data for. 52 | * `includeLicenses?: boolean` - Include the licenses in the data. 53 | 54 | https://members-ng.iracing.com/data/member/get 55 | 56 | ## Info 57 | 58 | Get the member info. 59 | 60 | * Always the authenticated member. 61 | 62 | ```ts 63 | const memberInfo = await ir.member.getMemberInfo(); 64 | ``` 65 | https://members-ng.iracing.com/data/member/info 66 | 67 | ## Participation Credits 68 | 69 | Get the participation credits. 70 | 71 | * Always the authenticated member. 72 | 73 | ```ts 74 | const participationCredits = await ir.member.getParticipationCredits(); 75 | ``` 76 | https://members-ng.iracing.com/data/member/participation_credits 77 | 78 | ## Profile 79 | 80 | Get the member profile. 81 | 82 | 83 | ```ts 84 | const memberProfile = await ir.member.getMemberProfile(params); 85 | ``` 86 | 87 | Available parameters: 88 | * `customerId?: number` - The customer ID of the member to get the profile for. 89 | * Defaults to the authenticated member. 90 | 91 | https://members-ng.iracing.com/data/member/profile -------------------------------------------------------------------------------- /packages/iracing-api/src/api/lookup.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import { 3 | Country, 4 | GetClubHistoryParams, 5 | GetDriversParams, 6 | License, 7 | } from '../types/lookup' 8 | 9 | /** 10 | * Provides methods for interacting with lookup endpoints (e.g., countries, drivers, licenses). 11 | */ 12 | export class LookupAPI extends API { 13 | /** 14 | * Get club history for a specific season. 15 | * 16 | * Note: Returns an earlier history if the requested quarter does not have a club history. 17 | * 18 | * @param {GetClubHistoryParams} params - Parameters for the request. 19 | * @param {number} params.seasonYear - The year of the season. 20 | * @param {number} params.seasonQuarter - The quarter of the season (1-4). 21 | * 22 | * @returns A promise resolving to the club history data, or undefined on error. 23 | */ 24 | getClubHistory = async (params: GetClubHistoryParams) => 25 | await this._getData('data/lookup/club_history', { 26 | season_year: params.seasonYear, 27 | season_quarter: params.seasonQuarter, 28 | }) 29 | /** 30 | * Get a list of all countries recognized by iRacing. 31 | * 32 | * @returns A promise resolving to an array of country objects, or undefined on error. 33 | */ 34 | getCountries = async () => 35 | await this._getData('data/lookup/countries') 36 | /** 37 | * Search for drivers by customer ID or partial name. 38 | * 39 | * @param {GetDriversParams} params - Parameters for the search. 40 | * @param {string} params.searchTerm - A customer ID or partial name to search for. 41 | * @param {number} [params.leagueId] - Optional league ID to narrow the search to the league's roster. 42 | * 43 | * @returns A promise resolving to the driver search results, or undefined on error. 44 | */ 45 | getDrivers = async (params: GetDriversParams) => 46 | await this._getData('data/lookup/drivers', { 47 | search_term: params.searchTerm, 48 | league_id: params.leagueId, 49 | }) 50 | /** 51 | * Get a list of all iRacing licenses. 52 | * 53 | * @returns A promise resolving to an array of license objects, or undefined on error. 54 | */ 55 | getLicenses = async () => 56 | await this._getData('data/lookup/licenses') 57 | 58 | /** 59 | * Get various lookup data. 60 | * This endpoint accepts query parameters in the format ?key=value&key=value 61 | * 62 | * @returns A promise resolving to the lookup data, or undefined on error. 63 | */ 64 | getLookupData = async () => await this._getData('data/lookup/get') 65 | } 66 | -------------------------------------------------------------------------------- /packages/iracing-api/src/api/series.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import { 3 | GetSeriesPastSeasonsParams, 4 | GetSeriesPastSeasonsResponse, 5 | GetSeriesSeasonsParams, 6 | SeriesAssets, 7 | SeriesData, 8 | SeriesSeason, 9 | SeriesStat, 10 | } from '../types' 11 | 12 | /** 13 | * Provides methods for interacting with series-related endpoints. 14 | */ 15 | export class SeriesAPI extends API { 16 | // Series API 17 | /** 18 | * Get assets for all series (logos, images, copy). 19 | * 20 | * Note: Image paths are relative to `https://images-static.iracing.com/`. 21 | * 22 | * @returns A promise resolving to the series assets data, or undefined on error. 23 | */ 24 | getSeriesAssets = async () => 25 | await this._getData('data/series/assets') 26 | /** 27 | * Get basic data for all series. 28 | * 29 | * @returns A promise resolving to an array of series data objects, or undefined on error. 30 | */ 31 | getSeriesData = async () => 32 | await this._getData('data/series/get') 33 | /** 34 | * Get all past seasons for a specific series. 35 | * 36 | * Note: Filter the response list by `official: true` for seasons with standings. 37 | * 38 | * @param {GetSeriesPastSeasonsParams} params - Parameters for the request. 39 | * @param {number} params.seriesId - The ID of the series. 40 | * 41 | * @returns A promise resolving to the past seasons data for the series, or undefined on error. 42 | */ 43 | getSeriesPastSeasons = async (params: GetSeriesPastSeasonsParams) => 44 | await this._getData( 45 | 'data/series/past_seasons', 46 | { 47 | series_id: params.seriesId, 48 | } 49 | ) 50 | /** 51 | * Get the current seasons for all series. 52 | * 53 | * @param {GetSeriesSeasonsParams} [params] - Optional parameters. 54 | * @param {boolean} [params.includeSeries=false] - Include detailed series information within each season object. 55 | * 56 | * @returns A promise resolving to an array of current series season objects, or undefined on error. 57 | */ 58 | getSeriesSeasons = async (params?: GetSeriesSeasonsParams) => 59 | await this._getData('data/series/seasons', { 60 | include_series: params?.includeSeries, 61 | }) 62 | /** 63 | * Get statistical data for all series, including associated seasons. 64 | * 65 | * Note: To get series and seasons for which standings should be available, filter the list by `official: true`. 66 | * 67 | * @returns A promise resolving to an array of series statistics objects, or undefined on error. 68 | */ 69 | getSeriesStats = async () => 70 | await this._getData('data/series/stats_series') 71 | } 72 | -------------------------------------------------------------------------------- /packages/iracing-api/src/types/season.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | 3 | // Params 4 | export const GetSeasonListParamsSchema = z.object({ 5 | seasonYear: z.number(), 6 | seasonQuarter: z.number(), 7 | }) 8 | export type GetSeasonListParams = z.infer 9 | export const GetSeasonRaceGuideParamsSchema = z.object({ 10 | from: z.string().optional(), 11 | includeEndAfterFrom: z.boolean().optional(), 12 | }) 13 | export type GetSeasonRaceGuideParams = z.infer< 14 | typeof GetSeasonRaceGuideParamsSchema 15 | > 16 | export const GetSpectatorSubsessionIdsParamsSchema = z.object({ 17 | eventTypes: z.array(z.number()).optional(), 18 | }) 19 | export type GetSpectatorSubsessionIdsParams = z.infer< 20 | typeof GetSpectatorSubsessionIdsParamsSchema 21 | > 22 | 23 | export const GetSpectatorSubsessionIdsDetailParamsSchema = z.object({ 24 | eventTypes: z.array(z.number()).optional(), 25 | seasonIds: z.array(z.number()).optional(), 26 | }) 27 | export type GetSpectatorSubsessionIdsDetailParams = z.infer< 28 | typeof GetSpectatorSubsessionIdsDetailParamsSchema 29 | > 30 | 31 | // Response 32 | export const SeasonListEntrySchema = z.object({ 33 | seasonId: z.number(), 34 | seriesId: z.number(), 35 | seasonName: z.string(), 36 | seriesName: z.string(), 37 | official: z.boolean(), 38 | seasonYear: z.number(), 39 | seasonQuarter: z.number(), 40 | licenseGroup: z.number(), 41 | fixedSetup: z.boolean(), 42 | driverChanges: z.boolean(), 43 | rookieSeason: z.string().optional(), // Added as optional based on example 44 | }) 45 | export type SeasonListEntry = z.infer 46 | 47 | export const GetSeasonListResponseSchema = z.object({ 48 | seasonQuarter: z.number(), 49 | seasons: z.array(SeasonListEntrySchema), 50 | seasonYear: z.number(), 51 | }) 52 | export type GetSeasonListResponse = z.infer 53 | 54 | export const SeasonRaceGuideSessionSchema = z.object({ 55 | seasonId: z.number(), 56 | startTime: z.string().datetime(), 57 | superSession: z.boolean(), 58 | seriesId: z.number(), 59 | raceWeekNum: z.number(), 60 | endTime: z.string().datetime(), 61 | sessionId: z.number(), 62 | entryCount: z.number(), 63 | }) 64 | export type SeasonRaceGuideSession = z.infer< 65 | typeof SeasonRaceGuideSessionSchema 66 | > 67 | 68 | export const GetSeasonRaceGuideResponseSchema = z.object({ 69 | subscribed: z.boolean(), 70 | sessions: z.array(SeasonRaceGuideSessionSchema), 71 | blockBeginTime: z.string().datetime(), 72 | blockEndTime: z.string().datetime(), 73 | success: z.boolean(), 74 | }) 75 | export type GetSeasonRaceGuideResponse = z.infer< 76 | typeof GetSeasonRaceGuideResponseSchema 77 | > 78 | 79 | export const GetSpectatorSubsessionIdsResponseSchema = z.object({ 80 | eventTypes: z.array(z.number()), 81 | success: z.boolean(), 82 | subsessionIds: z.array(z.number()), 83 | }) 84 | export type GetSpectatorSubsessionIdsResponse = z.infer< 85 | typeof GetSpectatorSubsessionIdsResponseSchema 86 | > 87 | -------------------------------------------------------------------------------- /docs/api/results.md: -------------------------------------------------------------------------------- 1 | # Results API 2 | 3 | All methods in the `Results` API are available through the `results` property of the `iRacingAPI` instance. 4 | 5 | ## Result 6 | 7 | Get the result. 8 | 9 | ```ts 10 | const result = await ir.results.getResult(params); 11 | ``` 12 | 13 | Available parameters: 14 | * `subsessionId: number` - The session ID of the result to get. 15 | * `includeLicenses?: boolean` - Include licenses in the result. 16 | 17 | 18 | https://members-ng.iracing.com/data/results/get 19 | 20 | ## Event Log 21 | 22 | Get the event log. 23 | 24 | ```ts 25 | const eventLog = await ir.results.getResultsEventLog(params); 26 | ``` 27 | 28 | Available parameters: 29 | * `subsessionId: number` - The session ID of the result to get. 30 | * `simsessionNumber?: number` - The sim-session number of the result to get. 31 | * The main event is `0` 32 | * The preceding event is `-1` 33 | * And so on. 34 | 35 | https://members-ng.iracing.com/data/results/event_log 36 | 37 | ## Lap Chart Data 38 | 39 | Get the lap chart data. 40 | 41 | ```ts 42 | const lapChartData = await ir.results.getResultsLapChartData(params); 43 | ``` 44 | 45 | Available parameters: 46 | * `subsessionId: number` - The session ID of the result to get. 47 | * `simsessionNumber?: number` - The sim-session number of the result to get. 48 | * The main event is `0` 49 | * The preceding event is `-1` 50 | * And so on. 51 | 52 | https://members-ng.iracing.com/data/results/lap_chart_data 53 | 54 | ## Lap Data 55 | 56 | Get the lap data. 57 | 58 | ```ts 59 | const lapData = await ir.results.getResultsLapData(params); 60 | ``` 61 | 62 | Available parameters: 63 | * `subsessionId: number` - The session ID of the result to get. 64 | * `simsessionNumber?: number` - The sim-session number of the result to get. 65 | * The main event is `0` 66 | * The preceding event is `-1` 67 | * And so on. 68 | * `customerId?: number` - The customer ID of the result to get. 69 | * Required if the subsession was a single-driver event. 70 | * Optional for team events. 71 | * If omitted for a team event, then the laps driven by all the team's drivers will be included. 72 | 73 | https://members-ng.iracing.com/data/results/lap_data 74 | 75 | ## Hosted Results 76 | 77 | Search hosted results. 78 | 79 | ```ts 80 | const hostedData = await ir.results.searchHostedResults(params); 81 | ``` 82 | 83 | Available parameters: 84 | * TBA 85 | 86 | https://members-ng.iracing.com/data/results/search_hosted 87 | 88 | ## Series Results 89 | 90 | Search series results. 91 | 92 | ```ts 93 | const seriesData = await ir.results.searchSeriesResults(params); 94 | ``` 95 | 96 | Available parameters: 97 | * TBA 98 | 99 | https://members-ng.iracing.com/data/results/search_series 100 | 101 | ## Season Results 102 | 103 | Get season results. 104 | ```ts 105 | const seasonResults = await ir.results.getSeasonResults(params); 106 | ``` 107 | 108 | Available parameters: 109 | * TBA 110 | 111 | https://members-ng.iracing.com/data/results/season_results -------------------------------------------------------------------------------- /packages/iracing-api/src/types/track.ts: -------------------------------------------------------------------------------- 1 | import * as z from 'zod' 2 | 3 | import { TrackTypeEnumSchema, TrackTypeSchema } from './common' 4 | 5 | export const TrackMapLayersSchema = z.object({ 6 | background: z.string(), 7 | inactive: z.string(), 8 | active: z.string(), 9 | pitroad: z.string(), 10 | startFinish: z.string(), 11 | turns: z.string(), 12 | }) 13 | export type TrackMapLayers = z.infer 14 | 15 | export const TrackAssetSchema = z.object({ 16 | coordinates: z.string(), 17 | detailCopy: z.string(), 18 | detailTechspecsCopy: z.union([z.string(), z.null()]), 19 | detailVideo: z.null(), 20 | folder: z.string(), 21 | galleryImages: z.union([z.null(), z.string()]), 22 | galleryPrefix: z.union([z.null(), z.string()]), 23 | largeImage: z.string(), 24 | logo: z.string(), 25 | north: z.union([z.string(), z.null()]), 26 | numSvgImages: z.number(), 27 | smallImage: z.string(), 28 | trackId: z.number(), 29 | trackMap: z.string(), 30 | trackMapLayers: TrackMapLayersSchema, 31 | }) 32 | export type TrackAssetValue = z.infer 33 | 34 | export const TrackAssetsSchema = z.record(TrackAssetSchema) 35 | export type TrackAssets = z.infer 36 | 37 | export const TrackSchema = z.object({ 38 | aiEnabled: z.boolean(), 39 | allowPitlaneCollisions: z.boolean(), 40 | allowRollingStart: z.boolean(), 41 | allowStandingStart: z.boolean(), 42 | awardExempt: z.boolean(), 43 | category: TrackTypeEnumSchema, 44 | categoryId: z.number(), 45 | closes: z.string(), 46 | configName: z.union([z.null(), z.string()]).optional(), 47 | cornersPerLap: z.number(), 48 | created: z.string(), 49 | firstSale: z.string(), 50 | freeWithSubscription: z.boolean(), 51 | fullyLit: z.boolean(), 52 | gridStalls: z.number(), 53 | hasOptPath: z.boolean(), 54 | hasShortParadeLap: z.boolean(), 55 | hasStartZone: z.boolean(), 56 | hasSvgMap: z.boolean(), 57 | isDirt: z.boolean(), 58 | isOval: z.boolean(), 59 | isPsPurchasable: z.boolean(), 60 | lapScoring: z.number(), 61 | latitude: z.number(), 62 | location: z.string(), 63 | longitude: z.number(), 64 | maxCars: z.number(), 65 | nightLighting: z.boolean(), 66 | nominalLapTime: z.number(), 67 | numberPitstalls: z.number(), 68 | opens: z.string(), 69 | packageId: z.number(), 70 | pitRoadSpeedLimit: z.union([z.number(), z.null()]).optional(), 71 | price: z.number(), 72 | priceDisplay: z.union([z.string(), z.null()]).optional(), 73 | priority: z.number(), 74 | purchasable: z.boolean(), 75 | qualifyLaps: z.number(), 76 | restartOnLeft: z.boolean(), 77 | retired: z.boolean(), 78 | searchFilters: z.string(), 79 | siteUrl: z.union([z.null(), z.string()]).optional(), 80 | sku: z.number(), 81 | soloLaps: z.number(), 82 | startOnLeft: z.boolean(), 83 | supportsGripCompound: z.boolean(), 84 | techTrack: z.boolean(), 85 | timeZone: z.string(), 86 | trackConfigLength: z.number(), 87 | trackDirpath: z.string(), 88 | trackId: z.number(), 89 | trackName: z.string(), 90 | trackTypes: z.array(TrackTypeSchema), 91 | banking: z.union([z.null(), z.string()]).optional(), 92 | }) 93 | export type Track = z.infer 94 | -------------------------------------------------------------------------------- /packages/iracing-api/src/api/season.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import { 3 | GetSeasonListParams, 4 | GetSeasonListResponse, 5 | GetSeasonRaceGuideParams, 6 | GetSeasonRaceGuideResponse, 7 | GetSpectatorSubsessionIdsDetailParams, 8 | GetSpectatorSubsessionIdsParams, 9 | GetSpectatorSubsessionIdsResponse, 10 | } from '../types' 11 | 12 | /** 13 | * Provides methods for interacting with season-related endpoints. 14 | */ 15 | export class SeasonAPI extends API { 16 | /** 17 | * Get a list of seasons for a specific year and quarter. 18 | * 19 | * @param {GetSeasonListParams} params - Parameters for the request. 20 | * @param {number} params.seasonYear - The year of the season. 21 | * @param {number} params.seasonQuarter - The quarter of the season (1-4). 22 | * 23 | * @returns A promise resolving to the list of seasons, or undefined on error. 24 | */ 25 | getSeasonList = async (params: GetSeasonListParams) => 26 | await this._getData('data/season/list', { 27 | season_year: params.seasonYear, 28 | season_quarter: params.seasonQuarter, 29 | }) 30 | /** 31 | * Get the race guide, showing upcoming sessions. 32 | * 33 | * @param {GetSeasonRaceGuideParams} [params] - Optional parameters to control the time frame. 34 | * @param {string} [params.from] - ISO-8601 offset format start time. Defaults to current time. Includes sessions up to 3 hours after this time. 35 | * @param {boolean} [params.includeEndAfterFrom=false] - Include sessions starting before `from` but ending after. 36 | * 37 | * @returns A promise resolving to the race guide data, or undefined on error. 38 | */ 39 | getSeasonRaceGuide = async (params?: GetSeasonRaceGuideParams) => 40 | await this._getData( 41 | 'data/season/race_guide', 42 | { 43 | from: params?.from, 44 | include_end_after_from: params?.includeEndAfterFrom, 45 | } 46 | ) 47 | /** 48 | * Get a list of subsession IDs that are available for spectating. 49 | * 50 | * @param {GetSpectatorSubsessionIdsParams} [params] - Optional parameters to filter by event type. 51 | * @param {number[]} [params.eventTypes] - Array of event type IDs to include. Defaults to all. 52 | * 53 | * @returns A promise resolving to the list of spectator subsession IDs, or undefined on error. 54 | */ 55 | getSpectatorSubsessionIds = async ( 56 | params?: GetSpectatorSubsessionIdsParams 57 | ) => 58 | await this._getData( 59 | 'data/season/spectator_subsession_ids', 60 | { 61 | event_types: params?.eventTypes, 62 | } 63 | ) 64 | /** 65 | * Get detailed information about subsession IDs that are available for spectating. 66 | * 67 | * @param {GetSpectatorSubsessionIdsDetailParams} [params] - Optional parameters to filter by event type and season. 68 | * @param {number[]} [params.eventTypes] - Array of event type IDs to include. Defaults to all. 69 | * @param {number[]} [params.seasonIds] - Array of season IDs to include. Defaults to all. 70 | * 71 | * @returns A promise resolving to the detailed list of spectator subsession IDs, or undefined on error. 72 | */ 73 | getSpectatorSubsessionIdsDetail = async ( 74 | params?: GetSpectatorSubsessionIdsDetailParams 75 | ) => 76 | await this._getData('data/season/spectator_subsessionids_detail', { 77 | event_types: params?.eventTypes, 78 | season_ids: params?.seasonIds, 79 | }) 80 | } 81 | -------------------------------------------------------------------------------- /packages/iracing-api/src/types/car.ts: -------------------------------------------------------------------------------- 1 | import * as z from 'zod' 2 | 3 | import { CarTypeSchema, CategorySchema } from './common' 4 | 5 | export const PriceDisplaySchema = z.string() 6 | export type PriceDisplay = z.infer 7 | 8 | export const PaintRuleSchema = z.object({ 9 | allowNumberColorChanges: z.union([z.boolean(), z.null()]).optional(), 10 | allowNumberFontChanges: z.union([z.boolean(), z.null()]).optional(), 11 | color1: z.string(), 12 | color2: z.string(), 13 | color3: z.string(), 14 | numberColor1: z.union([z.string(), z.null()]).optional(), 15 | numberColor2: z.union([z.string(), z.null()]).optional(), 16 | numberColor3: z.union([z.string(), z.null()]).optional(), 17 | numberFont: z.union([z.null(), z.string()]).optional(), 18 | paintCarAvailable: z.boolean(), 19 | paintWheelAvailable: z.union([z.boolean(), z.null()]).optional(), 20 | rimType: z.union([z.string(), z.null()]).optional(), 21 | rimTypeAvailable: z.union([z.boolean(), z.null()]).optional(), 22 | rulesExplanation: z.string(), 23 | sponsor1: z.string(), 24 | sponsor1Available: z.boolean(), 25 | sponsor2: z.string(), 26 | sponsor2Available: z.boolean(), 27 | wheelColor: z.union([z.string(), z.null()]).optional(), 28 | }) 29 | export type PaintRule = z.infer 30 | 31 | export const PaintRulesSchema = z.intersection( 32 | z.object({ 33 | restrictCustomPaint: z.union([z.boolean(), z.null()]).optional(), 34 | }), 35 | z.record(z.string(), PaintRuleSchema) 36 | ) 37 | export type PaintRules = z.infer 38 | 39 | export const CarSchema = z.object({ 40 | aiEnabled: z.boolean(), 41 | allowNumberColors: z.boolean(), 42 | allowNumberFont: z.boolean(), 43 | allowSponsor1: z.boolean(), 44 | allowSponsor2: z.boolean(), 45 | allowWheelColor: z.boolean(), 46 | awardExempt: z.boolean(), 47 | carDirpath: z.string(), 48 | carId: z.number(), 49 | carMake: z.union([z.null(), z.string()]).optional(), 50 | carModel: z.union([z.null(), z.string()]).optional(), 51 | carName: z.string(), 52 | carNameAbbreviated: z.string(), 53 | carTypes: z.array(CarTypeSchema), 54 | carWeight: z.number(), 55 | categories: z.array(CategorySchema), 56 | created: z.string(), 57 | firstSale: z.string(), 58 | forumUrl: z.union([z.null(), z.string()]).optional(), 59 | freeWithSubscription: z.boolean(), 60 | hasHeadlights: z.boolean(), 61 | hasMultipleDryTireTypes: z.boolean(), 62 | hasRainCapableTireTypes: z.boolean(), 63 | hp: z.number(), 64 | isPsPurchasable: z.boolean(), 65 | maxPowerAdjustPct: z.number(), 66 | maxWeightPenaltyKg: z.number(), 67 | minPowerAdjustPct: z.number(), 68 | packageId: z.number(), 69 | paintRules: z.union([PaintRulesSchema, z.null()]).optional(), 70 | patterns: z.number(), 71 | price: z.number(), 72 | priceDisplay: z.union([PriceDisplaySchema, z.null()]).optional(), 73 | rainEnabled: z.boolean(), 74 | retired: z.boolean(), 75 | searchFilters: z.string(), 76 | siteUrl: z.union([z.null(), z.string()]).optional(), 77 | sku: z.number(), 78 | }) 79 | export type Car = z.infer 80 | 81 | export const CarAssetSchema = z.object({ 82 | carId: z.number(), 83 | carRules: z.array(z.any()).optional(), // Type further if structure is known 84 | detailCopy: z.string().nullable().optional(), 85 | detailScreenShotImages: z.string().nullable().optional(), 86 | detailTechspecsCopy: z.string().nullable().optional(), 87 | folder: z.string().nullable().optional(), 88 | galleryImages: z.string().nullable().optional(), 89 | galleryPrefix: z.string().nullable().optional(), 90 | groupImage: z.string().nullable().optional(), 91 | groupName: z.string().nullable().optional(), 92 | largeImage: z.string().nullable().optional(), 93 | logo: z.string().nullable().optional(), 94 | smallImage: z.string().nullable().optional(), 95 | sponsorLogo: z.string().nullable().optional(), 96 | templatePath: z.string().nullable().optional(), 97 | }) 98 | export type CarAsset = z.infer 99 | 100 | export const CarAssetsResponseSchema = z.record(z.string(), CarAssetSchema) 101 | export type CarAssetsResponse = z.infer 102 | -------------------------------------------------------------------------------- /packages/iracing-api/src/index.ts: -------------------------------------------------------------------------------- 1 | import { API_URL, DEFAULT_OPTIONS } from './consts.js' 2 | import { encryptPassword } from './helpers.js' 3 | 4 | import makeFetchCookie from 'fetch-cookie' 5 | import { FetchCookie, Options } from './types/index.js' 6 | import { CarAPI } from './api/car.js' 7 | import { CarClassAPI } from './api/car-class.js' 8 | import { ConstantsAPI } from './api/constants.js' 9 | import { HostedAPI } from './api/hosted.js' 10 | import { LeagueAPI } from './api/league.js' 11 | import { LookupAPI } from './api/lookup.js' 12 | import { MemberAPI } from './api/member.js' 13 | import { ResultsAPI } from './api/results.js' 14 | import { SeasonAPI } from './api/season.js' 15 | import { SeriesAPI } from './api/series.js' 16 | import { StatsAPI } from './api/stats.js' 17 | import { TeamAPI } from './api/team.js' 18 | import { TimeAttackAPI } from './api/time-attack.js' 19 | import { TrackAPI } from './api/track.js' 20 | import { createLogger, logger } from './logger.js' 21 | 22 | export * from './consts.js' 23 | export * from './helpers.js' 24 | export * from './types/index.js' 25 | 26 | /** 27 | * Main client for interacting with the iRacing Data API. 28 | */ 29 | export default class IracingAPI { 30 | // 31 | fetchCookie: FetchCookie 32 | options: Options 33 | 34 | // API 35 | car: CarAPI 36 | carClass: CarClassAPI 37 | constants: ConstantsAPI 38 | hosted: HostedAPI 39 | league: LeagueAPI 40 | lookup: LookupAPI 41 | member: MemberAPI 42 | results: ResultsAPI 43 | season: SeasonAPI 44 | series: SeriesAPI 45 | stats: StatsAPI 46 | team: TeamAPI 47 | timeAttack: TimeAttackAPI 48 | track: TrackAPI 49 | 50 | /** 51 | * Creates an instance of the IracingAPI client. 52 | * 53 | * @param {Options} [options] - Configuration options for the client. 54 | * @param {boolean} [options.logger=false] - Enable logging of requests and responses. 55 | * @param {boolean} [options.manageRateLimit=false] - Automatically handle rate limiting by delaying requests. 56 | * @param {number} [options.rateLimitPadding=5000] - Milliseconds to pad the rate limit reset time when manageRateLimit is true. 57 | */ 58 | constructor(options?: Options) { 59 | this.fetchCookie = makeFetchCookie(fetch) 60 | this.options = options ?? DEFAULT_OPTIONS 61 | 62 | this.car = new CarAPI(this.fetchCookie, this.options) 63 | this.carClass = new CarClassAPI(this.fetchCookie, this.options) 64 | this.constants = new ConstantsAPI(this.fetchCookie, this.options) 65 | this.hosted = new HostedAPI(this.fetchCookie, this.options) 66 | this.league = new LeagueAPI(this.fetchCookie, this.options) 67 | this.lookup = new LookupAPI(this.fetchCookie, this.options) 68 | this.member = new MemberAPI(this.fetchCookie, this.options) 69 | this.results = new ResultsAPI(this.fetchCookie, this.options) 70 | this.season = new SeasonAPI(this.fetchCookie, this.options) 71 | this.series = new SeriesAPI(this.fetchCookie, this.options) 72 | this.stats = new StatsAPI(this.fetchCookie, this.options) 73 | this.team = new TeamAPI(this.fetchCookie, this.options) 74 | this.timeAttack = new TimeAttackAPI(this.fetchCookie, this.options) 75 | this.track = new TrackAPI(this.fetchCookie, this.options) 76 | 77 | createLogger(this.options) 78 | } 79 | 80 | /** 81 | * Authenticates the user with the iRacing API using email and password. 82 | * Stores the necessary authentication cookies for subsequent requests. 83 | * 84 | * @param email - iRacing account email address. 85 | * @param password - iRacing account password. 86 | * @returns A promise that resolves with the authentication response JSON on success, 87 | * or an object containing an error message on failure. 88 | */ 89 | login = async (email: string, password: string) => { 90 | const hashPassword = encryptPassword(email, password) 91 | 92 | const response = await this.fetchCookie(`${API_URL}auth`, { 93 | body: JSON.stringify({ email, password: hashPassword }), 94 | cache: 'no-cache', 95 | credentials: 'include', 96 | headers: { 97 | 'Content-Type': 'application/json', 98 | }, 99 | method: 'POST', 100 | }) 101 | 102 | if (response.status !== 200) { 103 | logger('Login failed...') 104 | return { 105 | error: response.statusText ?? 'Failed to login to iracing-api', 106 | } 107 | } 108 | 109 | logger('Login successful...') 110 | 111 | return await response.json() 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /packages/iracing-api/src/api/api.ts: -------------------------------------------------------------------------------- 1 | import { API_URL } from '../consts' 2 | import { logger } from '../logger' 3 | import { RateLimiter } from '../rate-limiter' 4 | import { type FetchCookie, type Options } from '../types' 5 | 6 | import humps from 'humps' 7 | const { camelizeKeys } = humps 8 | 9 | /** 10 | * Base class for iRacing API endpoints. 11 | * Provides common functionality for making requests, handling rate limits, and processing responses. 12 | * @internal 13 | */ 14 | export class API { 15 | fetchCookie: FetchCookie 16 | options: Options 17 | rateLimiter: RateLimiter 18 | 19 | /** 20 | * Initializes the base API class. 21 | * @param fetchCookie - The fetch instance with cookie support. 22 | * @param options - Client configuration options. 23 | */ 24 | constructor(fetchCookie: FetchCookie, options: Options) { 25 | this.fetchCookie = fetchCookie 26 | this.options = options 27 | this.rateLimiter = new RateLimiter(options) 28 | } 29 | 30 | /** 31 | * Internal method to fetch data from a specified API endpoint. 32 | * Handles rate limiting, URL construction, and optionally fetching data from a returned link. 33 | * 34 | * @template Data - The expected type of the primary data payload. 35 | * @template Parameters - The type of the query parameters object. 36 | * @param endpoint - The specific API endpoint path (e.g., 'data/car/get'). 37 | * @param [params] - Optional query parameters for the request. 38 | * @param [getLinkData=true] - If true and the response contains a 'link', fetch data from that link. 39 | * @returns A promise resolving to the fetched data (type Data) or undefined if an error occurs or no data is found. 40 | * @internal 41 | */ 42 | _getData = async , Parameters = void>( 43 | endpoint: string, 44 | params?: Parameters | Record, 45 | getLinkData: boolean = true 46 | ): Promise => { 47 | try { 48 | const canProceed = this.rateLimiter.checkRateLimit() 49 | 50 | if (!canProceed) { 51 | await this.rateLimiter.waitForReset() 52 | } 53 | 54 | const parsedParams = `[${Object.entries(params ?? {}) 55 | .map(([key, value]) => `${key}=${value}`) 56 | .join(', ')}]` 57 | logger(`Getting data from '${endpoint}'`, parsedParams) 58 | 59 | const url = this._getUrl(endpoint, params) 60 | const response = await this.fetchCookie(url, { 61 | cache: 'no-cache', 62 | credentials: 'include', 63 | }) 64 | this.rateLimiter.updateRateLimit(response) 65 | 66 | const data = await response.json() 67 | 68 | if (data?.link && getLinkData) { 69 | return await this._getLinkData(data?.link) 70 | } 71 | 72 | return data as Data | undefined 73 | } catch (error) { 74 | logger(`Error getting data from '${endpoint}'`) 75 | return undefined 76 | } 77 | } 78 | 79 | /** 80 | * Internal method to fetch data from a secondary URL (often an S3 link) provided in an initial API response. 81 | * Converts keys in the fetched JSON data to camelCase. 82 | * 83 | * @template Data - The expected type of the data payload from the link. 84 | * @param link - The URL to fetch data from. 85 | * @returns A promise resolving to the fetched and camelCased data (type Data) or undefined if the link is invalid or fetching fails. 86 | * @internal 87 | */ 88 | _getLinkData = async ( 89 | link: string | undefined 90 | ): Promise => { 91 | if (!link) return undefined 92 | 93 | const response = await fetch(link) 94 | const data = await response.json() 95 | 96 | if (!data) return undefined 97 | 98 | return camelizeKeys(data) as Data 99 | } 100 | 101 | /** 102 | * Internal method to construct the full API URL including the base path and query parameters. 103 | * 104 | * @template Parameters - The type of the query parameters object. 105 | * @param endpoint - The specific API endpoint path. 106 | * @param [params] - Optional query parameters. 107 | * @returns The fully constructed URL string. 108 | * @internal 109 | */ 110 | _getUrl = >( 111 | endpoint: string, 112 | params?: Parameters 113 | ) => { 114 | // Filter out empty values 115 | const searchParams = 116 | params && 117 | new URLSearchParams(JSON.parse(JSON.stringify(params))).toString() 118 | 119 | return `${API_URL}${endpoint}${searchParams ? `?${searchParams}` : ''}` 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/style.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Customize default theme styling by overriding CSS variables: 3 | * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css 4 | */ 5 | 6 | /** 7 | * Colors 8 | * 9 | * Each colors have exact same color scale system with 3 levels of solid 10 | * colors with different brightness, and 1 soft color. 11 | * 12 | * - `XXX-1`: The most solid color used mainly for colored text. It must 13 | * satisfy the contrast ratio against when used on top of `XXX-soft`. 14 | * 15 | * - `XXX-2`: The color used mainly for hover state of the button. 16 | * 17 | * - `XXX-3`: The color for solid background, such as bg color of the button. 18 | * It must satisfy the contrast ratio with pure white (#ffffff) text on 19 | * top of it. 20 | * 21 | * - `XXX-soft`: The color used for subtle background such as custom container 22 | * or badges. It must satisfy the contrast ratio when putting `XXX-1` colors 23 | * on top of it. 24 | * 25 | * The soft color must be semi transparent alpha channel. This is crucial 26 | * because it allows adding multiple "soft" colors on top of each other 27 | * to create a accent, such as when having inline code block inside 28 | * custom containers. 29 | * 30 | * - `default`: The color used purely for subtle indication without any 31 | * special meanings attched to it such as bg color for menu hover state. 32 | * 33 | * - `brand`: Used for primary brand colors, such as link text, button with 34 | * brand theme, etc. 35 | * 36 | * - `tip`: Used to indicate useful information. The default theme uses the 37 | * brand color for this by default. 38 | * 39 | * - `warning`: Used to indicate warning to the users. Used in custom 40 | * container, badges, etc. 41 | * 42 | * - `danger`: Used to show error, or dangerous message to the users. Used 43 | * in custom container, badges, etc. 44 | * -------------------------------------------------------------------------- */ 45 | 46 | :root { 47 | --vp-c-default-1: var(--vp-c-gray-1); 48 | --vp-c-default-2: var(--vp-c-gray-2); 49 | --vp-c-default-3: var(--vp-c-gray-3); 50 | --vp-c-default-soft: var(--vp-c-gray-soft); 51 | 52 | --vp-c-brand-1: var(--vp-c-indigo-1); 53 | --vp-c-brand-2: var(--vp-c-indigo-2); 54 | --vp-c-brand-3: var(--vp-c-indigo-3); 55 | --vp-c-brand-soft: var(--vp-c-indigo-soft); 56 | 57 | --vp-c-tip-1: var(--vp-c-brand-1); 58 | --vp-c-tip-2: var(--vp-c-brand-2); 59 | --vp-c-tip-3: var(--vp-c-brand-3); 60 | --vp-c-tip-soft: var(--vp-c-brand-soft); 61 | 62 | --vp-c-warning-1: var(--vp-c-yellow-1); 63 | --vp-c-warning-2: var(--vp-c-yellow-2); 64 | --vp-c-warning-3: var(--vp-c-yellow-3); 65 | --vp-c-warning-soft: var(--vp-c-yellow-soft); 66 | 67 | --vp-c-danger-1: var(--vp-c-red-1); 68 | --vp-c-danger-2: var(--vp-c-red-2); 69 | --vp-c-danger-3: var(--vp-c-red-3); 70 | --vp-c-danger-soft: var(--vp-c-red-soft); 71 | } 72 | 73 | /** 74 | * Component: Button 75 | * -------------------------------------------------------------------------- */ 76 | 77 | :root { 78 | --vp-button-brand-border: transparent; 79 | --vp-button-brand-text: var(--vp-c-white); 80 | --vp-button-brand-bg: var(--vp-c-brand-3); 81 | --vp-button-brand-hover-border: transparent; 82 | --vp-button-brand-hover-text: var(--vp-c-white); 83 | --vp-button-brand-hover-bg: var(--vp-c-brand-2); 84 | --vp-button-brand-active-border: transparent; 85 | --vp-button-brand-active-text: var(--vp-c-white); 86 | --vp-button-brand-active-bg: var(--vp-c-brand-1); 87 | } 88 | 89 | /** 90 | * Component: Home 91 | * -------------------------------------------------------------------------- */ 92 | 93 | :root { 94 | --vp-home-hero-name-color: transparent; 95 | --vp-home-hero-name-background: -webkit-linear-gradient( 96 | 120deg, 97 | #3e7ce8 30%, 98 | #41d1ff 99 | ); 100 | 101 | --vp-home-hero-image-background-image: linear-gradient( 102 | -45deg, 103 | #bd34fe 50%, 104 | #47caff 50% 105 | ); 106 | --vp-home-hero-image-filter: blur(44px); 107 | } 108 | 109 | @media (min-width: 640px) { 110 | :root { 111 | --vp-home-hero-image-filter: blur(56px); 112 | } 113 | } 114 | 115 | @media (min-width: 960px) { 116 | :root { 117 | --vp-home-hero-image-filter: blur(68px); 118 | } 119 | } 120 | 121 | /** 122 | * Component: Custom Block 123 | * -------------------------------------------------------------------------- */ 124 | 125 | :root { 126 | --vp-custom-block-tip-border: transparent; 127 | --vp-custom-block-tip-text: var(--vp-c-text-1); 128 | --vp-custom-block-tip-bg: var(--vp-c-brand-soft); 129 | --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft); 130 | } 131 | 132 | /** 133 | * Component: Algolia 134 | * -------------------------------------------------------------------------- */ 135 | 136 | .DocSearch { 137 | --docsearch-primary-color: var(--vp-c-brand-1) !important; 138 | } 139 | 140 | -------------------------------------------------------------------------------- /packages/iracing-api/src/api/member.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import { 3 | GetMemberAwardsParams, 4 | GetMemberAwardsResponse, 5 | GetMemberChartDataParams, 6 | GetMemberChartDataResponse, 7 | GetMemberDataParams, 8 | GetMemberDataResponse, 9 | GetMemberProfileParams, 10 | GetMemberProfileResponse, 11 | MemberInfo, 12 | MemberParticipationCredit, 13 | GetMemberAwardInstancesParams, 14 | } from '../types' 15 | 16 | /** 17 | * Provides methods for interacting with member-related endpoints (awards, stats, profile, etc.). 18 | */ 19 | export class MemberAPI extends API { 20 | /** 21 | * Get the awards earned by a member. 22 | * 23 | * @param {GetMemberAwardsParams} [params] - Optional parameters to specify the member. 24 | * @param {number} [params.customerId] - Customer ID. Defaults to the authenticated member. 25 | * 26 | * @returns A promise resolving to the member awards data, or undefined on error. 27 | */ 28 | getMemberAwards = async ( 29 | params?: GetMemberAwardsParams 30 | ): Promise => 31 | await this._getData('data/member/awards', { 32 | cust_id: params?.customerId, 33 | }) 34 | /** 35 | * Get chart data (iRating, TT Rating, License/SR) for a member in a specific category. 36 | * 37 | * @param {GetMemberChartDataParams} params - Parameters for the request. 38 | * @param {number} [params.customerId] - Customer ID. Defaults to the authenticated member. 39 | * @param {number} params.categoryId - Category ID: 1=Oval, 2=Road, 3=Dirt Oval, 4=Dirt Road. 40 | * @param {number} params.chartType - Chart type: 1=iRating, 2=TT Rating, 3=License/SR. 41 | * 42 | * @returns A promise resolving to the member chart data, or undefined on error. 43 | */ 44 | getMemberChartData = async ( 45 | params: GetMemberChartDataParams 46 | ): Promise => 47 | await this._getData( 48 | 'data/member/chart_data', 49 | { 50 | cust_id: params.customerId, 51 | category_id: params.categoryId, 52 | chart_type: params.chartType, 53 | } 54 | ) 55 | /** 56 | * Get basic data for one or more members. 57 | * 58 | * @param {GetMemberDataParams} params - Parameters for the request. 59 | * @param {string[]} params.customerIds - An array of customer IDs (as strings) to retrieve data for. 60 | * @param {boolean} [params.includeLicenses=false] - Include license information in the response. 61 | * 62 | * @returns A promise resolving to the member data, or undefined on error. 63 | */ 64 | getMemberData = async ( 65 | params: GetMemberDataParams 66 | ): Promise => 67 | await this._getData('data/member/get', { 68 | cust_ids: params.customerIds.join(','), 69 | include_licenses: params.includeLicenses, 70 | }) 71 | /** 72 | * Get detailed information about the **authenticated** member. 73 | * 74 | * @returns A promise resolving to the authenticated member's info, or undefined on error. 75 | */ 76 | getMemberInfo = async (): Promise => 77 | await this._getData('data/member/info') 78 | /** 79 | * Get the participation credits earned by the **authenticated** member. 80 | * 81 | * @returns A promise resolving to an array of participation credit objects, or undefined on error. 82 | */ 83 | getMemberParticipationCredits = async () => 84 | await this._getData( 85 | 'data/member/participation_credits' 86 | ) 87 | /** 88 | * Get profile data for a member, including recent awards, activity, licenses, etc. 89 | * 90 | * @param {GetMemberProfileParams} [params] - Optional parameters to specify the member. 91 | * @param {number} [params.customerId] - Customer ID. Defaults to the authenticated member. 92 | * 93 | * @returns A promise resolving to the member profile data, or undefined on error. 94 | */ 95 | getMemberProfile = async ( 96 | params?: GetMemberProfileParams 97 | ): Promise => 98 | await this._getData('data/member/profile', { 99 | cust_id: params?.customerId, 100 | }) 101 | /** 102 | * Get specific award instances for a member. 103 | * 104 | * @param {GetMemberAwardInstancesParams} params - Parameters for the request. 105 | * @param {number} params.awardId - The ID of the award to get instances for. 106 | * @param {number} [params.customerId] - The customer ID to get award instances for. Defaults to the authenticated member. 107 | * 108 | * @returns A promise resolving to the member's award instances, or undefined on error. 109 | */ 110 | getMemberAwardInstances = async (params: GetMemberAwardInstancesParams) => 111 | await this._getData('data/member/award_instances', { 112 | award_id: params.awardId, 113 | cust_id: params.customerId, 114 | }) 115 | } 116 | -------------------------------------------------------------------------------- /docs/api/league.md: -------------------------------------------------------------------------------- 1 | # League API 2 | 3 | All methods in the `League` API are available through the `league` property of the `iRacingAPI` instance. 4 | 5 | ## League Sessions 6 | 7 | Get the league sessions. 8 | 9 | ```ts 10 | const leagueSessions = await ir.league.getCustLeagueSessions(params); 11 | ``` 12 | 13 | Available parameters: 14 | * `mine?: boolean` 15 | * If `true`, return only sessions created by this user. 16 | * `packageId?: number` - The package id to filter the sessions by. 17 | * If set, return only sessions using this car or track package ID. 18 | 19 | https://members-ng.iracing.com/data/league/cust_league_sessions 20 | 21 | ## Directory 22 | 23 | Get the league directory. 24 | 25 | ```ts 26 | const leagueDirectory = await ir.league.getLeagueDirectory(params); 27 | ``` 28 | 29 | Available parameters: 30 | * `search?: string` - The search string to filter the leagues by. 31 | * Will search against league name, description, owner and league ID. 32 | * `tag?: string` - The tag to filter the leagues by. 33 | * One or more tags, comma-separated. 34 | * `restrictToMember?: boolean` 35 | * If `true`, include only leagues for which customer is a member. 36 | * `restrictToRecruiting?: boolean` 37 | * If `true`, include only leagues that are recruiting. 38 | * `restrictToFriends?: boolean` 39 | * If `true`, include only leagues owned by a friend. 40 | * `restrictToWatched?: boolean` 41 | * If `true`, include only leagues owned by a watched member. 42 | * `minimumRosterCount?: number` 43 | * If set, include leagues with at least this number of members. 44 | * `maximumRosterCount?: number` 45 | * If set, include leagues with at most this number of members. 46 | * `lowerbound?: number` 47 | * First row of results to return. 48 | * Defaults to `1`. 49 | * `upperbound?: number` 50 | * Last row of results to return. 51 | * Defaults to `lowerbound + 39`. 52 | * `sort?: string` 53 | * One of `relevance`, `leaguename`, `displayname`, `rostercount`. 54 | * `displayname` is owner's name. 55 | * Defaults to relevance. 56 | * `order?: string` 57 | * One of `asc`, `desc`. 58 | * Defaults to `asc`. 59 | 60 | https://members-ng.iracing.com/data/league/directory 61 | 62 | ## League Data 63 | 64 | Get the league data. 65 | 66 | ```ts 67 | const leagueData = await ir.league.getLeagueData(params); 68 | ``` 69 | 70 | Available parameters: 71 | * `leagueId: number` - The league ID to get the data for. 72 | * `includeLicenses?: boolean` - Include licenses in the response. 73 | * For faster responses, only request when necessary. 74 | 75 | https://members-ng.iracing.com/data/league/get 76 | 77 | ## Points Systems 78 | 79 | Get the league points systems. 80 | 81 | ```ts 82 | const pointsSystem = await ir.league.getLeaguePointsSystem(params); 83 | ``` 84 | 85 | Available parameters: 86 | * `leagueId: number` - The league ID to get the points system for. 87 | * `seasonId?: number` - The season ID to get the points system for. 88 | * If included and the season is using custom points (`pointsSystemId: 2`) then the custom points option is included in the returned list. 89 | * Otherwise the custom points option is not returned. 90 | 91 | https://members-ng.iracing.com/data/league/get_points_systems 92 | 93 | ## Membership 94 | 95 | Get the league membership. 96 | 97 | ```ts 98 | const leagueMembership = await ir.league.getLeagueMembership(params); 99 | ``` 100 | 101 | Available parameters: 102 | * `customerId?: number` - The customer ID to get the membership for. 103 | * If different from the authenticated member, the following restrictions apply: 104 | * Caller cannot be on requested customer's blocklist or an empty list will result; 105 | * Requested customer cannot have their online activity preference set to hidden or an empty list will result; 106 | * Only leagues for which the requested customer is an admin and the league roster is not private are returned. 107 | * `includeLeague?: boolean` - Include the league in the response. 108 | 109 | https://members-ng.iracing.com/data/league/membership 110 | 111 | ## Seasons 112 | 113 | Get the league seasons. 114 | 115 | ```ts 116 | const leagueSeasons = await ir.league.getLeagueSeasons(params); 117 | ``` 118 | 119 | Available parameters: 120 | * `leagueId: number` - The league ID to get the seasons for. 121 | * `retired?: boolean` - Include retired seasons. 122 | * If `true`, include seasons which are no longer active. 123 | 124 | https://members-ng.iracing.com/data/league/seasons 125 | 126 | ## Season Standings 127 | 128 | Get the league season standings. 129 | 130 | ```ts 131 | const seasonStandings = await ir.league.getLeagueSeasonStandings(params); 132 | ``` 133 | 134 | Available parameters: 135 | * `leagueId: number` - The league ID to get the season standings for. 136 | * `seasonId: number` - The season ID to get the season standings for. 137 | * `carClassId?: number` - The car class ID to filter the standings by. 138 | * `carId?: number` - The car ID to filter the standings by. 139 | * If `carClassId` is included, then the standings are for the car class. 140 | * Otherwise, they are for the car across car classes. 141 | 142 | https://members-ng.iracing.com/data/league/season_standings 143 | 144 | ## Season Sessions 145 | 146 | Get the league season sessions. 147 | 148 | ```ts 149 | const seasonSessions = await ir.league.getLeagueSeasonSessions(params); 150 | ``` 151 | 152 | Available parameters: 153 | * `leagueId: number` - The league ID to get the season sessions for. 154 | * `seasonId: number` - The season ID to get the season sessions for. 155 | * `resultsOnly?: boolean` 156 | * If `true`, include only sessions for which results are available. 157 | 158 | https://members-ng.iracing.com/data/league/season_sessions -------------------------------------------------------------------------------- /packages/iracing-api/src/types/hosted.ts: -------------------------------------------------------------------------------- 1 | import * as z from 'zod' 2 | 3 | import { 4 | CarTypeSchema, 5 | CategorySchema, 6 | EligSchema, 7 | EventTypeSchema, 8 | FarmSchema, 9 | HostSchema, 10 | LicenseGroupTypeSchema, 11 | SessionTypeSchema, 12 | TrackStateSchema, 13 | TrackTypeEnumSchema, 14 | WeatherSchema, 15 | } from './common' 16 | 17 | export const TrackTypeElementSchema = z.object({ 18 | trackType: TrackTypeEnumSchema, 19 | }) 20 | export type TrackTypeElement = z.infer 21 | 22 | export const HostedTrackSchema = z.object({ 23 | configName: z.union([z.null(), z.string()]).optional(), 24 | trackId: z.number(), 25 | trackName: z.string(), 26 | }) 27 | export type HostedTrack = z.infer 28 | 29 | export const HostedCarSchema = z.object({ 30 | carClassId: z.number(), 31 | carClassName: z.string(), 32 | carId: z.number(), 33 | carName: z.string(), 34 | maxDryTireSets: z.number(), 35 | maxPctFuelFill: z.number(), 36 | packageId: z.number(), 37 | powerAdjustPct: z.number(), 38 | qualSetupFilename: z.union([z.null(), z.string()]).optional(), 39 | qualSetupId: z.union([z.number(), z.null()]).optional(), 40 | raceSetupFilename: z.union([z.null(), z.string()]).optional(), 41 | raceSetupId: z.union([z.number(), z.null()]).optional(), 42 | weightPenaltyKg: z.number(), 43 | }) 44 | export type HostedCar = z.infer 45 | 46 | export const HostedSessionSchema = z.object({ 47 | admins: z.array(HostSchema), 48 | aiAvoidPlayers: z.boolean(), 49 | aiMaxSkill: z.union([z.number(), z.null()]).optional(), 50 | aiMinSkill: z.union([z.number(), z.null()]).optional(), 51 | aiRosterName: z.union([z.null(), z.string()]).optional(), 52 | allowedClubs: z.array(z.any()), 53 | allowedLeagues: z.array(z.any()), 54 | allowedTeams: z.array(z.any()), 55 | altAssetId: z.union([z.number(), z.null()]).optional(), 56 | carTypes: z.array(CarTypeSchema), 57 | cars: z.array(HostedCarSchema), 58 | carsLeft: z.number(), 59 | category: CategorySchema, 60 | categoryId: z.number(), 61 | consecCautionsSingleFile: z.boolean(), 62 | countByCarClassId: z.record(z.string(), z.number()), 63 | countByCarId: z.record(z.string(), z.number()), 64 | damageModel: z.number(), 65 | disallowVirtualMirror: z.boolean(), 66 | doNotCountCautionLaps: z.boolean(), 67 | doNotPaintCars: z.boolean(), 68 | driverChangeRule: z.number(), 69 | driverChanges: z.boolean(), 70 | elig: EligSchema, 71 | enablePitlaneCollisions: z.boolean(), 72 | entryCount: z.number(), 73 | eventTypes: z.array(EventTypeSchema), 74 | farm: FarmSchema, 75 | fixedSetup: z.boolean(), 76 | fullCourseCautions: z.boolean(), 77 | greenWhiteCheckeredLimit: z.number(), 78 | hardcoreLevel: z.number(), 79 | host: HostSchema, 80 | incidentLimit: z.number(), 81 | incidentWarnMode: z.number(), 82 | incidentWarnParam1: z.number(), 83 | incidentWarnParam2: z.number(), 84 | launchAt: z.string(), 85 | leagueId: z.number(), 86 | leagueSeasonId: z.number(), 87 | licenseGroupTypes: z.array(LicenseGroupTypeSchema), 88 | loneQualify: z.boolean(), 89 | luckyDog: z.boolean(), 90 | maxAiDrivers: z.number(), 91 | maxDrivers: z.number(), 92 | maxIr: z.number(), 93 | maxLicenseLevel: z.number(), 94 | maxTeamDrivers: z.number(), 95 | minIr: z.number(), 96 | minLicenseLevel: z.number(), 97 | minTeamDrivers: z.number(), 98 | multiclassType: z.number(), 99 | mustUseDiffTireTypesInRace: z.boolean(), 100 | noLapperWaveArounds: z.boolean(), 101 | numFastTows: z.number(), 102 | numOptLaps: z.number(), 103 | openRegExpires: z.string(), 104 | orderId: z.number(), 105 | paceCarClassId: z.union([z.number(), z.null()]), 106 | paceCarId: z.union([z.number(), z.null()]), 107 | passwordProtected: z.boolean(), 108 | pitsInUse: z.number(), 109 | practiceLength: z.number(), 110 | privateSessionId: z.number(), 111 | qualifierMustStartRace: z.boolean(), 112 | qualifyLaps: z.number(), 113 | qualifyLength: z.number(), 114 | raceLaps: z.number(), 115 | raceLength: z.number(), 116 | registeredTeams: z.union([z.array(z.number()), z.null()]).optional(), 117 | restarts: z.number(), 118 | restrictResults: z.boolean(), 119 | restrictViewing: z.boolean(), 120 | rollingStarts: z.boolean(), 121 | sessionDesc: z.union([z.null(), z.string()]).optional(), 122 | sessionFull: z.boolean(), 123 | sessionId: z.number(), 124 | sessionName: z.string(), 125 | sessionType: z.number(), 126 | sessionTypes: z.array(SessionTypeSchema), 127 | shortParadeLap: z.boolean(), 128 | startOnQualTire: z.boolean(), 129 | startZone: z.boolean(), 130 | status: z.number(), 131 | subsessionId: z.number(), 132 | teamEntryCount: z.number(), 133 | telemetryForceToDisk: z.number(), 134 | telemetryRestriction: z.number(), 135 | timeLimit: z.number(), 136 | track: HostedTrackSchema, 137 | trackState: TrackStateSchema, 138 | trackTypes: z.array(TrackTypeElementSchema), 139 | unsportConductRuleMode: z.number(), 140 | warmupLength: z.number(), 141 | weather: WeatherSchema, 142 | }) 143 | export type HostedSession = z.infer 144 | 145 | export const HostedSessionsSchema = z.object({ 146 | subscribed: z.boolean(), 147 | sessions: z.array(HostedSessionSchema), 148 | success: z.boolean(), 149 | }) 150 | export type HostedSessions = z.infer 151 | 152 | export const FriendSchema = z.object({ 153 | custId: z.number(), 154 | displayName: z.string(), 155 | }) 156 | export type Friend = z.infer 157 | 158 | export const HostedCombinedSessionsSchema = z.object({ 159 | subscribed: z.boolean(), 160 | sequence: z.number(), 161 | sessions: z.array(HostedSessionSchema), 162 | success: z.boolean(), 163 | }) 164 | export type HostedCombinedSessions = z.infer< 165 | typeof HostedCombinedSessionsSchema 166 | > 167 | 168 | // Params 169 | export const GetHostedCombinedSessionsParamsSchema = z.object({ 170 | packageId: z.number().optional(), 171 | }) 172 | export type GetHostedCombinedSessionsParams = z.infer< 173 | typeof GetHostedCombinedSessionsParamsSchema 174 | > 175 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/vue.js: -------------------------------------------------------------------------------- 1 | import { 2 | BaseTransition, 3 | BaseTransitionPropsValidators, 4 | Comment, 5 | DeprecationTypes, 6 | EffectScope, 7 | ErrorCodes, 8 | ErrorTypeStrings, 9 | Fragment, 10 | KeepAlive, 11 | ReactiveEffect, 12 | Static, 13 | Suspense, 14 | Teleport, 15 | Text, 16 | TrackOpTypes, 17 | Transition, 18 | TransitionGroup, 19 | TriggerOpTypes, 20 | VueElement, 21 | assertNumber, 22 | callWithAsyncErrorHandling, 23 | callWithErrorHandling, 24 | camelize, 25 | capitalize, 26 | cloneVNode, 27 | compatUtils, 28 | compile, 29 | computed, 30 | createApp, 31 | createBaseVNode, 32 | createBlock, 33 | createCommentVNode, 34 | createElementBlock, 35 | createHydrationRenderer, 36 | createPropsRestProxy, 37 | createRenderer, 38 | createSSRApp, 39 | createSlots, 40 | createStaticVNode, 41 | createTextVNode, 42 | createVNode, 43 | customRef, 44 | defineAsyncComponent, 45 | defineComponent, 46 | defineCustomElement, 47 | defineEmits, 48 | defineExpose, 49 | defineModel, 50 | defineOptions, 51 | defineProps, 52 | defineSSRCustomElement, 53 | defineSlots, 54 | devtools, 55 | effect, 56 | effectScope, 57 | getCurrentInstance, 58 | getCurrentScope, 59 | getTransitionRawChildren, 60 | guardReactiveProps, 61 | h, 62 | handleError, 63 | hasInjectionContext, 64 | hydrate, 65 | initCustomFormatter, 66 | initDirectivesForSSR, 67 | inject, 68 | isMemoSame, 69 | isProxy, 70 | isReactive, 71 | isReadonly, 72 | isRef, 73 | isRuntimeOnly, 74 | isShallow, 75 | isVNode, 76 | markRaw, 77 | mergeDefaults, 78 | mergeModels, 79 | mergeProps, 80 | nextTick, 81 | normalizeClass, 82 | normalizeProps, 83 | normalizeStyle, 84 | onActivated, 85 | onBeforeMount, 86 | onBeforeUnmount, 87 | onBeforeUpdate, 88 | onDeactivated, 89 | onErrorCaptured, 90 | onMounted, 91 | onRenderTracked, 92 | onRenderTriggered, 93 | onScopeDispose, 94 | onServerPrefetch, 95 | onUnmounted, 96 | onUpdated, 97 | openBlock, 98 | popScopeId, 99 | provide, 100 | proxyRefs, 101 | pushScopeId, 102 | queuePostFlushCb, 103 | reactive, 104 | readonly, 105 | ref, 106 | registerRuntimeCompiler, 107 | render, 108 | renderList, 109 | renderSlot, 110 | resolveComponent, 111 | resolveDirective, 112 | resolveDynamicComponent, 113 | resolveFilter, 114 | resolveTransitionHooks, 115 | setBlockTracking, 116 | setDevtoolsHook, 117 | setTransitionHooks, 118 | shallowReactive, 119 | shallowReadonly, 120 | shallowRef, 121 | ssrContextKey, 122 | ssrUtils, 123 | stop, 124 | toDisplayString, 125 | toHandlerKey, 126 | toHandlers, 127 | toRaw, 128 | toRef, 129 | toRefs, 130 | toValue, 131 | transformVNodeArgs, 132 | triggerRef, 133 | unref, 134 | useAttrs, 135 | useCssModule, 136 | useCssVars, 137 | useModel, 138 | useSSRContext, 139 | useSlots, 140 | useTransitionState, 141 | vModelCheckbox, 142 | vModelDynamic, 143 | vModelRadio, 144 | vModelSelect, 145 | vModelText, 146 | vShow, 147 | version, 148 | warn, 149 | watch, 150 | watchEffect, 151 | watchPostEffect, 152 | watchSyncEffect, 153 | withAsyncContext, 154 | withCtx, 155 | withDefaults, 156 | withDirectives, 157 | withKeys, 158 | withMemo, 159 | withModifiers, 160 | withScopeId 161 | } from "./chunk-KJTOLQBP.js"; 162 | export { 163 | BaseTransition, 164 | BaseTransitionPropsValidators, 165 | Comment, 166 | DeprecationTypes, 167 | EffectScope, 168 | ErrorCodes, 169 | ErrorTypeStrings, 170 | Fragment, 171 | KeepAlive, 172 | ReactiveEffect, 173 | Static, 174 | Suspense, 175 | Teleport, 176 | Text, 177 | TrackOpTypes, 178 | Transition, 179 | TransitionGroup, 180 | TriggerOpTypes, 181 | VueElement, 182 | assertNumber, 183 | callWithAsyncErrorHandling, 184 | callWithErrorHandling, 185 | camelize, 186 | capitalize, 187 | cloneVNode, 188 | compatUtils, 189 | compile, 190 | computed, 191 | createApp, 192 | createBlock, 193 | createCommentVNode, 194 | createElementBlock, 195 | createBaseVNode as createElementVNode, 196 | createHydrationRenderer, 197 | createPropsRestProxy, 198 | createRenderer, 199 | createSSRApp, 200 | createSlots, 201 | createStaticVNode, 202 | createTextVNode, 203 | createVNode, 204 | customRef, 205 | defineAsyncComponent, 206 | defineComponent, 207 | defineCustomElement, 208 | defineEmits, 209 | defineExpose, 210 | defineModel, 211 | defineOptions, 212 | defineProps, 213 | defineSSRCustomElement, 214 | defineSlots, 215 | devtools, 216 | effect, 217 | effectScope, 218 | getCurrentInstance, 219 | getCurrentScope, 220 | getTransitionRawChildren, 221 | guardReactiveProps, 222 | h, 223 | handleError, 224 | hasInjectionContext, 225 | hydrate, 226 | initCustomFormatter, 227 | initDirectivesForSSR, 228 | inject, 229 | isMemoSame, 230 | isProxy, 231 | isReactive, 232 | isReadonly, 233 | isRef, 234 | isRuntimeOnly, 235 | isShallow, 236 | isVNode, 237 | markRaw, 238 | mergeDefaults, 239 | mergeModels, 240 | mergeProps, 241 | nextTick, 242 | normalizeClass, 243 | normalizeProps, 244 | normalizeStyle, 245 | onActivated, 246 | onBeforeMount, 247 | onBeforeUnmount, 248 | onBeforeUpdate, 249 | onDeactivated, 250 | onErrorCaptured, 251 | onMounted, 252 | onRenderTracked, 253 | onRenderTriggered, 254 | onScopeDispose, 255 | onServerPrefetch, 256 | onUnmounted, 257 | onUpdated, 258 | openBlock, 259 | popScopeId, 260 | provide, 261 | proxyRefs, 262 | pushScopeId, 263 | queuePostFlushCb, 264 | reactive, 265 | readonly, 266 | ref, 267 | registerRuntimeCompiler, 268 | render, 269 | renderList, 270 | renderSlot, 271 | resolveComponent, 272 | resolveDirective, 273 | resolveDynamicComponent, 274 | resolveFilter, 275 | resolveTransitionHooks, 276 | setBlockTracking, 277 | setDevtoolsHook, 278 | setTransitionHooks, 279 | shallowReactive, 280 | shallowReadonly, 281 | shallowRef, 282 | ssrContextKey, 283 | ssrUtils, 284 | stop, 285 | toDisplayString, 286 | toHandlerKey, 287 | toHandlers, 288 | toRaw, 289 | toRef, 290 | toRefs, 291 | toValue, 292 | transformVNodeArgs, 293 | triggerRef, 294 | unref, 295 | useAttrs, 296 | useCssModule, 297 | useCssVars, 298 | useModel, 299 | useSSRContext, 300 | useSlots, 301 | useTransitionState, 302 | vModelCheckbox, 303 | vModelDynamic, 304 | vModelRadio, 305 | vModelSelect, 306 | vModelText, 307 | vShow, 308 | version, 309 | warn, 310 | watch, 311 | watchEffect, 312 | watchPostEffect, 313 | watchSyncEffect, 314 | withAsyncContext, 315 | withCtx, 316 | withDefaults, 317 | withDirectives, 318 | withKeys, 319 | withMemo, 320 | withModifiers, 321 | withScopeId 322 | }; 323 | //# sourceMappingURL=vue.js.map 324 | -------------------------------------------------------------------------------- /packages/iracing-api/README.md: -------------------------------------------------------------------------------- 1 | # iracing-api 2 | 3 | [Full docs](https://iracing-api.dyczkowski.dev/) 4 | 5 | ## Installation 6 | 7 | ```bash 8 | npm install iracing-api 9 | yarn add iracing-api 10 | pnpm i iracing-api 11 | bun i iracing-api 12 | ``` 13 | 14 | ## Basic Usage 15 | 16 | ```typescript 17 | import IracingAPI from 'iracing-api' 18 | 19 | const irUser = 'FOO@gmail.com' 20 | const irPass = 'BAR' 21 | 22 | const main = async () => { 23 | const ir = new IracingAPI() 24 | 25 | // First you have to login to iracing using your credentials to be able to use the API. 26 | await ir.login(irUser, irPass) 27 | 28 | // Now you can use any endpoint, e.g. getCars 29 | const cars = await ir.car.getCars() 30 | 31 | console.log(cars) 32 | } 33 | 34 | main().then(() => 'Done') 35 | ``` 36 | 37 | ## Endpoint Mapping 38 | 39 | | API Class | Method Name | Endpoint Path | 40 | | --------------- | -------------------------------- | ------------------------------------------ | 41 | | `CarAPI` | `getCarAssets` | `data/car/assets` | 42 | | `CarAPI` | `getCars` | `data/car/get` | 43 | | `CarClassAPI` | `getCarClasses` | `data/carclass/get` | 44 | | `ConstantsAPI` | `getCategories` | `data/constants/categories` | 45 | | `ConstantsAPI` | `getDivisions` | `data/constants/divisions` | 46 | | `ConstantsAPI` | `getEventTypes` | `data/constants/event_types` | 47 | | `HostedAPI` | `getHostedCombinedSessions` | `data/hosted/combined_sessions` | 48 | | `HostedAPI` | `getHostedSessions` | `data/hosted/sessions` | 49 | | `LeagueAPI` | `getCustLeagueSessions` | `data/league/cust_league_sessions` | 50 | | `LeagueAPI` | `getLeagueDirectory` | `data/league/directory` | 51 | | `LeagueAPI` | `getLeagueData` | `data/league/get` | 52 | | `LeagueAPI` | `getLeaguePointSystem` | `data/league/get_points_systems` | 53 | | `LeagueAPI` | `getLeagueMembership` | `data/league/membership` | 54 | | `LeagueAPI` | `getLeagueSeasons` | `data/league/seasons` | 55 | | `LeagueAPI` | `getLeagueSeasonStandings` | `data/league/season_standings` | 56 | | `LeagueAPI` | `getLeagueSeasonSessions` | `data/league/season_sessions` | 57 | | `LookupAPI` | `getClubHistory` | `data/lookup/club_history` | 58 | | `LookupAPI` | `getCountries` | `data/lookup/countries` | 59 | | `LookupAPI` | `getDrivers` | `data/lookup/drivers` | 60 | | `LookupAPI` | `getLicenses` | `data/lookup/licenses` | 61 | | `MemberAPI` | `getMemberAwards` | `data/member/awards` | 62 | | `MemberAPI` | `getMemberChartData` | `data/member/chart_data` | 63 | | `MemberAPI` | `getMemberData` | `data/member/get` | 64 | | `MemberAPI` | `getMemberInfo` | `data/member/info` | 65 | | `MemberAPI` | `getMemberParticipationCredits` | `data/member/participation_credits` | 66 | | `MemberAPI` | `getMemberProfile` | `data/member/profile` | 67 | | `ResultsAPI` | `getResult` | `data/results/get` | 68 | | `ResultsAPI` | `getResultsEventLog` | `data/results/event_log` | 69 | | `ResultsAPI` | `getResultsLapChartData` | `data/results/lap_chart_data` | 70 | | `ResultsAPI` | `getResultsLapData` | `data/results/lap_data` | 71 | | `ResultsAPI` | `searchHosted` | `data/results/search_hosted` | 72 | | `ResultsAPI` | `searchSeries` | `data/results/search_series` | 73 | | `ResultsAPI` | `getSeasonResults` | `data/results/season_results` | 74 | | `SeasonAPI` | `getSeasonList` | `data/season/list` | 75 | | `SeasonAPI` | `getSeasonRaceGuide` | `data/season/race_guide` | 76 | | `SeasonAPI` | `getSpectatorSubsessionIds` | `data/season/spectator_subsession_ids` | 77 | | `SeriesAPI` | `getSeriesAssets` | `data/series/assets` | 78 | | `SeriesAPI` | `getSeriesData` | `data/series/get` | 79 | | `SeriesAPI` | `getSeriesPastSeasons` | `data/series/past_seasons` | 80 | | `SeriesAPI` | `getSeriesSeasons` | `data/series/seasons` | 81 | | `SeriesAPI` | `getSeriesStats` | `data/series/stats_series` | 82 | | `StatsAPI` | `getMemberBests` | `data/stats/member_bests` | 83 | | `StatsAPI` | `getMemberCareer` | `data/stats/member_career` | 84 | | `StatsAPI` | `getMemberDivision` | `data/stats/member_division` | 85 | | `StatsAPI` | `getMemberRecentRaces` | `data/stats/member_recent_races` | 86 | | `StatsAPI` | `getMemberRecap` | `data/stats/member_recap` | 87 | | `StatsAPI` | `getMemberSummary` | `data/stats/member_summary` | 88 | | `StatsAPI` | `getMemberYearlyStats` | `data/stats/member_yearly` | 89 | | `StatsAPI` | `getDriverSeasonStandings` | `data/stats/season_driver_standings` | 90 | | `StatsAPI` | `getSupersessionSeasonStandings` | `data/stats/season_supersession_standings` | 91 | | `StatsAPI` | `getTeamSeasonStandings` | `data/stats/season_team_standings` | 92 | | `StatsAPI` | `getTimeTrialSeasonStandings` | `data/stats/season_tt_results` | 93 | | `StatsAPI` | `getQualifySeasonStandings` | `data/stats/season_qualify_results` | 94 | | `StatsAPI` | `getWorldRecords` | `data/stats/world_records` | 95 | | `TeamAPI` | `getTeamData` | `data/team/get` | 96 | | `TimeAttackAPI` | `getTimeAttackSeasonResults` | `data/time_attack/member_season_results` | 97 | | `TrackAPI` | `getTrackAssets` | `data/track/assets` | 98 | | `TrackAPI` | `getTracks` | `data/track/get` | 99 | -------------------------------------------------------------------------------- /packages/iracing-api/src/types/common.ts: -------------------------------------------------------------------------------- 1 | import * as z from 'zod' 2 | 3 | export const CategorySchema = z.enum([ 4 | 'dirt_oval', 5 | 'dirt_road', 6 | 'formula_car', 7 | 'oval', 8 | 'sports_car', 9 | ]) 10 | export type CarCategory = z.infer 11 | 12 | export const CarTypeSchema = z.object({ 13 | carType: z.string(), 14 | }) 15 | export type CarType = z.infer 16 | 17 | export const EligSchema = z.object({ 18 | sessionFull: z.boolean(), 19 | canSpot: z.boolean(), 20 | canWatch: z.boolean(), 21 | canDrive: z.boolean(), 22 | hasSessPassword: z.boolean(), 23 | needsPurchase: z.boolean(), 24 | ownCar: z.boolean(), 25 | ownTrack: z.boolean(), 26 | purchaseSkus: z.array(z.number()), 27 | registered: z.boolean(), 28 | }) 29 | export type Elig = z.infer 30 | 31 | export const EventTypeSchema = z.object({ 32 | eventType: z.number(), 33 | }) 34 | export type EventType = z.infer 35 | 36 | export const FarmSchema = z.object({ 37 | farmId: z.number(), 38 | displayName: z.string(), 39 | imagePath: z.string(), 40 | displayed: z.boolean(), 41 | }) 42 | export type Farm = z.infer 43 | 44 | export const HelmetSchema = z.object({ 45 | pattern: z.number(), 46 | color1: z.string(), 47 | color2: z.string(), 48 | color3: z.string(), 49 | faceType: z.number(), 50 | helmetType: z.number(), 51 | }) 52 | export type Helmet = z.infer 53 | 54 | export const HostSchema = z.object({ 55 | custId: z.number(), 56 | displayName: z.string(), 57 | helmet: HelmetSchema, 58 | }) 59 | export type Host = z.infer 60 | 61 | export const LicenseGroupTypeSchema = z.object({ 62 | licenseGroupType: z.number(), 63 | }) 64 | export type LicenseGroupType = z.infer 65 | 66 | export const SessionTypeSchema = z.object({ 67 | sessionType: z.number(), 68 | }) 69 | export type SessionType = z.infer 70 | 71 | export const TrackStateSchema = z.object({ 72 | leaveMarbles: z.boolean(), 73 | practiceGripCompound: z.number(), 74 | practiceRubber: z.number(), 75 | qualifyGripCompound: z.number(), 76 | qualifyRubber: z.number(), 77 | raceGripCompound: z.number(), 78 | raceRubber: z.number(), 79 | warmupGripCompound: z.number(), 80 | warmupRubber: z.number(), 81 | }) 82 | export type TrackState = z.infer 83 | 84 | export const ForecastOptionsSchema = z.object({ 85 | forecastType: z.number(), 86 | precipitation: z.number(), 87 | skies: z.number(), 88 | stopPrecip: z.number(), 89 | temperature: z.number(), 90 | windDir: z.number(), 91 | windSpeed: z.number(), 92 | }) 93 | export type ForecastOptions = z.infer 94 | 95 | export const MaxPrecipRateDescSchema = z.enum([ 96 | 'Heavy', 97 | 'Light', 98 | 'Moderate', 99 | 'None', 100 | ]) 101 | export type MaxPrecipRateDesc = z.infer 102 | 103 | export const WeatherSummarySchema = z.object({ 104 | maxPrecipRate: z.union([z.number(), z.null()]).optional(), 105 | maxPrecipRateDesc: MaxPrecipRateDescSchema, 106 | precipChance: z.number(), 107 | skiesHigh: z.union([z.number(), z.null()]).optional(), 108 | skiesLow: z.union([z.number(), z.null()]).optional(), 109 | tempHigh: z.union([z.number(), z.null()]).optional(), 110 | tempLow: z.union([z.number(), z.null()]).optional(), 111 | tempUnits: z.union([z.number(), z.null()]).optional(), 112 | windHigh: z.union([z.number(), z.null()]).optional(), 113 | windLow: z.union([z.number(), z.null()]).optional(), 114 | windUnits: z.union([z.number(), z.null()]).optional(), 115 | }) 116 | export type WeatherSummary = z.infer 117 | 118 | export const WeatherSchema = z.object({ 119 | allowFog: z.boolean(), 120 | fog: z.number(), 121 | forecastOptions: z.union([ForecastOptionsSchema, z.null()]).optional(), 122 | humidityUnits: z.number(), 123 | precipOption: z.number(), 124 | relHumidity: z.number(), 125 | simulatedStartTime: z.string(), 126 | simulatedStartUtcTime: z.string(), 127 | simulatedTimeMultiplier: z.number(), 128 | simulatedTimeOffsets: z.array(z.number()), 129 | skies: z.number(), 130 | tempUnits: z.number(), 131 | tempValue: z.number(), 132 | timeOfDay: z.number(), 133 | trackWater: z.union([z.number(), z.null()]).optional(), 134 | type: z.number(), 135 | version: z.number(), 136 | weatherSummary: z.union([WeatherSummarySchema, z.null()]).optional(), 137 | weatherUrl: z.union([z.string(), z.null()]).optional(), 138 | weatherVarInitial: z.number(), 139 | weatherVarOngoing: z.number(), 140 | windDir: z.number(), 141 | windUnits: z.number(), 142 | windValue: z.number(), 143 | }) 144 | export type Weather = z.infer 145 | 146 | export const HeatSesInfoSchema = z.object({ 147 | consolationDeltaMaxFieldSize: z.number(), 148 | consolationDeltaSessionLaps: z.number(), 149 | consolationDeltaSessionLengthMinutes: z.number(), 150 | consolationFirstMaxFieldSize: z.number(), 151 | consolationFirstSessionLaps: z.number(), 152 | consolationFirstSessionLengthMinutes: z.number(), 153 | consolationNumPositionToInvert: z.number(), 154 | consolationNumToConsolation: z.number(), 155 | consolationNumToMain: z.number(), 156 | consolationRunAlways: z.boolean(), 157 | consolationScoresChampPoints: z.boolean(), 158 | created: z.string(), 159 | custId: z.number(), 160 | heatCautionType: z.number(), 161 | heatInfoId: z.number(), 162 | heatInfoName: z.string(), 163 | heatLaps: z.number(), 164 | heatLengthMinutes: z.number(), 165 | heatMaxFieldSize: z.number(), 166 | heatNumFromEachToMain: z.number(), 167 | heatNumPositionToInvert: z.number(), 168 | heatScoresChampPoints: z.boolean(), 169 | heatSessionMinutesEstimate: z.number(), 170 | hidden: z.boolean(), 171 | mainLaps: z.number(), 172 | mainLengthMinutes: z.number(), 173 | mainMaxFieldSize: z.number(), 174 | mainNumPositionToInvert: z.number(), 175 | maxEntrants: z.number(), 176 | openPractice: z.boolean(), 177 | preMainPracticeLengthMinutes: z.number(), 178 | preQualNumToMain: z.number(), 179 | preQualPracticeLengthMinutes: z.number(), 180 | qualCautionType: z.number(), 181 | qualLaps: z.number(), 182 | qualLengthMinutes: z.number(), 183 | qualNumToMain: z.number(), 184 | qualOpenDelaySeconds: z.number(), 185 | qualScoresChampPoints: z.boolean(), 186 | qualScoring: z.number(), 187 | qualStyle: z.number(), 188 | raceStyle: z.number(), 189 | }) 190 | export type HeatSesInfo = z.infer 191 | 192 | export const TrackTypeEnumSchema = z.enum([ 193 | 'dirt_road', 194 | 'dirt_oval', 195 | 'oval', 196 | 'road', 197 | ]) 198 | export type TrackTypeEnum = z.infer 199 | 200 | export const TrackTypeSchema = z.object({ 201 | trackType: TrackTypeEnumSchema, 202 | }) 203 | export type TrackType = z.infer 204 | -------------------------------------------------------------------------------- /docs/api/stats.md: -------------------------------------------------------------------------------- 1 | # Stats API 2 | 3 | All methods in the `Stats` API are available through the `stats` property of the `iRacingAPI` instance. 4 | 5 | ## Member Bests 6 | 7 | Get the member bests. 8 | 9 | ```ts 10 | const memberBests = await ir.stats.getMemberBests(params); 11 | ``` 12 | 13 | Available parameters: 14 | * `customerId?: number` - The customer ID of the member to get the bests for. 15 | * Defaults to the authenticated member. 16 | * `carId?: number` - The car ID to get the bests for. 17 | * First call should exclude `carId`. 18 | * Use `carsDriven` list in return for subsequent calls. 19 | 20 | https://members-ng.iracing.com/data/stats/member_bests 21 | 22 | ## Member Career 23 | 24 | Get the member career. 25 | 26 | ```ts 27 | const memberCareer = await ir.stats.getMemberCareer(params); 28 | ``` 29 | 30 | Available parameters: 31 | * `customerId?: number` - The customer ID of the member to get the career for. 32 | * Defaults to the authenticated member. 33 | 34 | https://members-ng.iracing.com/data/stats/member_career 35 | 36 | ## Member Division 37 | 38 | Get the member division. 39 | 40 | ```ts 41 | const memberDivision = await ir.stats.getMemberDivision(params); 42 | ``` 43 | 44 | Available parameters: 45 | * `seasonId: number` - The season ID to get the division for. 46 | * `eventType: number` - The event type to get the division for. 47 | * The event type code for the division type: 48 | * `4` - Time Trial 49 | * `5` - Race 50 | 51 | https://members-ng.iracing.com/data/stats/member_division 52 | 53 | ## Member Recent Races 54 | 55 | Get the member's recent races. 56 | 57 | ```ts 58 | const memberRecentRaces = await ir.stats.getMemberRecentRaces(params); 59 | ``` 60 | 61 | Available parameters: 62 | * `customerId?: number` - The customer ID of the member to 63 | * Defaults to the authenticated member. 64 | 65 | https://members-ng.iracing.com/data/stats/member_recent_races 66 | 67 | ## Member Recap 68 | 69 | Get the member recap. 70 | 71 | ```ts 72 | const memberRecap = await ir.stats.getMemberRecap(params); 73 | ``` 74 | 75 | Available parameters: 76 | * `customerId?: number` - The customer ID of the member to get the recap for. 77 | * Defaults to the authenticated member. 78 | * `year?: number` - The year to get the recap for. 79 | * If not supplied, the current calendar year (UTC) is used. 80 | * `season?: number` - The season (quarter) within the year to get the recap for. 81 | * If not supplied, the recap will be for the entire year. 82 | 83 | https://members-ng.iracing.com/data/stats/member_recap 84 | 85 | ## Member Summary 86 | 87 | Get the member summary. 88 | 89 | ```ts 90 | const memberSummary = await ir.stats.getMemberSummary(params); 91 | ``` 92 | 93 | Available parameters: 94 | * `customerId?: number` - The customer ID of the member to get the summary for. 95 | * Defaults to the authenticated member. 96 | 97 | https://members-ng.iracing.com/data/stats/member_summary 98 | 99 | ## Member Yearly Stats 100 | 101 | Get the member yearly stats. 102 | 103 | ```ts 104 | const memberYearlyStats = await ir.stats.getMemberYearlyStats(params); 105 | ``` 106 | 107 | Available parameters: 108 | * `customerId?: number` - The customer ID of the member to get the yearly stats for. 109 | * Defaults to the authenticated member. 110 | 111 | https://members-ng.iracing.com/data/stats/member_yearly_stats 112 | 113 | ## Driver Season Standings 114 | 115 | Get the driver season standings. 116 | 117 | ```ts 118 | const driverSeasonStandings = await ir.stats.getDriverSeasonStandings(params); 119 | ``` 120 | 121 | Available parameters: 122 | * `seasonId: number` - The season ID to get the driver season standings for. 123 | * `carClassId: number` - The car class ID to get the driver season standings for. 124 | * `clubId? number` - The club ID to get the driver season standings for. 125 | * Defaults to all (`-1`). 126 | * `division?: number` - The division to get the driver season standings for. 127 | * Divisions are 0-based: 128 | * `0` is Division 1, 129 | * `10` is Rookie. 130 | * See [`constants.getDivisions()`](/api/constants.html#divisions) for more information. 131 | * Defaults to all. 132 | * `raceWeekNumber?: number` - The race week number to get the driver season standings for. 133 | * The first race week of a season is `0`. 134 | 135 | https://members-ng.iracing.com/data/stats/season_driver_standings 136 | 137 | ## Supersession Season Standings 138 | 139 | Get the supersession season standings. 140 | 141 | ```ts 142 | const supersessionSeasonStandings = await ir.stats.getSupersessionSeasonStandings(); 143 | ``` 144 | 145 | Available parameters: 146 | * `seasonId: number` - The season ID to get the driver season standings for. 147 | * `carClassId: number` - The car class ID to get the driver season standings for. 148 | * `clubId? number` - The club ID to get the driver season standings for. 149 | * Defaults to all (`-1`). 150 | * `division?: number` - The division to get the driver season standings for. 151 | * Divisions are 0-based: 152 | * `0` is Division 1, 153 | * `10` is Rookie. 154 | * See [`constants.getDivisions()`](/api/constants.html#divisions) for more information. 155 | * Defaults to all. 156 | * `raceWeekNumber?: number` - The race week number to get the driver season standings for. 157 | * The first race week of a season is `0`. 158 | 159 | https://members-ng.iracing.com/data/stats/season_supersession_standings 160 | 161 | ## Team Season Standings 162 | 163 | Get the team season standings. 164 | 165 | ```ts 166 | const teamSeasonStandings = await ir.stats.getTeamSeasonStandings(); 167 | ``` 168 | 169 | Available parameters: 170 | * `seasonId: number` - The season ID to get the driver season standings for. 171 | * `carClassId: number` - The car class ID to get the driver season standings for. 172 | * `raceWeekNumber?: number` - The race week number to get the driver season standings for. 173 | * The first race week of a season is `0`. 174 | 175 | https://members-ng.iracing.com/data/stats/season_team_standings 176 | 177 | ## Time Trial Season Standings 178 | 179 | Get the time trial season standings. 180 | 181 | ```ts 182 | const timeTrialSeasonStandings = await ir.stats.getTimeTrialSeasonStandings(); 183 | ``` 184 | 185 | Available parameters: 186 | * `seasonId: number` - The season ID to get the driver season standings for. 187 | * `carClassId: number` - The car class ID to get the driver season standings for. 188 | * `clubId? number` - The club ID to get the driver season standings for. 189 | * Defaults to all (`-1`). 190 | * `division?: number` - The division to get the driver season standings for. 191 | * Divisions are 0-based: 192 | * `0` is Division 1, 193 | * `10` is Rookie. 194 | * See [`constants.getDivisions()`](/api/constants.html#divisions) for more information. 195 | * Defaults to all. 196 | * `raceWeekNumber?: number` - The race week number to get the driver season standings for. 197 | * The first race week of a season is `0`. 198 | 199 | https://members-ng.iracing.com/data/stats/season_tt_results 200 | 201 | ## Qualify Season Standings 202 | 203 | Get the qualify season standings. 204 | 205 | ```ts 206 | const qualifySeasonStandings = await ir.stats.getQualifySeasonStandings(); 207 | ``` 208 | 209 | Available parameters: 210 | * `seasonId: number` - The season ID to get the driver season standings for. 211 | * `carClassId: number` - The car class ID to get the driver season standings for. 212 | * `clubId? number` - The club ID to get the driver season standings for. 213 | * Defaults to all (`-1`). 214 | * `division?: number` - The division to get the driver season standings for. 215 | * Divisions are 0-based: 216 | * `0` is Division 1, 217 | * `10` is Rookie. 218 | * See [`constants.getDivisions()`](/api/constants.html#divisions) for more information. 219 | * Defaults to all. 220 | * `raceWeekNumber?: number` - The race week number to get the driver season standings for. 221 | * The first race week of a season is `0`. 222 | 223 | https://members-ng.iracing.com/data/stats/season_qualify_results 224 | 225 | ## World Records 226 | 227 | Get the world records. 228 | 229 | ```ts 230 | const worldRecords = await ir.stats.getWorldRecords(); 231 | ``` 232 | 233 | Available parameters: 234 | * `carId: number` - The car ID to get the world records for. 235 | * `trackId: number` - The track ID to get the world records for. 236 | * `seasonYear?: number` - Limit best times to a given year. 237 | * `seasonQuarter?: number` - Limit best times to a given quarter. 238 | * Only applicable when year is used. 239 | 240 | https://members-ng.iracing.com/data/stats/world_records -------------------------------------------------------------------------------- /packages/iracing-api/src/api/league.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import type { 3 | CustLeagueSessions, 4 | GetCustLeagueSessionsParams, 5 | GetLeagueDataParams, 6 | GetLeagueDirectoryParams, 7 | GetLeagueMembershipParams, 8 | GetLeaguePointSystemParams, 9 | GetLeagueRosterParams, 10 | GetLeagueSeasonSessionsParams, 11 | GetLeagueSeasonStandingsParams, 12 | GetLeagueSeasonsParams, 13 | LeagueDirectory, 14 | } from '../types' 15 | 16 | /** 17 | * Provides methods for interacting with league-related endpoints. 18 | */ 19 | export class LeagueAPI extends API { 20 | /** 21 | * Get a list of customer league sessions. 22 | * 23 | * @param {GetCustLeagueSessionsParams} [params] - Optional parameters to filter the sessions. 24 | * @param {boolean} [params.mine] - If true, return only sessions created by the authenticated user. 25 | * @param {number} [params.packageId] - If set, return only sessions using this car or track package ID. 26 | * @returns A promise resolving to the customer league sessions data, or undefined on error. 27 | */ 28 | getCustLeagueSessions = async (params?: GetCustLeagueSessionsParams) => 29 | await this._getData( 30 | 'data/league/cust_league_sessions', 31 | { 32 | mine: params?.mine, 33 | package_id: params?.packageId, 34 | } 35 | ) 36 | 37 | /** 38 | * Search the league directory. 39 | * 40 | * @param {GetLeagueDirectoryParams} [params] - Optional parameters to filter and sort the league directory. 41 | * @param {string} [params.search] - Search term for league name, description, owner, and league ID. 42 | * @param {string} [params.tag] - One or more tags, comma-separated. 43 | * @param {boolean} [params.restrictToMember=false] - Include only leagues the customer is a member of. 44 | * @param {boolean} [params.restrictToRecruiting=false] - Include only leagues which are recruiting. 45 | * @param {boolean} [params.restrictToFriends=false] - Include only leagues owned by a friend. 46 | * @param {boolean} [params.restrictToWatched=false] - Include only leagues owned by a watched member. 47 | * @param {number} [params.minimumRosterCount] - Minimum number of members for included leagues. 48 | * @param {number} [params.maximumRosterCount] - Maximum number of members for included leagues. 49 | * @param {number} [params.lowerbound=1] - First row of results to return. 50 | * @param {number} [params.upperbound] - Last row of results to return (defaults to lowerbound + 39). 51 | * @param {string} [params.sort='relevance'] - Sort criteria: 'relevance', 'leaguename', 'displayname' (owner's name), 'rostercount'. 52 | * @param {string} [params.order='asc'] - Sort order: 'asc' or 'desc'. 53 | * 54 | * @returns A promise resolving to the league directory search results, or undefined on error. 55 | */ 56 | getLeagueDirectory = async (params?: GetLeagueDirectoryParams) => 57 | await this._getData('data/league/directory', { 58 | search: params?.search, 59 | tag: params?.tag, 60 | restrict_to_member: params?.restrictToMember, 61 | restrict_to_recruiting: params?.restrictToRecruiting, 62 | restrict_to_friends: params?.restrictToFriends, 63 | restrict_to_watched: params?.restrictToWatched, 64 | minimum_roster_count: params?.minimumRosterCount, 65 | maximum_roster_count: params?.maximumRosterCount, 66 | lowerbound: params?.lowerbound, 67 | upperbound: params?.upperbound, 68 | sort: params?.sort, 69 | order: params?.order, 70 | }) 71 | 72 | /** 73 | * Get detailed information about a specific league. 74 | * 75 | * @param {GetLeagueDataParams} params - Parameters for the request. 76 | * @param {number} params.leagueId - The ID of the league to retrieve. 77 | * @param {boolean} [params.includeLicenses=false] - Include license information for members (can slow down response). 78 | * 79 | * @returns A promise resolving to the league data, or undefined on error. 80 | */ 81 | getLeagueData = async (params: GetLeagueDataParams) => 82 | await this._getData('data/league/get', { 83 | league_id: params.leagueId, 84 | include_licenses: params.includeLicenses, 85 | }) 86 | 87 | /** 88 | * Get the points systems available for a league, optionally filtered by season. 89 | * 90 | * @param {GetLeaguePointSystemParams} params - Parameters for the request. 91 | * @param {number} params.leagueId - The ID of the league. 92 | * @param {number} [params.seasonId] - If provided and the season uses custom points, include the custom option. 93 | * 94 | * @returns A promise resolving to the list of points systems, or undefined on error. 95 | */ 96 | getLeaguePointSystem = async (params: GetLeaguePointSystemParams) => 97 | await this._getData('data/league/get_points_systems', { 98 | league_id: params.leagueId, 99 | season_id: params.seasonId, 100 | }) 101 | 102 | /** 103 | * Get league membership information for a customer. 104 | * 105 | * @param {GetLeagueMembershipParams} [params] - Optional parameters to specify the customer. 106 | * @param {number} [params.customerId] - Customer ID to fetch membership for. Defaults to the authenticated user. 107 | * Note: Restrictions apply if fetching for another user (see iRacing docs). 108 | * @param {boolean} [params.includeLeague=false] - Include detailed league information in the response. 109 | * 110 | * @returns A promise resolving to the league membership data, or undefined on error. 111 | */ 112 | getLeagueMembership = async (params?: GetLeagueMembershipParams) => 113 | await this._getData('data/league/membership', { 114 | cust_id: params?.customerId, 115 | include_league: params?.includeLeague, 116 | }) 117 | /** 118 | * Get the seasons for a specific league. 119 | * 120 | * @param {GetLeagueSeasonsParams} params - Parameters for the request. 121 | * @param {number} params.leagueId - The ID of the league. 122 | * @param {boolean} [params.retired=false] - If true, include inactive (retired) seasons. 123 | * 124 | * @returns A promise resolving to the list of league seasons, or undefined on error. 125 | */ 126 | getLeagueSeasons = async (params: GetLeagueSeasonsParams) => 127 | await this._getData('data/league/seasons', { 128 | league_id: params.leagueId, 129 | retired: params.retired, 130 | }) 131 | /** 132 | * Get the season standings for a specific league season. 133 | * 134 | * @param {GetLeagueSeasonStandingsParams} params - Parameters for the request. 135 | * @param {number} params.leagueId - The ID of the league. 136 | * @param {number} params.seasonId - The ID of the season. 137 | * @param {number} [params.carClassId] - Optional car class ID to filter standings. 138 | * @param {number} [params.carId] - Optional car ID. If `carClassId` is included, filters within the class; otherwise, across classes. 139 | * 140 | * @returns A promise resolving to the league season standings, or undefined on error. 141 | */ 142 | getLeagueSeasonStandings = async (params: GetLeagueSeasonStandingsParams) => 143 | await this._getData('data/league/season_standings', { 144 | car_id: params.carId, 145 | car_class_id: params.carClassId, 146 | league_id: params.leagueId, 147 | season_id: params.seasonId, 148 | }) 149 | /** 150 | * Get the sessions for a specific league season. 151 | * 152 | * @param {GetLeagueSeasonSessionsParams} params - Parameters for the request. 153 | * @param {number} params.leagueId - The ID of the league. 154 | * @param {number} params.seasonId - The ID of the season. 155 | * @param {boolean} [params.resultsOnly=false] - If true, include only sessions for which results are available. 156 | * 157 | * @returns A promise resolving to the list of league season sessions, or undefined on error. 158 | */ 159 | getLeagueSeasonSessions = async (params: GetLeagueSeasonSessionsParams) => 160 | await this._getData('data/league/season_sessions', { 161 | league_id: params.leagueId, 162 | season_id: params.seasonId, 163 | results_only: params.resultsOnly, 164 | }) 165 | 166 | /** 167 | * Get the roster for a specific league. 168 | * 169 | * @param {GetLeagueRosterParams} params - Parameters for the request. 170 | * @param {number} params.leagueId - The ID of the league. 171 | * @param {boolean} [params.includeLicenses=false] - Include license information for roster members (can slow down response). 172 | * 173 | * @returns A promise resolving to the league roster, or undefined on error. 174 | */ 175 | getLeagueRoster = async (params: GetLeagueRosterParams) => 176 | await this._getData('data/league/roster', { 177 | league_id: params.leagueId, 178 | include_licenses: params.includeLicenses, 179 | }) 180 | } 181 | -------------------------------------------------------------------------------- /packages/iracing-api/src/types/league.ts: -------------------------------------------------------------------------------- 1 | import * as z from 'zod' 2 | 3 | import { 4 | CarTypeSchema, 5 | EligSchema, 6 | EventTypeSchema, 7 | FarmSchema, 8 | HelmetSchema, 9 | HostSchema, 10 | LicenseGroupTypeSchema, 11 | SessionTypeSchema, 12 | TrackStateSchema, 13 | TrackTypeSchema, 14 | WeatherSchema, 15 | } from './common' 16 | 17 | export const LeagueTrackSchema = z.object({ 18 | trackId: z.number(), 19 | trackName: z.string(), 20 | configName: z.union([z.null(), z.string()]).optional(), 21 | }) 22 | export type LeagueTrack = z.infer 23 | 24 | export const ImageSchema = z.object({ 25 | largeLogo: z.union([z.null(), z.string()]), 26 | smallLogo: z.string(), 27 | }) 28 | export type Image = z.infer 29 | 30 | export const LeagueCarSchema = z.object({ 31 | carClassId: z.number(), 32 | carClassName: z.string(), 33 | carId: z.number(), 34 | carName: z.string(), 35 | maxDryTireSets: z.number(), 36 | maxPctFuelFill: z.number(), 37 | packageId: z.number(), 38 | powerAdjustPct: z.number(), 39 | qualSetupFilename: z.union([z.null(), z.string()]).optional(), 40 | qualSetupId: z.union([z.number(), z.null()]).optional(), 41 | raceSetupFilename: z.union([z.null(), z.string()]).optional(), 42 | raceSetupId: z.union([z.number(), z.null()]).optional(), 43 | weightPenaltyKg: z.number(), 44 | }) 45 | export type LeagueCar = z.infer 46 | 47 | export const SessionSchema = z.object({ 48 | admin: z.boolean(), 49 | admins: z.array(HostSchema), 50 | aiAvoidPlayers: z.boolean(), 51 | aiMaxSkill: z.union([z.number(), z.null()]).optional(), 52 | aiMinSkill: z.union([z.number(), z.null()]).optional(), 53 | aiRosterName: z.union([z.null(), z.string()]).optional(), 54 | allowedClubs: z.array(z.any()), 55 | allowedLeagues: z.array(z.number()), 56 | allowedTeams: z.array(z.any()), 57 | availableReservedBroadcasterSlots: z.number(), 58 | availableSpectatorSlots: z.number(), 59 | broadcaster: z.boolean(), 60 | canBroadcast: z.boolean(), 61 | canJoin: z.boolean(), 62 | canSpot: z.boolean(), 63 | canWatch: z.boolean(), 64 | carTypes: z.array(CarTypeSchema), 65 | cars: z.array(LeagueCarSchema), 66 | carsLeft: z.number(), 67 | consecCautionsSingleFile: z.boolean(), 68 | countByCarClassId: z.record(z.string(), z.number()), 69 | countByCarId: z.record(z.string(), z.number()), 70 | damageModel: z.number(), 71 | disallowVirtualMirror: z.boolean(), 72 | doNotCountCautionLaps: z.boolean(), 73 | doNotPaintCars: z.boolean(), 74 | driverChangeRule: z.number(), 75 | driverChanges: z.boolean(), 76 | elig: EligSchema, 77 | enablePitlaneCollisions: z.boolean(), 78 | endTime: z.string(), 79 | entryCount: z.number(), 80 | eventTypes: z.array(EventTypeSchema), 81 | farm: FarmSchema, 82 | fixedSetup: z.boolean(), 83 | friends: z.array(z.any()), 84 | fullCourseCautions: z.boolean(), 85 | greenWhiteCheckeredLimit: z.number(), 86 | hardcoreLevel: z.number(), 87 | host: HostSchema, 88 | image: z.union([ImageSchema, z.null()]).optional(), 89 | incidentLimit: z.number(), 90 | incidentWarnMode: z.number(), 91 | incidentWarnParam1: z.number(), 92 | incidentWarnParam2: z.number(), 93 | isHeatRacing: z.boolean(), 94 | launchAt: z.string(), 95 | leagueId: z.number(), 96 | leagueName: z.string(), 97 | leagueSeasonId: z.number(), 98 | leagueSeasonName: z.union([z.null(), z.string()]).optional(), 99 | licenseGroupTypes: z.array(LicenseGroupTypeSchema), 100 | loneQualify: z.boolean(), 101 | luckyDog: z.boolean(), 102 | maxAiDrivers: z.number(), 103 | maxDrivers: z.number(), 104 | maxIr: z.number(), 105 | maxLicenseLevel: z.number(), 106 | maxTeamDrivers: z.number(), 107 | maxUsers: z.number(), 108 | minIr: z.number(), 109 | minLicenseLevel: z.number(), 110 | minTeamDrivers: z.number(), 111 | multiclassType: z.number(), 112 | mustUseDiffTireTypesInRace: z.boolean(), 113 | noLapperWaveArounds: z.boolean(), 114 | numBroadcasters: z.number(), 115 | numDrivers: z.number(), 116 | numFastTows: z.number(), 117 | numOptLaps: z.number(), 118 | numSpectatorSlots: z.number(), 119 | numSpectators: z.number(), 120 | numSpotters: z.number(), 121 | openRegExpires: z.string(), 122 | orderId: z.number(), 123 | owner: z.boolean(), 124 | paceCarClassId: z.null(), 125 | paceCarId: z.null(), 126 | passwordProtected: z.boolean(), 127 | pitsInUse: z.number(), 128 | populated: z.boolean(), 129 | practiceLength: z.number(), 130 | privateSessionId: z.number(), 131 | qualifierMustStartRace: z.boolean(), 132 | qualifyLaps: z.number(), 133 | qualifyLength: z.number(), 134 | raceLaps: z.number(), 135 | raceLength: z.number(), 136 | restarts: z.number(), 137 | restrictResults: z.boolean(), 138 | restrictViewing: z.boolean(), 139 | rollingStarts: z.boolean(), 140 | sessionDesc: z.union([z.null(), z.string()]).optional(), 141 | sessionFull: z.boolean(), 142 | sessionId: z.number(), 143 | sessionName: z.string(), 144 | sessionType: z.number(), 145 | sessionTypes: z.array(SessionTypeSchema), 146 | shortParadeLap: z.boolean(), 147 | startOnQualTire: z.boolean(), 148 | startZone: z.boolean(), 149 | status: z.number(), 150 | subsessionId: z.number(), 151 | teamEntryCount: z.number(), 152 | telemetryForceToDisk: z.number(), 153 | telemetryRestriction: z.number(), 154 | timeLimit: z.number(), 155 | track: LeagueTrackSchema, 156 | trackState: TrackStateSchema, 157 | trackTypes: z.array(TrackTypeSchema), 158 | unsportConductRuleMode: z.number(), 159 | warmupLength: z.number(), 160 | watched: z.array(z.any()), 161 | weather: WeatherSchema, 162 | }) 163 | export type Session = z.infer 164 | 165 | export const CustLeagueSessionsSchema = z.object({ 166 | mine: z.boolean(), 167 | sequence: z.number(), 168 | sessions: z.array(SessionSchema), 169 | subscribed: z.boolean(), 170 | success: z.boolean(), 171 | }) 172 | export type CustLeagueSessions = z.infer 173 | 174 | export const OwnerSchema = z.object({ 175 | carNumber: z.null(), 176 | custId: z.number(), 177 | displayName: z.string(), 178 | helmet: HelmetSchema, 179 | nickName: z.null(), 180 | }) 181 | export type Owner = z.infer 182 | 183 | export const ResultsPageSchema = z.object({ 184 | about: z.union([z.null(), z.string()]).optional(), 185 | created: z.string(), 186 | isAdmin: z.boolean(), 187 | isMember: z.boolean(), 188 | leagueId: z.number(), 189 | leagueName: z.string(), 190 | owner: OwnerSchema, 191 | ownerId: z.number(), 192 | pendingApplication: z.boolean(), 193 | pendingInvitation: z.boolean(), 194 | recruiting: z.boolean(), 195 | rosterCount: z.number(), 196 | url: z.union([z.null(), z.string()]).optional(), 197 | }) 198 | export type ResultsPage = z.infer 199 | 200 | export const LeagueDirectorySchema = z.object({ 201 | resultsPage: z.array(ResultsPageSchema), 202 | success: z.boolean(), 203 | lowerbound: z.number(), 204 | upperbound: z.number(), 205 | rowCount: z.number(), 206 | }) 207 | export type LeagueDirectory = z.infer 208 | 209 | // Params 210 | 211 | export const GetCustLeagueSessionsParamsSchema = z.object({ 212 | mine: z.boolean().optional(), 213 | packageId: z.number().optional(), 214 | }) 215 | export type GetCustLeagueSessionsParams = z.infer< 216 | typeof GetCustLeagueSessionsParamsSchema 217 | > 218 | 219 | export const GetLeagueDirectoryParamsSchema = z.object({ 220 | lowerbound: z.number().optional(), 221 | maximumRosterCount: z.number().optional(), 222 | minimumRosterCount: z.number().optional(), 223 | order: z.string().optional(), 224 | restrictToFriends: z.boolean().optional(), 225 | restrictToMember: z.boolean().optional(), 226 | restrictToRecruiting: z.boolean().optional(), 227 | restrictToWatched: z.boolean().optional(), 228 | search: z.string().optional(), 229 | sort: z.string().optional(), 230 | tag: z.string().optional(), 231 | upperbound: z.number().optional(), 232 | }) 233 | export type GetLeagueDirectoryParams = z.infer< 234 | typeof GetLeagueDirectoryParamsSchema 235 | > 236 | 237 | export const GetLeagueDataParamsSchema = z.object({ 238 | leagueId: z.number(), 239 | includeLicenses: z.boolean().optional(), 240 | }) 241 | export type GetLeagueDataParams = z.infer 242 | 243 | export const GetLeaguePointSystemParamsSchema = z.object({ 244 | leagueId: z.number(), 245 | seasonId: z.number().optional(), 246 | }) 247 | export type GetLeaguePointSystemParams = z.infer< 248 | typeof GetLeaguePointSystemParamsSchema 249 | > 250 | 251 | export const getLeagueMembershipParamsSchema = z.object({ 252 | customerId: z.number().optional(), 253 | includeLeague: z.boolean().optional(), 254 | }) 255 | export type GetLeagueMembershipParams = z.infer< 256 | typeof getLeagueMembershipParamsSchema 257 | > 258 | 259 | export const GetLeagueSeasonsParamsSchema = z.object({ 260 | leagueId: z.number(), 261 | retired: z.boolean().optional(), 262 | }) 263 | export type GetLeagueSeasonsParams = z.infer< 264 | typeof GetLeagueSeasonsParamsSchema 265 | > 266 | 267 | export const GetLeagueSeasonStandingsParamsSchema = z.object({ 268 | carClassId: z.number().optional(), 269 | carId: z.number().optional(), 270 | leagueId: z.number(), 271 | seasonId: z.number(), 272 | }) 273 | export type GetLeagueSeasonStandingsParams = z.infer< 274 | typeof GetLeagueSeasonStandingsParamsSchema 275 | > 276 | 277 | export const GetLeagueSeasonSessionsParamsSchema = z.object({ 278 | leagueId: z.number(), 279 | resultsOnly: z.boolean().optional(), 280 | seasonId: z.number(), 281 | }) 282 | export type GetLeagueSeasonSessionsParams = z.infer< 283 | typeof GetLeagueSeasonSessionsParamsSchema 284 | > 285 | 286 | export const GetLeagueRosterParamsSchema = z.object({ 287 | leagueId: z.number(), 288 | includeLicenses: z.boolean().optional(), 289 | }) 290 | export type GetLeagueRosterParams = z.infer 291 | -------------------------------------------------------------------------------- /packages/iracing-api/src/types/series.ts: -------------------------------------------------------------------------------- 1 | import * as z from 'zod' 2 | 3 | import { 4 | CarTypeSchema, 5 | CategorySchema, 6 | HeatSesInfoSchema, 7 | LicenseGroupTypeSchema, 8 | TrackTypeSchema, 9 | WeatherSchema, 10 | } from './common' 11 | 12 | export const SeriesAssetSchema = z.object({ 13 | largeImage: z.null(), 14 | logo: z.string(), 15 | seriesCopy: z.string(), 16 | seriesId: z.number(), 17 | smallImage: z.null(), 18 | }) 19 | export type SeriesAsset = z.infer 20 | 21 | export const SeriesAssetsSchema = z.record(SeriesAssetSchema) 22 | export type SeriesAssets = z.infer 23 | 24 | export const GroupNameSchema = z.enum([ 25 | 'Class A', 26 | 'Class B', 27 | 'Class C', 28 | 'Class D', 29 | 'Pro', 30 | 'Pro/WC', 31 | 'Rookie', 32 | ]) 33 | export type GroupName = z.infer 34 | 35 | export const AllowedLicenseSchema = z.object({ 36 | groupName: GroupNameSchema, 37 | licenseGroup: z.number(), 38 | maxLicenseLevel: z.number(), 39 | minLicenseLevel: z.number(), 40 | parentId: z.number().optional(), 41 | }) 42 | export type AllowedLicense = z.infer 43 | 44 | export const SeriesDataSchema = z.object({ 45 | allowedLicenses: z.array(AllowedLicenseSchema), 46 | category: CategorySchema, 47 | categoryId: z.number(), 48 | eligible: z.boolean(), 49 | forumUrl: z.union([z.null(), z.string()]).optional(), 50 | maxStarters: z.number(), 51 | minStarters: z.number(), 52 | ovalCautionType: z.number(), 53 | roadCautionType: z.number(), 54 | seriesId: z.number(), 55 | seriesName: z.string(), 56 | seriesShortName: z.string(), 57 | searchFilters: z.union([z.null(), z.string()]).optional(), 58 | }) 59 | export type SeriesData = z.infer 60 | 61 | export const SeriesTrackSchema = z.object({ 62 | trackId: z.number(), 63 | trackName: z.string(), 64 | configName: z.union([z.null(), z.string()]).optional(), 65 | categoryId: z.union([z.null(), z.number()]).optional(), 66 | category: z.union([z.null(), z.string()]).optional(), 67 | }) 68 | export type SeriesTrack = z.infer 69 | 70 | export const RaceWeekSchema = z.object({ 71 | seasonId: z.number(), 72 | raceWeekNum: z.number(), 73 | track: SeriesTrackSchema, 74 | }) 75 | export type RaceWeek = z.infer 76 | 77 | export const SeriesCarClassSchema = z.object({ 78 | carClassId: z.number(), 79 | shortName: z.string(), 80 | name: z.string(), 81 | relativeSpeed: z.number(), 82 | }) 83 | export type SeriesCarClass = z.infer 84 | 85 | export const SeasonSchema = z.object({ 86 | seasonId: z.number(), 87 | seriesId: z.number(), 88 | seasonName: z.string(), 89 | seasonShortName: z.string(), 90 | seasonYear: z.number(), 91 | seasonQuarter: z.number(), 92 | active: z.boolean(), 93 | official: z.boolean(), 94 | driverChanges: z.boolean(), 95 | fixedSetup: z.boolean(), 96 | licenseGroup: z.number(), 97 | hasSupersessions: z.boolean().optional(), 98 | licenseGroupTypes: z.array(LicenseGroupTypeSchema), 99 | carClasses: z.array(SeriesCarClassSchema), 100 | raceWeeks: z.array(RaceWeekSchema), 101 | }) 102 | export type Season = z.infer 103 | 104 | export const SeriesStatSchema = z.object({ 105 | seriesId: z.number(), 106 | seriesName: z.string(), 107 | seriesShortName: z.string(), 108 | categoryId: z.number(), 109 | category: CategorySchema, 110 | active: z.boolean(), 111 | official: z.boolean(), 112 | fixedSetup: z.boolean(), 113 | logo: z.union([z.null(), z.string()]), 114 | licenseGroup: z.number(), 115 | licenseGroupTypes: z.array(LicenseGroupTypeSchema), 116 | allowedLicenses: z.array(AllowedLicenseSchema), 117 | seasons: z.array(SeasonSchema), 118 | searchFilters: z.union([z.null(), z.string()]).optional(), 119 | }) 120 | export type SeriesStat = z.infer 121 | 122 | export const SeriesTrackStateSchema = z.object({ 123 | leaveMarbles: z.boolean(), 124 | practiceRubber: z.union([z.number(), z.null()]).optional(), 125 | }) 126 | export type SeriesTrackState = z.infer 127 | 128 | export const RaceTimeDescriptorSchema = z.object({ 129 | repeating: z.boolean(), 130 | superSession: z.boolean(), 131 | sessionMinutes: z.number(), 132 | sessionTimes: z.union([z.array(z.string()), z.null()]).optional(), 133 | startDate: z.union([z.null(), z.string()]).optional(), 134 | dayOffset: z.union([z.array(z.number()), z.null()]).optional(), 135 | firstSessionTime: z.union([z.null(), z.string()]).optional(), 136 | repeatMinutes: z.union([z.number(), z.null()]).optional(), 137 | }) 138 | export type RaceTimeDescriptor = z.infer 139 | 140 | export const CarRestrictionSchema = z.object({ 141 | carId: z.number(), 142 | raceSetupId: z.union([z.number(), z.null()]).optional(), 143 | maxPctFuelFill: z.number(), 144 | weightPenaltyKg: z.number(), 145 | powerAdjustPct: z.number(), 146 | maxDryTireSets: z.number(), 147 | qualSetupId: z.union([z.number(), z.null()]).optional(), 148 | }) 149 | export type CarRestriction = z.infer 150 | 151 | export const ScheduleSchema = z.object({ 152 | carRestrictions: z.array(CarRestrictionSchema), 153 | category: CategorySchema, 154 | categoryId: z.number(), 155 | enablePitlaneCollisions: z.boolean(), 156 | fullCourseCautions: z.boolean(), 157 | qualAttached: z.boolean(), 158 | raceLapLimit: z.union([z.number(), z.null()]), 159 | raceTimeDescriptors: z.array(RaceTimeDescriptorSchema), 160 | raceTimeLimit: z.union([z.number(), z.null()]), 161 | raceWeekNum: z.number(), 162 | restartType: z.string(), 163 | scheduleName: z.string(), 164 | seasonId: z.number(), 165 | seasonName: z.string(), 166 | seriesId: z.number(), 167 | seriesName: z.string(), 168 | shortParadeLap: z.boolean(), 169 | simulatedTimeMultiplier: z.number(), 170 | specialEventType: z.null(), 171 | startDate: z.string(), 172 | startType: z.string(), 173 | startZone: z.boolean(), 174 | track: SeriesTrackSchema, 175 | trackState: SeriesTrackStateSchema, 176 | weather: WeatherSchema, 177 | }) 178 | export type Schedule = z.infer 179 | 180 | export const SeriesHeatSesInfoSchema = z.intersection( 181 | HeatSesInfoSchema, 182 | z.object({ description: z.string() }) 183 | ) 184 | export type SeriesHeatSesInfo = z.infer 185 | 186 | export const AllowedSeasonMemberSchema = z.object({ 187 | seasonId: z.number(), 188 | custId: z.number(), 189 | displayName: z.string(), 190 | carId: z.number(), 191 | carNum: z.string(), 192 | }) 193 | export type AllowedSeasonMember = z.infer 194 | 195 | export const SeriesSeasonSchema = z.object({ 196 | active: z.boolean(), 197 | allowedSeasonMembers: z.union([ 198 | z.record(z.string(), AllowedSeasonMemberSchema), 199 | z.null(), 200 | ]), 201 | carClassIds: z.array(z.number()), 202 | carTypes: z.array(CarTypeSchema), 203 | cautionLapsDoNotCount: z.boolean(), 204 | complete: z.boolean(), 205 | crossLicense: z.boolean(), 206 | driverChangeRule: z.number(), 207 | driverChanges: z.boolean(), 208 | drops: z.number(), 209 | enablePitlaneCollisions: z.boolean(), 210 | fixedSetup: z.boolean(), 211 | greenWhiteCheckeredLimit: z.number(), 212 | gridByClass: z.boolean(), 213 | hardcoreLevel: z.number(), 214 | heatSesInfo: z.union([SeriesHeatSesInfoSchema, z.null()]).optional(), 215 | ignoreLicenseForPractice: z.boolean(), 216 | incidentLimit: z.number(), 217 | incidentWarnMode: z.number(), 218 | incidentWarnParam1: z.number(), 219 | incidentWarnParam2: z.number(), 220 | isHeatRacing: z.boolean(), 221 | licenseGroup: z.number(), 222 | licenseGroupTypes: z.array(LicenseGroupTypeSchema), 223 | luckyDog: z.boolean(), 224 | maxTeamDrivers: z.number(), 225 | maxWeeks: z.number(), 226 | minTeamDrivers: z.number(), 227 | multiclass: z.boolean(), 228 | mustUseDiffTireTypesInRace: z.boolean(), 229 | nextRaceSession: z.null(), 230 | numOptLaps: z.number(), 231 | official: z.boolean(), 232 | opDuration: z.number(), 233 | openPracticeSessionTypeId: z.number(), 234 | qualifierMustStartRace: z.boolean(), 235 | racePoints: z.union([z.number(), z.null()]).optional(), 236 | raceWeek: z.number(), 237 | raceWeekToMakeDivisions: z.number(), 238 | regOpenMinutes: z.union([z.number(), z.null()]).optional(), 239 | regUserCount: z.number(), 240 | regionCompetition: z.boolean(), 241 | restrictByMember: z.boolean(), 242 | restrictToCar: z.boolean(), 243 | restrictViewing: z.boolean(), 244 | rookieSeason: z.union([z.null(), z.string()]).optional(), 245 | scheduleDescription: z.string(), 246 | schedules: z.array(ScheduleSchema), 247 | seasonId: z.number(), 248 | seasonName: z.string(), 249 | seasonQuarter: z.number(), 250 | seasonShortName: z.string(), 251 | seasonYear: z.number(), 252 | sendToOpenPractice: z.boolean(), 253 | seriesId: z.number(), 254 | shortParadeLap: z.boolean(), 255 | startDate: z.string(), 256 | startOnQualTire: z.boolean(), 257 | startZone: z.boolean(), 258 | trackTypes: z.array(TrackTypeSchema), 259 | unsportConductRuleMode: z.number(), 260 | }) 261 | export type SeriesSeason = z.infer 262 | 263 | // Params 264 | 265 | export const getSeriesPastSeasonsParamsSchema = z.object({ 266 | seriesId: z.number(), 267 | }) 268 | export type GetSeriesPastSeasonsParams = z.infer< 269 | typeof getSeriesPastSeasonsParamsSchema 270 | > 271 | export const GetSeriesSeasonsParamSchema = z.object({ 272 | includeSeries: z.boolean().optional(), 273 | }) 274 | export type GetSeriesSeasonsParams = z.infer 275 | 276 | export const GetSeriesPastSeasonsResponseSchema = z.object({ 277 | success: z.boolean(), 278 | series: SeriesStatSchema, 279 | seriesId: z.number(), 280 | }) 281 | export type GetSeriesPastSeasonsResponse = z.infer< 282 | typeof GetSeriesPastSeasonsResponseSchema 283 | > 284 | -------------------------------------------------------------------------------- /packages/iracing-api/src/types/stats.ts: -------------------------------------------------------------------------------- 1 | import * as z from 'zod' 2 | import { HelmetSchema } from './common' 3 | import { BasicLiverySchema } from './results' 4 | 5 | export const CarsDrivenSchema = z.object({ 6 | carId: z.number(), 7 | carName: z.string(), 8 | }) 9 | export type CarsDriven = z.infer 10 | 11 | export const StatsTrackSchema = z.object({ 12 | trackId: z.number(), 13 | trackName: z.string(), 14 | configName: z.string(), 15 | }) 16 | export type StatsTrack = z.infer 17 | 18 | export const BestSchema = z.object({ 19 | track: StatsTrackSchema, 20 | eventType: z.string(), 21 | bestLapTime: z.number(), 22 | subsessionId: z.number(), 23 | endTime: z.string(), 24 | seasonYear: z.number(), 25 | seasonQuarter: z.number(), 26 | }) 27 | export type Best = z.infer 28 | 29 | export const MemberBestsSchema = z.object({ 30 | carsDriven: z.array(CarsDrivenSchema), 31 | bests: z.array(BestSchema), 32 | custId: z.number(), 33 | carId: z.number(), 34 | }) 35 | export type MemberBests = z.infer 36 | 37 | export const MemberDivisionSchema = z.object({ 38 | division: z.number(), 39 | projected: z.boolean(), 40 | eventType: z.number(), 41 | success: z.boolean(), 42 | seasonId: z.number(), 43 | }) 44 | export type MemberDivision = z.infer 45 | 46 | export const RecentRaceTrackSchema = z.object({ 47 | trackId: z.number(), 48 | trackName: z.string(), 49 | }) 50 | export type RecentRaceTrack = z.infer 51 | 52 | export const RecentRaceSchema = z.object({ 53 | seasonId: z.number(), 54 | seriesId: z.number(), 55 | seriesName: z.string(), 56 | carId: z.number(), 57 | carClassId: z.number(), 58 | livery: BasicLiverySchema, 59 | licenseLevel: z.number(), 60 | sessionStartTime: z.string(), 61 | winnerGroupId: z.number(), 62 | winnerName: z.string(), 63 | winnerHelmet: HelmetSchema, 64 | winnerLicenseLevel: z.number(), 65 | startPosition: z.number(), 66 | finishPosition: z.number(), 67 | qualifyingTime: z.number(), 68 | laps: z.number(), 69 | lapsLed: z.number(), 70 | incidents: z.number(), 71 | clubPoints: z.number(), 72 | points: z.number(), 73 | strengthOfField: z.number(), 74 | subsessionId: z.number(), 75 | oldSubLevel: z.number(), 76 | newSubLevel: z.number(), 77 | oldiRating: z.number(), 78 | newiRating: z.number(), 79 | track: RecentRaceTrackSchema, 80 | dropRace: z.boolean(), 81 | seasonYear: z.number(), 82 | seasonQuarter: z.number(), 83 | raceWeekNum: z.number(), 84 | }) 85 | export type RecentRace = z.infer 86 | 87 | export const MemberRecentRacesSchema = z.object({ 88 | races: z.array(RecentRaceSchema), 89 | custId: z.number(), 90 | }) 91 | export type MemberRecentRaces = z.infer 92 | 93 | export const WorldRecordsChunkInfoSchema = z.object({ 94 | chunk_size: z.number(), 95 | num_chunks: z.number(), 96 | rows: z.number(), 97 | base_download_url: z.string(), 98 | chunk_file_names: z.array(z.string()), 99 | }) 100 | export type WorldRecordsChunkInfo = z.infer 101 | 102 | export const WorldRecordsDataSchema = z.object({ 103 | success: z.boolean(), 104 | car_id: z.number(), 105 | track_id: z.number(), 106 | chunk_info: WorldRecordsChunkInfoSchema, 107 | last_updated: z.string(), 108 | }) 109 | export type WorldRecordsData = z.infer 110 | 111 | export const WorldRecordsSchema = z.object({ 112 | type: z.literal('stats_world_records'), 113 | data: WorldRecordsDataSchema, 114 | }) 115 | export type WorldRecords = z.infer 116 | 117 | export const StatSchema = z.object({ 118 | categoryId: z.number(), 119 | category: z.string(), 120 | starts: z.number(), 121 | wins: z.number(), 122 | top5: z.number(), 123 | poles: z.number(), 124 | avgStartPosition: z.number(), 125 | avgFinishPosition: z.number(), 126 | laps: z.number(), 127 | lapsLed: z.number(), 128 | avgIncidents: z.number(), 129 | avgPoints: z.number(), 130 | winPercentage: z.number(), 131 | top5Percentage: z.number(), 132 | lapsLedPercentage: z.number(), 133 | totalClubPoints: z.number(), 134 | }) 135 | export type Stat = z.infer 136 | 137 | export const MemberCareerSchema = z.object({ 138 | stats: z.array(StatSchema), 139 | custId: z.number(), 140 | }) 141 | export type MemberCareer = z.infer 142 | 143 | export const FavoriteTrackSchema = z.object({ 144 | trackId: z.number(), 145 | trackName: z.string(), 146 | configName: z.string(), 147 | trackLogo: z.string(), 148 | }) 149 | export type FavoriteTrack = z.infer 150 | 151 | export const FavoriteCarSchema = z.object({ 152 | carId: z.number(), 153 | carName: z.string(), 154 | carImage: z.string(), 155 | }) 156 | export type FavoriteCar = z.infer 157 | 158 | export const StatsSchema = z.object({ 159 | starts: z.number(), 160 | wins: z.number(), 161 | top5: z.number(), 162 | avgStartPosition: z.number(), 163 | avgFinishPosition: z.number(), 164 | laps: z.number(), 165 | lapsLed: z.number(), 166 | favoriteCar: FavoriteCarSchema, 167 | favoriteTrack: FavoriteTrackSchema, 168 | }) 169 | export type Stats = z.infer 170 | 171 | export const MemberRecapSchema = z.object({ 172 | year: z.number(), 173 | stats: StatsSchema, 174 | success: z.boolean(), 175 | season: z.null(), 176 | custId: z.number(), 177 | }) 178 | export type MemberRecap = z.infer 179 | 180 | export const ThisYearSchema = z.object({ 181 | numOfficialSessions: z.number(), 182 | numLeagueSessions: z.number(), 183 | numOfficialWins: z.number(), 184 | numLeagueWins: z.number(), 185 | }) 186 | export type ThisYear = z.infer 187 | 188 | export const MemberSummarySchema = z.object({ 189 | thisYear: ThisYearSchema, 190 | custId: z.number(), 191 | }) 192 | export type MemberSummary = z.infer 193 | 194 | export const YearlyStatSchema = z.intersection( 195 | StatSchema, 196 | z.object({ 197 | year: z.number(), 198 | }) 199 | ) 200 | export type YearlyStat = z.infer 201 | 202 | export const MemberYearlyStatsSchema = z.object({ 203 | stats: z.array(YearlyStatSchema), 204 | custId: z.number(), 205 | }) 206 | export type MemberYearlyStats = z.infer 207 | 208 | // Params 209 | 210 | export const GetMemberBestsParamsSchema = z.object({ 211 | customerId: z.number().optional(), 212 | carId: z.number().optional(), 213 | }) 214 | export type GetMemberBestsParams = z.infer 215 | export const GetMemberCareerParamsSchema = z.object({ 216 | customerId: z.number().optional(), 217 | }) 218 | export type GetMemberCareerParams = z.infer 219 | export const GetMemberDivisionParamsSchema = z.object({ 220 | seasonId: z.number(), 221 | eventType: z.number(), 222 | }) 223 | export type GetMemberDivisionParams = z.infer< 224 | typeof GetMemberDivisionParamsSchema 225 | > 226 | export const GetMemberRecentRacesParamsSchema = z.object({ 227 | customerId: z.number().optional(), 228 | }) 229 | export type GetMemberRecentRacesParams = z.infer< 230 | typeof GetMemberRecentRacesParamsSchema 231 | > 232 | export const GetMemberRecapParamsSchema = z.object({ 233 | customerId: z.number().optional(), 234 | year: z.number().optional(), 235 | season: z.number().optional(), 236 | }) 237 | export type GetMemberRecapParams = z.infer 238 | export const GetMemberSummaryParamsSchema = z.object({ 239 | customerId: z.number().optional(), 240 | }) 241 | export type GetMemberSummaryParams = z.infer< 242 | typeof GetMemberSummaryParamsSchema 243 | > 244 | export const GetMemberYearlyStatsParamsSchema = z.object({ 245 | customerId: z.number().optional(), 246 | }) 247 | export type GetMemberYearlyStatsParams = z.infer< 248 | typeof GetMemberYearlyStatsParamsSchema 249 | > 250 | export const GetDriverSeasonStandingsParamsSchema = z.object({ 251 | seasonId: z.number(), 252 | carClassId: z.number(), 253 | clubId: z.number().optional(), 254 | division: z.number().optional(), 255 | raceWeekNumber: z.number().optional(), 256 | }) 257 | export type GetDriverSeasonStandingsParams = z.infer< 258 | typeof GetDriverSeasonStandingsParamsSchema 259 | > 260 | export const getSupersessionSeasonStandingsParamsSchema = z.object({ 261 | seasonId: z.number(), 262 | carClassId: z.number(), 263 | clubId: z.number().optional(), 264 | division: z.number().optional(), 265 | raceWeekNumber: z.number().optional(), 266 | }) 267 | export type GetSupersessionSeasonStandingsParams = z.infer< 268 | typeof getSupersessionSeasonStandingsParamsSchema 269 | > 270 | export const GetTeamSeasonStandingsParamsSchema = z.object({ 271 | seasonId: z.number(), 272 | carClassId: z.number(), 273 | raceWeekNumber: z.number().optional(), 274 | }) 275 | export type GetTeamSeasonStandingsParams = z.infer< 276 | typeof GetTeamSeasonStandingsParamsSchema 277 | > 278 | export const GetTimeTrialSeasonStandingsParamsSchema = z.object({ 279 | seasonId: z.number(), 280 | carClassId: z.number(), 281 | clubId: z.number().optional(), 282 | division: z.number().optional(), 283 | raceWeekNumber: z.number().optional(), 284 | }) 285 | export type GetTimeTrialSeasonStandingsParams = z.infer< 286 | typeof GetTimeTrialSeasonStandingsParamsSchema 287 | > 288 | export const GetTimeTrialSeasonResultsParamsSchema = z.object({ 289 | seasonId: z.number(), 290 | carClassId: z.number(), 291 | raceWeekNumber: z.number(), 292 | clubId: z.number().optional(), 293 | division: z.number().optional(), 294 | }) 295 | export type GetTimeTrialSeasonResultsParams = z.infer< 296 | typeof GetTimeTrialSeasonResultsParamsSchema 297 | > 298 | export const GetQualifySeasonResultsParamsSchema = z.object({ 299 | seasonId: z.number(), 300 | carClassId: z.number(), 301 | clubId: z.number().optional(), 302 | division: z.number().optional(), 303 | raceWeekNumber: z.number().optional(), 304 | }) 305 | export type GetQualifySeasonResultsParams = z.infer< 306 | typeof GetQualifySeasonResultsParamsSchema 307 | > 308 | export const GetWorldRecordsParamsSchema = z.object({ 309 | carId: z.number(), 310 | trackId: z.number(), 311 | seasonYear: z.number().optional(), 312 | seasonQuarter: z.number().optional(), 313 | }) 314 | export type GetWorldRecordsParams = z.infer 315 | -------------------------------------------------------------------------------- /packages/iracing-api/src/types/member.ts: -------------------------------------------------------------------------------- 1 | import * as z from 'zod' 2 | 3 | import { HelmetSchema } from './common' 4 | 5 | export const SuitSchema = z.object({ 6 | pattern: z.number(), 7 | color1: z.string(), 8 | color2: z.string(), 9 | color3: z.string(), 10 | bodyType: z.number(), 11 | }) 12 | export type Suit = z.infer 13 | 14 | export const RestrictionsSchema = z.object({}) 15 | export type Restrictions = z.infer 16 | 17 | export const DirtOvalSchema = z.object({ 18 | categoryId: z.number(), 19 | category: z.string(), 20 | licenseLevel: z.number(), 21 | safetyRating: z.number(), 22 | cpi: z.number(), 23 | irating: z.number(), 24 | ttRating: z.number(), 25 | mprNumRaces: z.number(), 26 | color: z.string(), 27 | groupName: z.string(), 28 | groupId: z.number(), 29 | proPromotable: z.boolean(), 30 | mprNumTts: z.number(), 31 | }) 32 | export type DirtOval = z.infer 33 | 34 | export const LicenseDetailSchema = z.object({ 35 | categoryId: z.number(), 36 | category: z.string(), 37 | categoryName: z.string(), 38 | licenseLevel: z.number(), 39 | safetyRating: z.number(), 40 | cpi: z.number(), 41 | irating: z.number(), 42 | ttRating: z.number(), 43 | mprNumRaces: z.number(), 44 | color: z.string(), 45 | groupName: z.string(), 46 | groupId: z.number(), 47 | proPromotable: z.boolean(), 48 | seq: z.number(), 49 | mprNumTts: z.number(), 50 | }) 51 | export type LicenseDetail = z.infer 52 | 53 | export const LicensesSchema = z.record(LicenseDetailSchema) 54 | export type Licenses = z.infer 55 | 56 | export const PackageSchema = z.object({ 57 | packageId: z.number(), 58 | contentIds: z.array(z.number()), 59 | }) 60 | export type Package = z.infer 61 | 62 | export const AccountSchema = z.object({ 63 | irDollars: z.number(), 64 | irCredits: z.number(), 65 | status: z.string(), 66 | countryRules: z.null().optional(), 67 | }) 68 | export type Account = z.infer 69 | 70 | export const MemberInfoSchema = z.object({ 71 | custId: z.number(), 72 | email: z.string().optional(), 73 | username: z.string().optional(), 74 | displayName: z.string(), 75 | firstName: z.string(), 76 | lastName: z.string(), 77 | onCarName: z.string(), 78 | memberSince: z.string(), 79 | lastTestTrack: z.number().optional(), 80 | lastTestCar: z.number().optional(), 81 | lastSeason: z.number(), 82 | flags: z.number(), 83 | clubId: z.number(), 84 | clubName: z.string(), 85 | connectionType: z.string(), 86 | downloadServer: z.string(), 87 | lastLogin: z.string().datetime(), 88 | readCompRules: z.string().datetime(), 89 | account: AccountSchema, 90 | helmet: HelmetSchema, 91 | suit: SuitSchema, 92 | licenses: LicensesSchema, 93 | carPackages: z.array(PackageSchema), 94 | trackPackages: z.array(PackageSchema), 95 | otherOwnedPackages: z.array(z.number()), 96 | dev: z.boolean(), 97 | alphaTester: z.boolean(), 98 | rainTester: z.boolean(), 99 | broadcaster: z.boolean(), 100 | restrictions: RestrictionsSchema, 101 | hasReadCompRules: z.boolean(), 102 | hasReadNda: z.boolean(), 103 | flagsHex: z.string(), 104 | hundredPctClub: z.boolean(), 105 | twentyPctDiscount: z.boolean(), 106 | raceOfficial: z.boolean().optional(), 107 | ai: z.boolean().optional(), 108 | bypassHostedPassword: z.boolean().optional(), 109 | readTc: z.string().datetime(), 110 | readPp: z.string().datetime(), 111 | hasReadTc: z.boolean(), 112 | hasReadPp: z.boolean(), 113 | hasAdditionalContent: z.boolean(), 114 | }) 115 | export type MemberInfo = z.infer 116 | 117 | export const MemberParticipationCreditSchema = z.object({ 118 | custId: z.number(), 119 | seasonId: z.number(), 120 | seriesId: z.number(), 121 | seriesName: z.string(), 122 | licenseGroup: z.number(), 123 | licenseGroupName: z.string(), 124 | participationCredits: z.number(), 125 | minWeeks: z.number(), 126 | weeks: z.number(), 127 | earnedCredits: z.number(), 128 | totalCredits: z.number(), 129 | }) 130 | export type MemberParticipationCredit = z.infer< 131 | typeof MemberParticipationCreditSchema 132 | > 133 | 134 | // Params 135 | 136 | export const GetMemberAwardsParamsSchema = z.object({ 137 | customerId: z.number().optional(), 138 | }) 139 | export type GetMemberAwardsParams = z.infer 140 | 141 | export const GetMemberChartDataParamsSchema = z.object({ 142 | customerId: z.number().optional(), 143 | categoryId: z.number(), 144 | chartType: z.number(), 145 | }) 146 | export type GetMemberChartDataParams = z.infer< 147 | typeof GetMemberChartDataParamsSchema 148 | > 149 | 150 | export const GetMemberDataParamsSchema = z.object({ 151 | customerIds: z.array(z.string()), 152 | includeLicenses: z.boolean().optional(), 153 | }) 154 | export type GetMemberDataParams = z.infer 155 | 156 | export const GetMemberProfileParamsSchema = z.object({ 157 | customerId: z.number().optional(), 158 | }) 159 | export type GetMemberProfileParams = z.infer< 160 | typeof GetMemberProfileParamsSchema 161 | > 162 | 163 | export const GetMemberAwardInstancesParamsSchema = z.object({ 164 | awardId: z.number(), 165 | customerId: z.number().optional(), 166 | }) 167 | export type GetMemberAwardInstancesParams = z.infer< 168 | typeof GetMemberAwardInstancesParamsSchema 169 | > 170 | 171 | // Response 172 | 173 | export const GetMemberAwardsDataSchema = z.object({ 174 | success: z.boolean(), 175 | cust_id: z.number(), 176 | award_count: z.number(), 177 | }) 178 | export type GetMemberAwardsData = z.infer 179 | 180 | export const GetMemberAwardsResponseSchema = z.object({ 181 | type: z.literal('member_awards'), 182 | data: GetMemberAwardsDataSchema, 183 | data_url: z.string().url(), 184 | }) 185 | export type GetMemberAwardsResponse = z.infer< 186 | typeof GetMemberAwardsResponseSchema 187 | > 188 | 189 | export const MemberChartDataPointSchema = z.object({ 190 | when: z.string(), // Appears to be just YYYY-MM-DD, not full datetime 191 | value: z.number(), 192 | }) 193 | export type MemberChartDataPoint = z.infer 194 | 195 | export const GetMemberChartDataResponseSchema = z.object({ 196 | blackout: z.boolean(), 197 | categoryId: z.number(), 198 | chartType: z.number(), 199 | data: z.array(MemberChartDataPointSchema), 200 | success: z.boolean(), 201 | custId: z.number(), 202 | }) 203 | export type GetMemberChartDataResponse = z.infer< 204 | typeof GetMemberChartDataResponseSchema 205 | > 206 | 207 | export const MemberDataEntrySchema = z.object({ 208 | custId: z.number(), 209 | displayName: z.string(), 210 | helmet: HelmetSchema, 211 | lastLogin: z.string().datetime(), 212 | memberSince: z.string(), // Date only string 213 | clubId: z.number(), 214 | clubName: z.string(), 215 | ai: z.boolean(), 216 | }) 217 | export type MemberDataEntry = z.infer 218 | 219 | export const GetMemberDataResponseSchema = z.object({ 220 | success: z.boolean(), 221 | custIds: z.array(z.number()), 222 | members: z.array(MemberDataEntrySchema), 223 | }) 224 | export type GetMemberDataResponse = z.infer 225 | 226 | // Response Schemas for GetMemberProfile 227 | export const RecentAwardSchema = z.object({ 228 | memberAwardId: z.number(), 229 | awardId: z.number(), 230 | achievement: z.boolean(), 231 | awardCount: z.number(), 232 | awardDate: z.string(), // Date only 233 | awardOrder: z.number(), 234 | awardedDescription: z.string(), 235 | description: z.string(), 236 | groupName: z.string(), 237 | hasPdf: z.boolean(), 238 | iconUrlLarge: z.string(), 239 | iconUrlSmall: z.string(), 240 | iconUrlUnawarded: z.string(), 241 | name: z.string(), 242 | progress: z.number().optional(), 243 | progressLabel: z.string().optional(), 244 | threshold: z.number().optional(), 245 | subsessionId: z.number().optional(), 246 | viewed: z.boolean(), 247 | weight: z.number(), 248 | }) 249 | export type RecentAward = z.infer 250 | 251 | export const ActivitySchema = z.object({ 252 | recent30daysCount: z.number(), 253 | prev30daysCount: z.number(), 254 | consecutiveWeeks: z.number(), 255 | mostConsecutiveWeeks: z.number(), 256 | }) 257 | export type Activity = z.infer 258 | 259 | export const MemberProfileInfoSchema = z.object({ 260 | custId: z.number(), 261 | displayName: z.string(), 262 | helmet: HelmetSchema, 263 | lastLogin: z.string().datetime(), 264 | memberSince: z.string(), // Date only 265 | clubId: z.number(), 266 | clubName: z.string(), 267 | ai: z.boolean(), 268 | licenses: z.array(LicenseDetailSchema), // Array of existing LicenseDetailSchema 269 | country: z.string(), 270 | countryCode: z.string(), 271 | }) 272 | export type MemberProfileInfo = z.infer 273 | 274 | export const LicenseHistoryEntrySchema = z.object({ 275 | categoryId: z.number(), 276 | category: z.string(), 277 | categoryName: z.string(), 278 | licenseLevel: z.number(), 279 | safetyRating: z.number(), 280 | cpi: z.number(), 281 | irating: z.number(), 282 | ttRating: z.number(), 283 | color: z.string(), 284 | groupName: z.string(), 285 | groupId: z.number(), 286 | seq: z.number(), 287 | }) 288 | export type LicenseHistoryEntry = z.infer 289 | 290 | export const RecentEventTrackSchema = z.object({ 291 | configName: z.string(), 292 | trackId: z.number(), 293 | trackName: z.string(), 294 | }) 295 | export type RecentEventTrack = z.infer 296 | 297 | export const RecentEventSchema = z.object({ 298 | eventType: z.string(), 299 | subsessionId: z.number(), 300 | startTime: z.string().datetime(), 301 | eventId: z.number(), 302 | eventName: z.string(), 303 | simsessionType: z.number(), 304 | startingPosition: z.number(), 305 | finishPosition: z.number(), 306 | bestLapTime: z.number(), 307 | percentRank: z.number(), 308 | carId: z.number(), 309 | carName: z.string(), 310 | logoUrl: z.string().nullable(), 311 | track: RecentEventTrackSchema, 312 | }) 313 | export type RecentEvent = z.infer 314 | 315 | export const FollowCountsSchema = z.object({ 316 | followers: z.number(), 317 | follows: z.number(), 318 | }) 319 | export type FollowCounts = z.infer 320 | 321 | export const GetMemberProfileResponseSchema = z.object({ 322 | recentAwards: z.array(RecentAwardSchema), 323 | activity: ActivitySchema, 324 | success: z.boolean(), 325 | imageUrl: z.string().url(), 326 | memberInfo: MemberProfileInfoSchema, 327 | disabled: z.boolean(), 328 | licenseHistory: z.array(LicenseHistoryEntrySchema), 329 | recentEvents: z.array(RecentEventSchema), 330 | custId: z.number(), 331 | isGenericImage: z.boolean(), 332 | followCounts: FollowCountsSchema, 333 | }) 334 | export type GetMemberProfileResponse = z.infer< 335 | typeof GetMemberProfileResponseSchema 336 | > 337 | -------------------------------------------------------------------------------- /packages/iracing-api/src/api/stats.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import { 3 | GetDriverSeasonStandingsParams, 4 | GetMemberBestsParams, 5 | GetMemberCareerParams, 6 | GetMemberDivisionParams, 7 | GetMemberRecapParams, 8 | GetMemberRecentRacesParams, 9 | GetMemberSummaryParams, 10 | GetMemberYearlyStatsParams, 11 | GetQualifySeasonResultsParams, 12 | GetSupersessionSeasonStandingsParams, 13 | GetTeamSeasonStandingsParams, 14 | GetTimeTrialSeasonResultsParams, 15 | GetTimeTrialSeasonStandingsParams, 16 | GetWorldRecordsParams, 17 | MemberBests, 18 | MemberCareer, 19 | MemberRecap, 20 | MemberSummary, 21 | MemberYearlyStats, 22 | MemberDivision, 23 | MemberRecentRaces, 24 | WorldRecords, 25 | } from '../types' 26 | 27 | /** 28 | * Provides methods for interacting with member statistics endpoints. 29 | */ 30 | export class StatsAPI extends API { 31 | /** 32 | * Get member's best lap times for specified car at various tracks. 33 | * 34 | * @param {GetMemberBestsParams} [params] - Optional parameters. 35 | * @param {number} [params.customerId] - Customer ID. Defaults to the authenticated member. 36 | * @param {number} [params.carId] - Car ID. First call should omit this; use `carsDriven` list in response for subsequent calls. 37 | * 38 | * @returns A promise resolving to the member's best lap times data, or undefined on error. 39 | */ 40 | getMemberBests = async (params?: GetMemberBestsParams) => 41 | await this._getData('data/stats/member_bests', { 42 | cust_id: params?.customerId, 43 | car_id: params?.carId, 44 | }) 45 | /** 46 | * Get career statistics for a member across different categories. 47 | * 48 | * @param {GetMemberCareerParams} [params] - Optional parameters. 49 | * @param {number} [params.customerId] - Customer ID. Defaults to the authenticated member. 50 | * 51 | * @returns A promise resolving to the member's career stats, or undefined on error. 52 | */ 53 | getMemberCareer = async (params?: GetMemberCareerParams) => 54 | await this._getData('data/stats/member_career', { 55 | cust_id: params?.customerId, 56 | }) 57 | /** 58 | * Get the division for the **authenticated** member in a specific season and event type. 59 | * 60 | * Note: Divisions are 0-based (0=Division 1, 10=Rookie). 61 | * 62 | * @param {GetMemberDivisionParams} params - Parameters for the request. 63 | * @param {number} params.seasonId - The ID of the season. 64 | * @param {number} params.eventType - Event type code (4=Time Trial, 5=Race). 65 | * 66 | * @returns A promise resolving to the member's division data, or undefined on error. 67 | */ 68 | getMemberDivision = async (params: GetMemberDivisionParams) => 69 | await this._getData('data/stats/member_division', { 70 | season_id: params.seasonId, 71 | event_type: params.eventType, 72 | }) 73 | /** 74 | * Get a list of the member's most recent races. 75 | * 76 | * @param {GetMemberRecentRacesParams} [params] - Optional parameters. 77 | * @param {number} [params.customerId] - Customer ID. Defaults to the authenticated member. 78 | * 79 | * @returns A promise resolving to the list of recent races, or undefined on error. 80 | */ 81 | getMemberRecentRaces = async (params?: GetMemberRecentRacesParams) => 82 | await this._getData( 83 | 'data/stats/member_recent_races', 84 | { 85 | cust_id: params?.customerId, 86 | } 87 | ) 88 | /** 89 | * Get a recap of a member's statistics for a specific year or season. 90 | * 91 | * @param {GetMemberRecapParams} [params] - Optional parameters. 92 | * @param {number} [params.customerId] - Customer ID. Defaults to the authenticated member. 93 | * @param {number} [params.year] - Year for the recap. Defaults to the current calendar year (UTC). 94 | * @param {number} [params.season] - Season (quarter) within the year. If omitted, recap is for the entire year. 95 | * 96 | * @returns A promise resolving to the member recap data, or undefined on error. 97 | */ 98 | getMemberRecap = async (params?: GetMemberRecapParams) => 99 | await this._getData('data/stats/member_recap', { 100 | cust_id: params?.customerId, 101 | year: params?.year, 102 | season: params?.season, 103 | }) 104 | /** 105 | * Get a summary of a member's participation (official vs. league) for the current year. 106 | * 107 | * @param {GetMemberSummaryParams} [params] - Optional parameters. 108 | * @param {number} [params.customerId] - Customer ID. Defaults to the authenticated member. 109 | * 110 | * @returns A promise resolving to the member summary data, or undefined on error. 111 | */ 112 | getMemberSummary = async (params?: GetMemberSummaryParams) => 113 | await this._getData('data/stats/member_summary', { 114 | cust_id: params?.customerId, 115 | }) 116 | /** 117 | * Get yearly statistics for a member. 118 | * 119 | * @param {GetMemberYearlyStatsParams} [params] - Optional parameters. 120 | * @param {number} [params.customerId] - Customer ID. Defaults to the authenticated member. 121 | * 122 | * @returns A promise resolving to the member's yearly stats, or undefined on error. 123 | */ 124 | getMemberYearlyStats = async (params?: GetMemberYearlyStatsParams) => 125 | await this._getData('data/stats/member_yearly', { 126 | cust_id: params?.customerId, 127 | }) 128 | /** 129 | * Get the driver standings for a specific season. 130 | * 131 | * @param {GetDriverSeasonStandingsParams} params - Parameters for the request. 132 | * @param {number} params.seasonId - The ID of the season. 133 | * @param {number} params.carClassId - The ID of the car class. 134 | * @param {number} [params.clubId=-1] - Filter by club ID. Defaults to all. 135 | * @param {number} [params.division] - Filter by division (0-based). Defaults to all. 136 | * @param {number} [params.raceWeekNumber] - Filter by race week number (0-based). Defaults to the latest completed week. 137 | * 138 | * @returns A promise resolving to the driver season standings data, or undefined on error. 139 | */ 140 | getDriverSeasonStandings = async (params: GetDriverSeasonStandingsParams) => 141 | await this._getData('data/stats/season_driver_standings', { 142 | season_id: params.seasonId, 143 | car_class_id: params.carClassId, 144 | club_id: params.clubId, 145 | division: params.division, 146 | race_week_num: params.raceWeekNumber, 147 | }) 148 | /** 149 | * Get the supersession standings for a specific season. 150 | * 151 | * @param {GetSupersessionSeasonStandingsParams} params - Parameters for the request. 152 | * @param {number} params.seasonId - The ID of the season. 153 | * @param {number} params.carClassId - The ID of the car class. 154 | * @param {number} [params.clubId=-1] - Filter by club ID. Defaults to all. 155 | * @param {number} [params.division] - Filter by division (0-based). Defaults to all. 156 | * @param {number} [params.raceWeekNumber] - Filter by race week number (0-based). Defaults to the latest completed week. 157 | * 158 | * @returns A promise resolving to the supersession standings data, or undefined on error. 159 | */ 160 | getSupersessionSeasonStandings = async ( 161 | params: GetSupersessionSeasonStandingsParams 162 | ) => 163 | await this._getData('data/stats/season_supersession_standings', { 164 | season_id: params.seasonId, 165 | car_class_id: params.carClassId, 166 | club_id: params.clubId, 167 | division: params.division, 168 | race_week_num: params.raceWeekNumber, 169 | }) 170 | /** 171 | * Get the team standings for a specific season. 172 | * 173 | * @param {GetTeamSeasonStandingsParams} params - Parameters for the request. 174 | * @param {number} params.seasonId - The ID of the season. 175 | * @param {number} params.carClassId - The ID of the car class. 176 | * @param {number} [params.raceWeekNumber] - Filter by race week number (0-based). Defaults to the latest completed week. 177 | * 178 | * @returns A promise resolving to the team season standings data, or undefined on error. 179 | */ 180 | getTeamSeasonStandings = async (params: GetTeamSeasonStandingsParams) => 181 | await this._getData('data/stats/season_team_standings', { 182 | season_id: params.seasonId, 183 | car_class_id: params.carClassId, 184 | race_week_num: params.raceWeekNumber, 185 | }) 186 | /** 187 | * Get the time trial results for a specific season. 188 | * 189 | * @param {GetTimeTrialSeasonResultsParams} params - Parameters for the request. 190 | * @param {number} params.seasonId - The ID of the season. 191 | * @param {number} params.carClassId - The ID of the car class. 192 | * @param {number} [params.clubId=-1] - Filter by club ID. Defaults to all. 193 | * @param {number} [params.division] - Filter by division (0-based). Defaults to all. 194 | * @param {number} [params.raceWeekNumber] - Filter by race week number (0-based). Defaults to the latest completed week. 195 | * 196 | * @returns A promise resolving to the time trial results data, or undefined on error. 197 | */ 198 | getTimeTrialSeasonResults = async ( 199 | params: GetTimeTrialSeasonResultsParams 200 | ) => 201 | await this._getData('data/stats/season_tt_results', { 202 | season_id: params.seasonId, 203 | car_class_id: params.carClassId, 204 | race_week_num: params.raceWeekNumber, 205 | club_id: params.clubId, 206 | division: params.division, 207 | }) 208 | /** 209 | * Get the time trial season standings. 210 | * 211 | * @param {GetTimeTrialSeasonStandingsParams} params - Parameters for the request. 212 | * @param {number} params.seasonId - The season ID to get the standings for. 213 | * @param {number} params.carClassId - The car class ID to get the standings for. 214 | * @param {number} [params.clubId=-1] - Filter by club ID. Defaults to all. 215 | * @param {number} [params.division] - Filter by division (0-based). Defaults to all. 216 | * @param {number} [params.raceWeekNumber] - Filter by race week number (0-based). 217 | * 218 | * @returns A promise resolving to the time trial season standings, or undefined on error. 219 | */ 220 | getTimeTrialSeasonStandings = async ( 221 | params: GetTimeTrialSeasonStandingsParams 222 | ) => 223 | await this._getData('data/stats/season_tt_standings', { 224 | season_id: params.seasonId, 225 | car_class_id: params.carClassId, 226 | club_id: params.clubId, 227 | division: params.division, 228 | race_week_num: params.raceWeekNumber, 229 | }) 230 | /** 231 | * Get the qualify results for a specific season. 232 | * 233 | * @param {GetQualifySeasonResultsParams} params - Parameters for the request. 234 | * @param {number} params.seasonId - The ID of the season. 235 | * @param {number} params.carClassId - The ID of the car class. 236 | * @param {number} [params.clubId=-1] - Filter by club ID. Defaults to all. 237 | * @param {number} [params.division] - Filter by division (0-based). Defaults to all. 238 | * @param {number} [params.raceWeekNumber] - Filter by race week number (0-based). Defaults to the latest completed week. 239 | * 240 | * @returns A promise resolving to the qualify results data, or undefined on error. 241 | */ 242 | getQualifySeasonStandings = async (params: GetQualifySeasonResultsParams) => 243 | await this._getData('data/stats/season_qualify_results', { 244 | season_id: params.seasonId, 245 | car_class_id: params.carClassId, 246 | race_week_num: params.raceWeekNumber, 247 | club_id: params.clubId, 248 | division: params.division, 249 | }) 250 | /** 251 | * Get world records for a specific car and track combination. 252 | * 253 | * @param {GetWorldRecordsParams} params - Parameters for the request. 254 | * @param {number} params.carId - The ID of the car. 255 | * @param {number} params.trackId - The ID of the track. 256 | * @param {number} [params.seasonYear] - Optional year to limit results. 257 | * @param {number} [params.seasonQuarter] - Optional quarter (1-4) to limit results (requires `seasonYear`). 258 | * 259 | * @returns A promise resolving to the world records data (chunked), or undefined on error. 260 | */ 261 | getWorldRecords = async (params: GetWorldRecordsParams) => 262 | await this._getData('data/stats/world_records', { 263 | car_id: params.carId, 264 | track_id: params.trackId, 265 | season_year: params.seasonYear, 266 | season_quarter: params.seasonQuarter, 267 | }) 268 | } 269 | -------------------------------------------------------------------------------- /packages/iracing-api/src/api/results.ts: -------------------------------------------------------------------------------- 1 | import { API } from './api' 2 | import { 3 | GetResultParams, 4 | GetResultResponse, 5 | GetResultsEventLogParams, 6 | GetResultsLapChartDataParams, 7 | GetResultsLapDataOptions, 8 | GetResultsLapDataParams, 9 | GetResultsLapDataResponse, 10 | GetResultsLapDataWithChunksResponse, 11 | GetSeasonResultsParams, 12 | GetSeasonResultsResponse, 13 | LapDataItem, 14 | SearchSeriesParams, 15 | SearchSeriesResponse, 16 | SearchHostedParams, 17 | SearchHostedResponse, 18 | GetResultsLapChartDataResponse, 19 | LapChartDataItem, 20 | EventLogItem, 21 | GetResultsEventLogResponse, 22 | GetResultsEventLogWithChunksResponse, 23 | } from '../types/results' 24 | 25 | /** 26 | * Provides methods for interacting with session result endpoints. 27 | */ 28 | export class ResultsAPI extends API { 29 | /** 30 | * Get the results of a specific subsession. 31 | * 32 | * Note: `series_logo` image paths in response are relative to `https://images-static.iracing.com/img/logos/series/`. 33 | * 34 | * @param {GetResultParams} params - Parameters for the request. 35 | * @param {number} params.subsessionId - The ID of the subsession. 36 | * @param {boolean} [params.includeLicenses=false] - Include license information in the response. 37 | * 38 | * @returns A promise resolving to the race result data, or undefined on error. 39 | */ 40 | getResult = async ( 41 | params: GetResultParams 42 | ): Promise => 43 | await this._getData('data/results/get', { 44 | subsession_id: params.subsessionId, 45 | include_licenses: params.includeLicenses, 46 | }) 47 | /** 48 | * Get the event log for a specific subsession and simsession. 49 | * 50 | * @param {GetResultsEventLogParams} params - Parameters for the request. 51 | * @param {number} params.subsessionId - The ID of the subsession. 52 | * @param {number} params.simsessionNumber - The simsession number (0 for main event, -1 for preceding, etc.). 53 | * @param {Object} [options] - Options for fetching data. 54 | * @param {boolean} [options.getAllChunks=false] - If true, fetch and combine data from all chunks (if applicable). 55 | * 56 | * @returns A promise resolving to the event log data, potentially combined from chunks, or throws an error if fetching fails. 57 | */ 58 | getResultsEventLog = async ( 59 | params: GetResultsEventLogParams, 60 | options?: { getAllChunks?: boolean } 61 | ): Promise< 62 | GetResultsEventLogResponse | GetResultsEventLogWithChunksResponse 63 | > => { 64 | const data = await this._getData( 65 | 'data/results/event_log', 66 | { 67 | subsession_id: params.subsessionId, 68 | simsession_number: params.simsessionNumber, 69 | } 70 | ) 71 | 72 | if (!data) { 73 | throw new Error('Failed to fetch event log data') 74 | } 75 | 76 | if (!options?.getAllChunks || !data.chunkInfo) return data 77 | 78 | const chunkData = await Promise.all( 79 | data.chunkInfo.chunkFileNames.map((chunkFileName: string) => { 80 | return this._getLinkData( 81 | `${data.chunkInfo!.baseDownloadUrl}${chunkFileName}` 82 | ) 83 | }) 84 | ) 85 | 86 | return { 87 | ...data, 88 | eventLog: chunkData.flatMap((chunk) => chunk as EventLogItem[]), 89 | } 90 | } 91 | /** 92 | * Get lap chart data for a specific subsession and simsession. 93 | * 94 | * @param {GetResultsLapChartDataParams} params - Parameters for the request. 95 | * @param {number} params.subsessionId - The ID of the subsession. 96 | * @param {number} params.simsessionNumber - The simsession number (0 for main event, -1 for preceding, etc.). 97 | * @param {Object} [options] - Options for fetching data. 98 | * @param {boolean} [options.getAllChunks=false] - If true, fetch and combine data from all chunks (if applicable). 99 | * 100 | * @returns A promise resolving to the lap chart data, potentially combined from chunks, or throws an error if fetching fails. 101 | */ 102 | getResultsLapChartData = async ( 103 | params: GetResultsLapChartDataParams, 104 | options?: { getAllChunks?: boolean } 105 | ) => { 106 | const data = await this._getData( 107 | 'data/results/lap_chart_data', 108 | { 109 | subsession_id: params.subsessionId, 110 | simsession_number: params.simsessionNumber, 111 | } 112 | ) 113 | 114 | if (!data) { 115 | throw new Error('Failed to fetch lap chart data') 116 | } 117 | 118 | if (!options?.getAllChunks) return data 119 | 120 | const chunkData = await Promise.all( 121 | data.chunkInfo?.chunkFileNames?.map((chunkFileName: string) => { 122 | return this._getLinkData( 123 | `${data.chunkInfo?.baseDownloadUrl}${chunkFileName}` 124 | ) 125 | }) ?? [] 126 | ) 127 | 128 | return { 129 | ...data, 130 | lapChartData: chunkData.flatMap( 131 | (chunk) => chunk as LapChartDataItem[] 132 | ), 133 | } 134 | } 135 | 136 | /** 137 | * Get lap data for a driver or team in a specific subsession and simsession. 138 | * 139 | * @param {GetResultsLapDataParams} params - Parameters for the request. 140 | * @param {number} params.subsessionId - The ID of the subsession. 141 | * @param {number} params.simsessionNumber - The simsession number (0 for main event, -1 for preceding, etc.). 142 | * @param {number} [params.customerId] - Required for single-driver events. Optional for team events (returns all team laps if omitted). 143 | * @param {number} [params.teamId] - Required for team events. 144 | * 145 | * @param {GetResultsLapDataOptions} [options] - Options for fetching data. 146 | * @param {boolean} [options.getAllChunks=false] - If true, fetch and combine data from all chunks (if applicable). 147 | * 148 | * @returns A promise resolving to the lap data, potentially combined from chunks, or throws an error if fetching fails. 149 | */ 150 | getResultsLapData = async ( 151 | params: GetResultsLapDataParams, 152 | options?: GetResultsLapDataOptions 153 | ): Promise< 154 | GetResultsLapDataResponse | GetResultsLapDataWithChunksResponse 155 | > => { 156 | const data = await this._getData( 157 | 'data/results/lap_data', 158 | { 159 | subsession_id: params.subsessionId, 160 | simsession_number: params.simsessionNumber, 161 | cust_id: params.customerId, 162 | team_id: params.teamId, 163 | } 164 | ) 165 | 166 | if (!data) { 167 | throw new Error('Failed to fetch lap data') 168 | } 169 | 170 | if (!options?.getAllChunks) return data 171 | 172 | const chunkData = await Promise.all( 173 | data.chunkInfo?.chunkFileNames?.map((chunkFileName: string) => { 174 | return this._getLinkData( 175 | `${data.chunkInfo?.baseDownloadUrl}${chunkFileName}` 176 | ) 177 | }) ?? [] 178 | ) 179 | 180 | return { 181 | ...data, 182 | lapData: chunkData.flatMap((chunk) => chunk as LapDataItem[]), 183 | } 184 | } 185 | 186 | /** 187 | * Search for hosted and league session results. 188 | * 189 | * Note: Maximum time frame is 90 days. Results may be split into chunks. 190 | * Requires one time range (`start_range_begin` or `finish_range_begin`). 191 | * Requires one identifier (`custId`, `teamId`, `hostCustId`, `sessionName`). 192 | * 193 | * @param {SearchHostedParams} [params] - Search parameters. 194 | * @param {string} [params.startRangeBegin] - Session start time range begin (ISO-8601 UTC). 195 | * @param {string} [params.startRangeEnd] - Session start time range end (ISO-8601 UTC, exclusive). 196 | * @param {string} [params.finishRangeBegin] - Session finish time range begin (ISO-8601 UTC). 197 | * @param {string} [params.finishRangeEnd] - Session finish time range end (ISO-8601 UTC, exclusive). 198 | * @param {number} [params.custId] - Participant's customer ID (ignored if `teamId` provided). 199 | * @param {number} [params.teamId] - Team ID (takes priority over `custId`). 200 | * @param {number} [params.hostCustId] - Host's customer ID. 201 | * @param {string} [params.sessionName] - Partial or full session name. 202 | * @param {number} [params.leagueId] - Filter by league ID. 203 | * @param {number} [params.leagueSeasonId] - Filter by league season ID. 204 | * @param {number} [params.carId] - Filter by car ID used in the session. 205 | * @param {number} [params.trackId] - Filter by track ID used in the session. 206 | * @param {number[]} [params.categoryIds] - Filter by track category IDs (defaults to all). 207 | * 208 | * @returns A promise resolving to the search results (possibly chunked), or undefined on error. 209 | */ 210 | searchHosted = async ( 211 | params?: SearchHostedParams 212 | ): Promise => 213 | await this._getData( 214 | 'data/results/search_hosted', 215 | { 216 | start_range_begin: params?.startRangeBegin, 217 | start_range_end: params?.startRangeEnd, 218 | finish_range_begin: params?.finishRangeBegin, 219 | finish_range_end: params?.finishRangeEnd, 220 | cust_id: params?.custId, 221 | team_id: params?.teamId, 222 | host_cust_id: params?.hostCustId, 223 | session_name: params?.sessionName, 224 | league_id: params?.leagueId, 225 | league_season_id: params?.leagueSeasonId, 226 | car_id: params?.carId, 227 | track_id: params?.trackId, 228 | category_ids: params?.categoryIds?.join(','), 229 | } 230 | ) 231 | /** 232 | * Search for official series results. 233 | * 234 | * Note: Maximum time frame is 90 days. Results may be split into chunks. 235 | * Requires at least one time filter (`season_year`/`season_quarter`, `start_range_begin`, or `finish_range_begin`). 236 | * 237 | * @param {SearchSeriesParams} [params] - Search parameters. 238 | * @param {number} [params.seasonYear] - Season year (requires `seasonQuarter`). 239 | * @param {number} [params.seasonQuarter] - Season quarter (requires `seasonYear`). 240 | * @param {string} [params.startRangeBegin] - Session start time range begin (ISO-8601 UTC). 241 | * @param {string} [params.startRangeEnd] - Session start time range end (ISO-8601 UTC, exclusive). 242 | * @param {string} [params.finishRangeBegin] - Session finish time range begin (ISO-8601 UTC). 243 | * @param {string} [params.finishRangeEnd] - Session finish time range end (ISO-8601 UTC, exclusive). 244 | * @param {number} [params.customerId] - Participant's customer ID (ignored if `teamId` provided). 245 | * @param {number} [params.teamId] - Team ID (takes priority over `customerId`). 246 | * @param {number} [params.seriesId] - Filter by series ID. 247 | * @param {number} [params.raceWeekNum] - Filter by race week number (0-based). 248 | * @param {boolean} [params.officialOnly=false] - Include only official sessions earning points. 249 | * @param {number[]} [params.eventTypes] - Filter by event type IDs (defaults to all). 250 | * @param {number[]} [params.categoryIds] - Filter by license category IDs (defaults to all). 251 | * 252 | * @returns A promise resolving to the search results (potentially combined from chunks), or the raw chunk info response if chunk fetching is not implemented/fails. 253 | */ 254 | searchSeries = async (params?: SearchSeriesParams) => { 255 | const responseData = await this._getData( 256 | 'data/results/search_series', 257 | { 258 | season_year: params?.seasonYear, 259 | season_quarter: params?.seasonQuarter, 260 | start_range_begin: params?.startRangeBegin, 261 | start_range_end: params?.startRangeEnd, 262 | finish_range_begin: params?.finishRangeBegin, 263 | finish_range_end: params?.finishRangeEnd, 264 | cust_id: params?.customerId, 265 | team_id: params?.teamId, 266 | series_id: params?.seriesId, 267 | race_week_num: params?.raceWeekNum, 268 | official_only: params?.officialOnly, 269 | event_types: params?.eventTypes?.join(','), 270 | category_ids: params?.categoryIds?.join(','), 271 | } 272 | ) 273 | 274 | if (!responseData?.data?.success || !responseData?.data?.chunk_info) { 275 | return responseData 276 | } 277 | 278 | const { 279 | data: { 280 | chunk_info: { base_download_url, chunk_file_names }, 281 | }, 282 | } = responseData 283 | 284 | const chunksData = await Promise.all( 285 | chunk_file_names.map(async (chunkFileName: string) => { 286 | return await this._getLinkData( 287 | `${base_download_url}${chunkFileName}` 288 | ) 289 | }) 290 | ) 291 | 292 | return chunksData.flatMap((chunk: unknown) => chunk as unknown[]) 293 | } 294 | 295 | /** 296 | * Get results for a specific season, optionally filtered by event type and race week. 297 | * 298 | * @param {GetSeasonResultsParams} params - Parameters for the request. 299 | * @param {number} params.seasonId - The ID of the season. 300 | * @param {number} [params.eventType] - Filter by event type ID (2=Practice, 3=Qualify, 4=Time Trial, 5=Race). 301 | * @param {number} [params.raceWeekNumber] - Filter by race week number (0-based). 302 | * 303 | * @returns A promise resolving to the season results data, or undefined on error. 304 | */ 305 | getSeasonResults = async (params: GetSeasonResultsParams) => 306 | await this._getData( 307 | 'data/results/season_results', 308 | { 309 | season_id: params.seasonId, 310 | event_type: params.eventType, 311 | race_week_num: params.raceWeekNumber, 312 | } 313 | ) 314 | } 315 | --------------------------------------------------------------------------------