UNPKG

@haelp/teto

Version:

A typescript-based controllable TETR.IO client.

1,227 lines (1,226 loc) 72.1 kB
declare const NodeError: ErrorConstructor; export declare namespace ChannelAPI { class Error extends NodeError { constructor(type: string, message: string); } const randomSessionID: (length?: number) => string; const getConfig: () => Types.Config; const setConfig: (newConfig: Partial<Types.Config>) => void; const clearCache: () => void; interface GetOptions { sessionID?: string | null; host?: string; } const get: <Res = any>({ route, args, query, options }: { route: string; args?: { data: { [k: string]: string; }; format: string[]; }; query?: { [k: string]: string; }; options?: GetOptions; }) => Promise<Res>; namespace generator { const empty: <Res extends object, ResKey extends keyof Res | undefined = undefined>(route: string, res?: ResKey) => () => Promise<ResKey extends undefined ? Res : Res[Extract<ResKey, keyof Res>]>; const args: <Req extends object, Res extends object, ArgValues extends any[], ResKey extends keyof Res | undefined = undefined>(route: string, res?: ResKey) => (...args: ArgValues | [Types.ArgsObject<Req>]) => Promise<ResKey extends undefined ? Res : Res[Extract<ResKey, keyof Res>]>; const query: <Res extends object, QueryParams extends object, ResKey extends keyof Res | undefined = undefined>(route: string, res?: ResKey) => (query?: QueryParams) => Promise<ResKey extends undefined ? Res : Res[Extract<ResKey, keyof Res>]>; const argsAndQuery: <Req extends object, Res extends object, QueryParams extends object, ArgValues extends any[], ResKey extends keyof Res | undefined = undefined>(route: string, res?: ResKey) => (...args: [...ArgValues, QueryParams] | ArgValues | [Types.ArgsObject<Req>, QueryParams] | [Types.ArgsObject<Req>]) => Promise<ResKey extends undefined ? Res : Res[Extract<ResKey, keyof Res>]>; } namespace general { namespace Stats { /** * Some statistics about the service. */ interface Response { /** * The amount of users on the server, including anonymous accounts. */ usercount: number; /** * The amount of users created a second (through the last minute). */ usercount_delta: number; /** * The amount of anonymous accounts on the server. */ anoncount: number; /** * The total amount of accounts ever created (including pruned anons etc.). */ totalaccounts: number; /** * The amount of ranked (visible in TETRA LEAGUE leaderboard) accounts on the server. */ rankedcount: number; /** * The amount of game records stored on the server. */ recordcount: number; /** * The amount of games played across all users, including both off- and online modes. */ gamesplayed: number; /** * The amount of games played a second (through the last minute). */ gamesplayed_delta: number; /** * The amount of games played across all users, including both off- and online modes, excluding games that were not completed (e.g. retries) */ gamesfinished: number; /** * The amount of seconds spent playing across all users, including both off- and online modes. */ gametime: number; /** * The amount of keys pressed across all users, including both off- and online modes. */ inputs: number; /** * The amount of pieces placed across all users, including both off- and online modes. */ piecesplaced: number; } } /** * Gets statistics about TETR.IO */ const stats: () => Promise<Stats.Response>; namespace Activity { /** * A graph of user activity over the last 2 days. A user is seen as active if they logged in or received XP within the last 30 minutes. */ interface Response { /** * An array of plot points, newest points first. */ activity: number[]; } interface Request { } } /** * Gets a graph of user activity over the last 2 days. A user is seen as active if they logged in or received XP within the last 30 minutes. */ const activity: () => Promise<number[]>; } namespace users { /** * An object describing the user in detail. */ interface Response extends ChannelAPI.Types.User { } interface Request { /** * The lowercase username or user ID to look up. */ user: string; } const get: { (user: string): Promise<Response>; ({ user }: { user: string; }): Promise<Response>; }; namespace summaries { namespace FourtyLines { /** * An object describing a summary of the user's 40 LINES games. */ interface Response extends ChannelAPI.Types.BaseSummaryResponse { } interface Request { /** * The lowercase username or user ID to look up. */ user: string; } } const fourtyLines: { (user: string): Promise<FourtyLines.Response>; ({ user }: { user: string; }): Promise<FourtyLines.Response>; }; namespace Blitz { /** * An object describing a summary of the user's BLITZ games. */ interface Response extends ChannelAPI.Types.BaseSummaryResponse { } interface Request { /** * The lowercase username or user ID to look up. */ user: string; } } const blitz: { (user: string): Promise<Blitz.Response>; ({ user }: { user: string; }): Promise<Blitz.Response>; }; namespace QuickPlay { interface Request { /** * The lowercase username or user ID to look up. */ user: string; } /** * An object describing a summary of the user's QUICK PLAY games. */ interface Response extends ChannelAPI.Types.BaseSummaryResponse { /** * The user's career best: */ best: { /** * The user's best record, or null if the user hasn't placed one yet. */ record?: ChannelAPI.Types.Record; /** * The rank said record had in global leaderboards at the end of the week, or -1 if it was not ranked. */ rank: number; }; } } const quickPlay: { (user: string): Promise<QuickPlay.Response>; ({ user }: { user: string; }): Promise<QuickPlay.Response>; }; /** Alias of quickPlay */ const zenith: { (user: string): Promise<QuickPlay.Response>; ({ user }: { user: string; }): Promise<QuickPlay.Response>; }; namespace ExpertQuickPlay { /** * An object describing a summary of the user's EXPERT QUICK PLAY games. */ interface Response extends ChannelAPI.Types.BaseSummaryResponse { /** * The user's career best: */ best: { /** * The user's best record, or null if the user hasn't placed one yet. */ record?: ChannelAPI.Types.Record; /** * The rank said record had in global leaderboards at the end of the week, or -1 if it was not ranked. */ rank: number; }; } interface Request { /** * The lowercase username or user ID to look up. */ user: string; } } const expertQuickPlay: { (user: string): Promise<ExpertQuickPlay.Response>; ({ user }: { user: string; }): Promise<ExpertQuickPlay.Response>; }; /** Alias of expertQuickPlay */ const zenthiex: { (user: string): Promise<ExpertQuickPlay.Response>; ({ user }: { user: string; }): Promise<ExpertQuickPlay.Response>; }; namespace TetraLeague { /** * An object describing a summary of the user's TETRA LEAGUE standing. */ interface Response { gamesplayed: number; gameswon: number; glicko: number; rd?: number; decaying: boolean; tr: number; gxe: number; rank: string; bestrank?: string; apm?: number; pps?: number; vs?: number; standing?: number; standing_local?: number; percentile?: number; percentile_rank?: string; next_rank?: string; prev_rank?: string; next_at?: number; prev_at?: number; /** * An object mapping past season IDs to past season final placement information. A season will include the following: */ past: { [key: string]: { /** * The season ID. */ season: string; /** * The username the user had at the time. */ username: string; /** * The country the user represented at the time. */ country?: string; /** * This user's final position in the season's global leaderboards. */ placement?: number; /** * Whether the user was ranked at the time of the season's end. */ ranked: boolean; /** * The amount of TETRA LEAGUE games played by this user. */ gamesplayed: number; /** * The amount of TETRA LEAGUE games won by this user. */ gameswon: number; /** * This user's final Glicko-2 rating. */ glicko: number; /** * This user's final Glicko-2 Rating Deviation. */ rd: number; /** * This user's final TR (Tetra Rating). */ tr: number; /** * This user's final GLIXARE score (a % chance of beating an average player). */ gxe: number; /** * This user's final letter rank. z is unranked. */ rank: string; /** * This user's highest achieved rank in the season. */ bestrank?: string; /** * This user's average APM (attack per minute) over the last 10 games in the season. */ apm: number; /** * This user's average PPS (pieces per second) over the last 10 games in the season. */ pps: number; /** * This user's average VS (versus score) over the last 10 games in the season. */ vs: number; }; }; } interface Request { /** * The lowercase username or user ID to look up. */ user: string; } } const tetraLeague: { (user: string): Promise<TetraLeague.Response>; ({ user }: { user: string; }): Promise<TetraLeague.Response>; }; /** Alias of tetraLeague */ const tl: { (user: string): Promise<TetraLeague.Response>; ({ user }: { user: string; }): Promise<TetraLeague.Response>; }; namespace Zen { /** * An object describing a summary of the user's ZEN progress. */ interface Response { /** * The user's level. */ level: number; /** * The user's score. */ score: number; } interface Request { /** * The lowercase username or user ID to look up. */ user: string; } } const zen: { (user: string): Promise<Zen.Response>; ({ user }: { user: string; }): Promise<Zen.Response>; }; namespace Achievements { /** * An object containing all the user's achievements. */ interface Response { achievements: ChannelAPI.Types.Achievement[]; } interface Request { /** * The lowercase username or user ID to look up. */ user: string; } } const achievements: { (user: string): Promise<Achievements.Response["achievements"]>; ({ user }: { user: string; }): Promise<Achievements.Response["achievements"]>; }; namespace All { /** * An object containing all the user's summaries in one. */ interface Response { /** * See User Summary: 40 LINES. */ "40l": FourtyLines.Response; /** * See User Summary: BLITZ. */ blitz: Blitz.Response; /** * See User Summary: QUICK PLAY. */ zenith: QuickPlay.Response; /** * See User Summary: EXPERT QUICK PLAY. */ zenithex: ExpertQuickPlay.Response; /** * See User Summary: TETRA LEAGUE. */ league: TetraLeague.Response; /** * See User Summary: ZEN. */ zen: Zen.Response; /** * See User Summary: Achievements. */ achievements: Achievements.Response; } interface Request { /** * The lowercase username or user ID to look up. */ user: string; } } const all: { (user: string): Promise<All.Response>; ({ user }: { user: string; }): Promise<All.Response>; }; } namespace Search { /** * An object describing the user found, or null if none found. */ interface Response { /** * The requested user: */ users?: { /** * The user's internal ID. */ _id: string; /** * The user's username. */ username: string; }[]; } type Query = `discord:id:${string}` | `discord:username:${string}` | `twitch:id:${string}` | `twitch:username:${string}` | `twitch:display_username:${string}` | `twitter:id:${string}` | `twitter:username:${string}` | `twitter:display_username:${string}` | `reddit:id:${string}` | `reddit:username:${string}` | `youtube:id:${string}` | `youtube:username:${string}` | `steam:id:${string}` | `steam:username:${string}`; interface Request { /** * The social connection to look up. Must be one of: discord:id:<snowflake> - a Discord user ID discord:username:<username> - a Discord username twitch:id:<userid> - a Twitch user ID twitch:username:<username> - a Twitch username (as used in the URL) twitch:display_username:<username> - a Twitch display name (may include Unicode) twitter:id:<userid> - an X user ID twitter:username:<handle> - an X handle (as used in the URL) twitter:display_username:<username> - an X display name (may include Unicode) reddit:id:<userid> - a Reddit user ID reddit:username:<username> - a Reddit username youtube:id:<userid> - a YouTube user ID (as used in the URL) youtube:username:<username> - a YouTube display name steam:id:<steamid> - a SteamID steam:username:<username> - a Steam display name */ query: Query; } } const search: { (query: Search.Query): Promise<Search.Response["users"]>; ({ query }: { query: Search.Query; }): Promise<Search.Response["users"]>; }; namespace Leaderboard { interface Response { /** * The matched users: */ entries: ChannelAPI.Types.LeaderboardEntry[]; } interface Request { /** * The leaderboard to sort users by. Must be one of: * league — the TETRA LEAGUE leaderboard. * xp — the XP leaderboard. * ar — the Achievement Rating leaderboard. */ leaderboard: "league" | "xp" | "ar"; } interface QueryParams { /** * The upper bound. Use this to paginate downwards: take the lowest seen prisecter and pass that back through this field to continue scrolling. */ after?: string; /** * The lower bound. Use this to paginate upwards: take the highest seen prisecter and pass that back through this field to continue scrolling. If set, the search order is reversed (returning the lowest items that match the query) */ before?: string; /** * The amount of entries to return, between 1 and 100. 50 by default. */ limit?: number; /** * The ISO 3166-1 country code to filter to. Leave unset to not filter by country. */ country?: string; } } const leaderboard: { (leaderboard: Leaderboard.Request["leaderboard"]): Promise<Leaderboard.Response["entries"]>; ({ leaderboard }: { leaderboard: Leaderboard.Request["leaderboard"]; }): Promise<Leaderboard.Response["entries"]>; (leaderboard: Leaderboard.Request["leaderboard"], query: Leaderboard.QueryParams): Promise<Leaderboard.Response["entries"]>; ({ leaderboard }: { leaderboard: Leaderboard.Request["leaderboard"]; }, query: Leaderboard.QueryParams): Promise<Leaderboard.Response["entries"]>; }; /** Alias of leaderboard */ const lb: { (leaderboard: Leaderboard.Request["leaderboard"]): Promise<Leaderboard.Response["entries"]>; ({ leaderboard }: { leaderboard: Leaderboard.Request["leaderboard"]; }): Promise<Leaderboard.Response["entries"]>; (leaderboard: Leaderboard.Request["leaderboard"], query: Leaderboard.QueryParams): Promise<Leaderboard.Response["entries"]>; ({ leaderboard }: { leaderboard: Leaderboard.Request["leaderboard"]; }, query: Leaderboard.QueryParams): Promise<Leaderboard.Response["entries"]>; }; namespace History { interface Response { /** * The matched users: */ entries: ChannelAPI.Types.HistoricalLeaderboardEntry[]; } interface Request { /** * The leaderboard to sort users by. Must be: * league — the TETRA LEAGUE leaderboard. */ leaderboard: "league"; /** * The season to look up. */ season: string; } type QueryParams = ({ /** * The upper bound. Use this to paginate downwards: take the lowest seen prisecter and pass that back through this field to continue scrolling. */ after?: string; } | { /** * The lower bound. Use this to paginate upwards: take the highest seen prisecter and pass that back through this field to continue scrolling. If set, the search order is reversed (returning the lowest items that match the query) */ before?: string; }) & { /** * The amount of entries to return, between 1 and 100. 50 by default. */ limit?: number; /** * The ISO 3166-1 country code to filter to. Leave unset to not filter by country. */ country?: string; }; } const history: { (leaderboard: History.Request["leaderboard"], season: History.Request["season"]): Promise<History.Response["entries"]>; ({ leaderboard, season }: History.Request): Promise<History.Response["entries"]>; (leaderboard: History.Request["leaderboard"], season: History.Request["season"], query: History.QueryParams): Promise<History.Response["entries"]>; ({ leaderboard, season }: History.Request, query: History.QueryParams): Promise<History.Response["entries"]>; }; namespace PersonalRecords { type Response = ChannelAPI.Types.Record[]; interface Request { /** * The lowercase username or user ID to look up. */ user: string; /** * The game mode to look up. One of: * 40l — their 40 LINES records. * blitz — their BLITZ records. * zenith — their QUICK PLAY records. * zenithex — their EXPERT QUICK PLAY records. * league — their TETRA LEAGUE history. */ gamemode: "40l" | "blitz" | "zenith" | "zenithex" | "league"; /** * The personal leaderboard to look up. One of: * top — their top scores. * recent — their most recently placed records. * progression — their top scores (PBs only). */ leaderboard: "top" | "recent" | "progression"; } type QueryParams = ({ /** * The upper bound. Use this to paginate downwards: take the lowest seen prisecter and pass that back through this field to continue scrolling. */ after?: string; } | { /** * The lower bound. Use this to paginate upwards: take the highest seen prisecter and pass that back through this field to continue scrolling. If set, the search order is reversed (returning the lowest items that match the query) */ before?: string; }) & { /** * The amount of entries to return, between 1 and 100. 50 by default. */ limit?: number; }; } const personalRecords: { (user: PersonalRecords.Request["user"], gamemode: PersonalRecords.Request["gamemode"], leaderboard: PersonalRecords.Request["leaderboard"]): Promise<PersonalRecords.Response["entries"]>; ({ user, gamemode, leaderboard }: PersonalRecords.Request): Promise<PersonalRecords.Response["entries"]>; (user: PersonalRecords.Request["user"], gamemode: PersonalRecords.Request["gamemode"], leaderboard: PersonalRecords.Request["leaderboard"], query: PersonalRecords.QueryParams): Promise<PersonalRecords.Response["entries"]>; ({ user, gamemode, leaderboard }: PersonalRecords.Request, query: PersonalRecords.QueryParams): Promise<PersonalRecords.Response["entries"]>; }; /** Alias of personalRecords */ const records: { (user: PersonalRecords.Request["user"], gamemode: PersonalRecords.Request["gamemode"], leaderboard: PersonalRecords.Request["leaderboard"]): Promise<PersonalRecords.Response["entries"]>; ({ user, gamemode, leaderboard }: PersonalRecords.Request): Promise<PersonalRecords.Response["entries"]>; (user: PersonalRecords.Request["user"], gamemode: PersonalRecords.Request["gamemode"], leaderboard: PersonalRecords.Request["leaderboard"], query: PersonalRecords.QueryParams): Promise<PersonalRecords.Response["entries"]>; ({ user, gamemode, leaderboard }: PersonalRecords.Request, query: PersonalRecords.QueryParams): Promise<PersonalRecords.Response["entries"]>; }; } namespace records { namespace Leaderboard { interface Response { /** * The requested records. The record will additionally include: */ entries: (ChannelAPI.Types.Record & { /** * The prisecter of this entry: */ p: { /** * The primary sort key. */ pri: number; /** * The secondary sort key. */ sec: number; /** * The tertiary sort key. */ ter: number; }; })[]; } interface Request { /** * The leaderboard to look up (e.g. 40l_global, blitz_country_XM, zenith_global@2024w31). Leaderboard IDs consist of: * the game mode, e.g. 40l, * the scope, either _global or a country, e.g. _country_XM, * an optional Revolution ID, e.g. @2024w31. */ leaderboard: string; } type QueryParams = ({ /** * The upper bound. Use this to paginate downwards: take the lowest seen prisecter and pass that back through this field to continue scrolling. */ after?: string; } | { /** * The lower bound. Use this to paginate upwards: take the highest seen prisecter and pass that back through this field to continue scrolling. If set, the search order is reversed (returning the lowest items that match the query) */ before?: string; }) & { /** * The amount of entries to return, between 1 and 100. 50 by default. */ limit?: number; }; } const leaderboard: { (leaderboard: Leaderboard.Request["leaderboard"]): Promise<Leaderboard.Response["entries"]>; ({ leaderboard }: { leaderboard: Leaderboard.Request["leaderboard"]; }): Promise<Leaderboard.Response["entries"]>; (leaderboard: Leaderboard.Request["leaderboard"], query: Leaderboard.QueryParams): Promise<Leaderboard.Response["entries"]>; ({ leaderboard }: { leaderboard: Leaderboard.Request["leaderboard"]; }, query: Leaderboard.QueryParams): Promise<Leaderboard.Response["entries"]>; }; /** Alias of leaderboard */ const lb: { (leaderboard: Leaderboard.Request["leaderboard"]): Promise<Leaderboard.Response["entries"]>; ({ leaderboard }: { leaderboard: Leaderboard.Request["leaderboard"]; }): Promise<Leaderboard.Response["entries"]>; (leaderboard: Leaderboard.Request["leaderboard"], query: Leaderboard.QueryParams): Promise<Leaderboard.Response["entries"]>; ({ leaderboard }: { leaderboard: Leaderboard.Request["leaderboard"]; }, query: Leaderboard.QueryParams): Promise<Leaderboard.Response["entries"]>; }; namespace Search { interface Response { /** * If successful and found, the requested record. */ record?: ChannelAPI.Types.Record; } interface Request { } interface QueryParams { /** * The user ID to look up. */ user: string; /** * The game mode to look up. */ gamemode: string; /** * The timestamp of the record to find. */ ts: number; } } const search: { (query: Search.QueryParams): Promise<Search.Response>; }; } namespace news { namespace All { interface Response { /** * The latest news items: */ news: ChannelAPI.Types.NewsItem[]; } interface Request { } interface QueryParams { /** * The amount of entries to return, between 1 and 100. 25 by default. */ limit?: number; } } const all: { (): Promise<All.Response>; (query: All.QueryParams): Promise<All.Response>; }; namespace Latest { interface Response { /** * The latest news items: */ news: ChannelAPI.Types.NewsItem[]; } interface Request { /** * The news stream to look up (either "global" or "user_{ userID }"). */ stream: ChannelAPI.Types.StreamID; } interface QueryParams { /** * The amount of entries to return, between 1 and 100. 25 by default. */ limit?: number; } } const latest: { (stream: Latest.Request["stream"]): Promise<Latest.Response["news"]>; ({ stream }: { stream: Latest.Request["stream"]; }): Promise<Latest.Response["news"]>; (stream: Latest.Request["stream"], query: Latest.QueryParams): Promise<Latest.Response["news"]>; ({ stream, query }: { stream: Latest.Request["stream"]; query: Latest.QueryParams; }): Promise<Latest.Response["news"]>; }; /** Alias of latest */ const stream: { (stream: Latest.Request["stream"]): Promise<Latest.Response["news"]>; ({ stream }: { stream: Latest.Request["stream"]; }): Promise<Latest.Response["news"]>; (stream: Latest.Request["stream"], query: Latest.QueryParams): Promise<Latest.Response["news"]>; ({ stream, query }: { stream: Latest.Request["stream"]; query: Latest.QueryParams; }): Promise<Latest.Response["news"]>; }; } namespace labs { namespace ScoreFlow { interface Response { /** * The timestamp of the oldest record found. */ startTime: number; /** * The points in the chart: */ points: [ /** * The timestamp offset. Add startTime to get the true timestamp. */ number, /** * Whether the score set was a PB. 0 = not a PB, 1 = PB. */ 0 | 1, /** * The score achieved. (For 40 LINES, this is negative.) */ number ][]; } interface Request { /** * The lowercase username or user ID to look up. */ user: string; /** * The game mode to look up. */ gamemode: string; } } const scoreflow: { (user: string, gamemode: string): Promise<ScoreFlow.Response>; ({ user, gamemode }: ScoreFlow.Request): Promise<ScoreFlow.Response>; }; namespace LeagueFlow { interface Response { /** * The timestamp of the oldest record found. */ startTime: number; /** * The points in the chart: */ points: [ /** * The timestamp offset. Add startTime to get the true timestamp. */ number, /** * The result of the match, where: * 1 = victory, * 2 = defeat, * 3 = victory by disqualification, * 4 = defeat by disqualification, * 5 = tie, * 6 = no contest, * 7 = match nullified. */ 1 | 2 | 3 | 4 | 5 | 6 | 7, /** * The user's TR after the match. */ number, /** * The opponent's TR before the match. (If the opponent was unranked, same as 2.) */ number ][]; } interface Request { /** * The lowercase username or user ID to look up. */ user: string; } } const leagueflow: { (user: string): Promise<LeagueFlow.Response>; ({ user }: { user: string; }): Promise<LeagueFlow.Response>; }; } namespace Achievements { interface Response { /** * The achievement info. */ achievement: ChannelAPI.Types.Achievement; /** * The entries in the achievement's leaderboard: */ leaderboard: ChannelAPI.Types.AchievementLeaderboardEntry[]; /** * Scores required to obtain the achievement: */ cutoffs: ChannelAPI.Types.AchievementCutoffs; } interface Request { /** * The achievement ID to look up. */ k: number; } } const achievements: { (k: number): Promise<Achievements.Response>; ({ k }: { k: number; }): Promise<Achievements.Response>; }; namespace Types { type ArgsObject<Req extends object> = { [k in keyof Req]: Req[k]; }; interface Config { sessionID: string | null; /** Must include the trailing slash. Include the full url. Example: https://ch.tetr.io/api/ */ host: string; caching: boolean; } /** * Cache is not shared between workers. Load balancing may therefore give you unexpected responses. To use the same worker, pass the same X-Session-ID header for all requests that should use the same cache. */ interface Cache { /** * Whether the cache was hit. Either "hit", "miss", or "awaited" (resource was already being requested by another client) */ status: "hit" | "miss" | "awaited"; /** * When this resource was cached. */ cached_at: number; /** * When this resource's cache expires. */ cached_until: number; } interface SuccessfulResponse<Data = any> { /** Whether the request was successful */ success: true; /** If successful, data about how this request was cached */ cache: Cache; /** If successful, the requested data */ data: Data; } interface UnsuccessfulResponse { /** Whether the request was successful */ success: false; /** If unsuccessful, the reason the request failed */ error: { msg: string; }; } type Response<Data = any> = SuccessfulResponse<Data> | UnsuccessfulResponse; interface User { /** * The user's internal ID. */ _id: string; /** * The user's username. */ username: string; /** * The user's role (one of "anon", "user", "bot", "halfmod", "mod", "admin", "sysop", "hidden", "banned"). */ role: "anon" | "user" | "bot" | "halfmod" | "mod" | "admin" | "sysop" | "hidden" | "banned"; /** * When the user account was created. If not set, this account was created before join dates were recorded. */ ts?: string; /** * If this user is a bot, the bot's operator. */ botmaster?: string; /** * The user's badges: */ badges: { /** * The badge's internal ID, and the filename of the badge icon (all PNGs within /res/badges/). Note that badge IDs may include forward slashes. Please do not encode them! Follow the folder structure. */ id: string; /** * The badge's group ID. If multiple badges have the same group ID, they are rendered together. */ group?: string; /** * The badge's label, shown when hovered. */ label: string; /** * The badge's timestamp, if shown. */ ts?: string; }[]; /** * The user's XP in points. */ xp: number; /** * The amount of online games played by this user. If the user has chosen to hide this statistic, it will be -1. */ gamesplayed: number; /** * The amount of online games won by this user. If the user has chosen to hide this statistic, it will be -1. */ gameswon: number; /** * The amount of seconds this user spent playing, both on- and offline. If the user has chosen to hide this statistic, it will be -1. */ gametime: number; /** * The user's ISO 3166-1 country code, or null if hidden/unknown. Some vanity flags exist. */ country?: string; /** * Whether this user currently has a bad standing (recently banned). */ badstanding?: boolean; /** * Whether this user is currently supporting TETR.IO <3 */ supporter: boolean; /** * An indicator of their total amount supported, between 0 and 4 inclusive. */ supporter_tier: number; /** * This user's avatar ID. Get their avatar at https://tetr.io/user-content/avatars/{ USERID }.jpg?rv={ AVATAR_REVISION } */ avatar_revision?: number; /** * This user's banner ID. Get their banner at https://tetr.io/user-content/banners/{ USERID }.jpg?rv={ BANNER_REVISION }. Ignore this field if the user is not a supporter. */ banner_revision?: number; /** * This user's "About Me" section. Ignore this field if the user is not a supporter. */ bio?: string; /** * This user's third party connections: */ connections: { /** * This user's connection to Discord: */ discord?: { /** * This user's Discord ID. */ id: string; /** * This user's Discord username. */ username: string; /** * Same as username. */ display_username: string; }; /** * This user's connection to Twitch: */ twitch?: { /** * This user's Twitch user ID. */ id: string; /** * This user's Twitch username (as used in the URL). */ username: string; /** * This user's Twitch display name (may include Unicode). */ display_username: string; }; /** * This user's connection to X (kept in the API as twitter for readability): */ twitter?: { /** * This user's X user ID. */ id: string; /** * This user's X handle (as used in the URL). */ username: string; /** * This user's X display name (may include Unicode). */ display_username: string; }; /** * This user's connection to Reddit: */ reddit?: { /** * This user's Reddit user ID. */ id: string; /** * This user's Reddit username. */ username: string; /** * Same as username. */ display_username: string; }; /** * This user's connection to YouTube: */ youtube?: { /** * This user's YouTube user ID (as used in the URL). */ id: string; /** * This user's YouTube display name. */ username: string; /** * Same as username. */ display_username: string; }; /** * This user's connection to Steam: */ steam?: { /** * This user's SteamID. */ id: string; /** * This user's Steam display name. */ username: string; /** * Same as username. */ display_username: string; }; }; /** * The amount of players who have added this user to their friends list. */ friend_count: number; /** * This user's distinguishment banner, if any. Must at least have: */ distinguishment?: { /** * The type of distinguishment banner. */ type: string; }; /** * This user's featured achievements. Up to three integers which correspond to Achievement IDs. */ achievements: number[]; /** * This user's Achievement Rating. */ ar: number; /** * The breakdown of the source of this user's Achievement Rating: */ ar_counts: { /** * The amount of ranked Bronze achievements this user has. */ bronze?: number; /** * The amount of ranked Silver achievements this user has. */ silver?: number; /** * The amount of ranked Gold achievements this user has. */ gold?: number; /** * The amount of ranked Platinum achievements this user has. */ platinum?: number; /** * The amount of ranked Diamond achievements this user has. */ diamond?: number; /**