@retroachievements/api
Version:
A well-tested library that lets you get achievement, user, and game data from RetroAchievements.
1 lines • 101 kB
Source Map (JSON)
{"version":3,"file":"api.cjs","sources":["../src/utils/internal/apiBaseUrl.ts","../src/utils/internal/buildRequestUrl.ts","../src/utils/internal/call.ts","../src/feed/models/claim-set-type.enum.ts","../src/feed/models/claim-status.enum.ts","../src/feed/models/claim-type.enum.ts","../src/game/models/achievement-distribution-flags.enum.ts","../src/game/models/get-game-extended-response.model.ts","../src/utils/internal/serializeProperties.ts","../src/comment/getComments.ts","../src/feed/getClaims.ts","../src/leaderboard/getLeaderboardEntries.ts","../src/ticket/getTicketData.ts","../src/utils/public/buildAuthorization.ts","../src/game/getAchievementCount.ts","../src/game/getAchievementDistribution.ts","../src/feed/getAchievementOfTheWeek.ts","../src/achievement/getAchievementUnlocks.ts","../src/user/getAchievementsEarnedBetween.ts","../src/user/getAchievementsEarnedOnDay.ts","../src/feed/getActiveClaims.ts","../src/console/getConsoleIds.ts","../src/game/getGame.ts","../src/game/getGameExtended.ts","../src/game/getGameHashes.ts","../src/user/getGameInfoAndUserProgress.ts","../src/console/getGameList.ts","../src/game/getGameRankAndScore.ts","../src/game/getGameRating.ts","../src/feed/getRecentGameAwards.ts","../src/feed/getTopTenUsers.ts","../src/user/getUserAwards.ts","../src/user/getUserClaims.ts","../src/user/getUserCompletedGames.ts","../src/user/getUserCompletionProgress.ts","../src/user/getUserGameRankAndScore.ts","../src/user/getUserPoints.ts","../src/user/getUserProfile.ts","../src/user/getUserProgress.ts","../src/user/getUserRecentAchievements.ts","../src/user/getUserRecentlyPlayedGames.ts","../src/user/getUserSummary.ts","../src/user/getUserWantToPlayList.ts"],"sourcesContent":["export const apiBaseUrl = \"https://retroachievements.org/API\";\n","import type { AuthObject } from \"../public/models\";\n\nexport const buildRequestUrl = (\n baseUrl: string,\n endpointUrl: string,\n authObject: AuthObject,\n args: Record<string, string | number> = {}\n) => {\n const concatenated = `${baseUrl}/${endpointUrl}`;\n const withoutDoubleSlashes = concatenated.replaceAll(/([^:]\\/)\\/+/g, \"$1\");\n\n let withArgs = withoutDoubleSlashes;\n\n // `z` and `y` are expected query params from the RA API.\n // Authentication is handled purely by query params.\n const queryParamValues: Record<string, string> = {\n z: authObject.username,\n y: authObject.webApiKey,\n };\n\n for (const [argKey, argValue] of Object.entries(args)) {\n // \"abc.com/some-route/:foo/some-path\" & {\"foo\": 4} --> \"abc.com/some-route/4/some-path\"\n if (withArgs.includes(`:${argKey}`)) {\n withArgs = withArgs.replace(`:${argKey}`, String(argValue));\n } else if (argValue !== undefined) {\n queryParamValues[argKey] = String(argValue);\n }\n }\n\n const queryString = new URLSearchParams(queryParamValues).toString();\n return `${withArgs}?${queryString}`;\n};\n","const packageVersion = process.env?.[\"PACKAGE_VERSION\"] ?? \"Unknown\";\n\n/**\n * Fetch an HTTP resource. This is publicly exposed in the\n * event you would like to access an endpoint that this\n * library does not currently support.\n *\n * UNLESS YOU'RE SURE OF WHAT YOU'RE DOING, YOU PROBABLY\n * SHOULDN'T USE THIS FUNCTION.\n */\nexport const call = async <\n T extends readonly any[] | Record<string, any>\n>(config: {\n url: string;\n}) => {\n const { url } = config;\n\n const headers = new Headers({\n \"User-Agent\": `RetroAchievements-api-js/${packageVersion}`,\n });\n\n const rawResponse = await fetch(url, { headers });\n\n if (!rawResponse.ok) {\n throw new Error(\n `HTTP Error: Status ${rawResponse.status} ${rawResponse.statusText}`\n );\n }\n\n return (await rawResponse.json()) as T;\n};\n","export enum ClaimSetType {\n NewSet = 0,\n Revision = 1,\n}\n","export enum ClaimStatus {\n Active = 0,\n Complete = 1,\n Dropped = 2,\n}\n","export enum ClaimType {\n Primary = 0,\n Collaboration = 1,\n}\n","export enum AchievementDistributionFlags {\n CoreAchievements = 3,\n UnofficialAchievements = 5,\n}\n","// NOTE: This cannot be a true extension of the `GetGameResponse`\n// interface because the return types for many of these fields\n// are different from the actual RA API.\n\nenum GameExtendedClaimType {\n Primary = \"0\",\n Collaboration = \"1\",\n}\n\nexport interface GameExtendedRawAchievementEntity {\n ID: string;\n NumAwarded: string;\n NumAwardedHardcore: string;\n Title: string;\n Description: string;\n Points: string;\n TrueRatio: string;\n Author: string;\n DateModified: string;\n DateCreated: string;\n BadgeName: string;\n DisplayOrder: string;\n MemAddr: string;\n}\n\ninterface GameExtendedRawClaimEntity {\n User: string;\n SetType: string;\n ClaimType: GameExtendedClaimType;\n Created: string;\n Expiration: string;\n}\n\nexport interface GetGameExtendedResponse {\n ID: number;\n Title: string;\n ConsoleID: number;\n ForumTopicID: number;\n Flags: number;\n ImageIcon: string;\n ImageTitle: string;\n ImageIngame: string;\n ImageBoxArt: string;\n Publisher: string;\n Developer: string;\n Genre: string;\n Released: string;\n IsFinal: boolean;\n ConsoleName: string;\n RichPresencePatch: string;\n NumAchievements: number;\n NumDistinctPlayersCasual: string;\n NumDistinctPlayersHardcore: string;\n Claims: GameExtendedRawClaimEntity[];\n Achievements: Record<number, GameExtendedRawAchievementEntity> | [];\n}\n","/* eslint-disable sonarjs/cognitive-complexity */\n/* eslint-disable sonarjs/prefer-immediate-return */\n\nexport const serializeProperties = (\n originalData: any,\n options: Partial<{\n shouldCastToNumbers: string[];\n shouldMapToBooleans: string[];\n }> = {}\n) => {\n const { shouldCastToNumbers, shouldMapToBooleans } = options;\n\n let returnValue = originalData;\n\n if (Array.isArray(originalData)) {\n const cleanedArray: any[] = [];\n\n for (const entity of originalData) {\n cleanedArray.push(serializeProperties(entity, options));\n }\n\n returnValue = cleanedArray;\n } else if (!Array.isArray(originalData) && originalData instanceof Object) {\n let cleanedObject: Record<string, any> = {};\n\n for (const [originalKey, originalValue] of Object.entries(originalData)) {\n let sanitizedValue = originalValue;\n if (shouldCastToNumbers?.includes(originalKey)) {\n sanitizedValue = originalValue === null ? null : Number(originalValue);\n }\n\n if (shouldMapToBooleans?.includes(originalKey)) {\n if (originalValue === null) {\n sanitizedValue = null;\n } else {\n sanitizedValue = String(originalValue) === \"1\" ? true : false;\n }\n }\n\n cleanedObject = {\n ...cleanedObject,\n [naiveCamelCase(originalKey)]: serializeProperties(\n sanitizedValue,\n options\n ),\n };\n }\n\n returnValue = cleanedObject;\n }\n\n return returnValue;\n};\n\nconst naiveCamelCase = (originalValue: string) => {\n // \"ID\" --> \"id\", \"URL\" --> \"url\"\n if (originalValue.toUpperCase() === originalValue) {\n return originalValue.toLowerCase();\n }\n\n // \"GameID\" -> \"gameID\"\n let camelCased =\n originalValue.charAt(0).toLowerCase() + originalValue.slice(1);\n\n // \"authorULId\" -> \"authorUlid\"\n camelCased = camelCased.replaceAll(\"ULID\", \"Ulid\");\n\n // \"gameID\" -> \"gameId\"\n camelCased = camelCased.replaceAll(\"ID\", \"Id\");\n\n // \"badgeURL\" --> \"badgeUrl\"\n camelCased = camelCased.replaceAll(\"URL\", \"Url\");\n\n // \"rAPoints\" -> \"raPoints\"\n camelCased = camelCased.replaceAll(\"rA\", \"ra\");\n\n // \"visibleUserawards\" -> \"visibleUserAwards\"\n camelCased = camelCased.replaceAll(\"visibleUserawards\", \"visibleUserAwards\");\n\n return camelCased;\n};\n","import type { ID } from \"../utils/internal\";\nimport {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type { CommentsResponse, GetCommentsResponse } from \"./models\";\n\nconst kindMap: Record<\"game\" | \"achievement\" | \"user\", number> = {\n game: 1,\n achievement: 2,\n user: 3,\n};\n\n/**\n * A call to this function will retrieve a list of comments on a particular target.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.identifier The identifier to retrieve. For user walls, this will\n * be a string (the username), and for game and achievement walls, this will be a\n * the ID of the object in question.\n *\n * @param payload.kind What kind of identifier was used. This can be \"game\",\n * \"achievement\", or \"user\".\n *\n * @param payload.offset Defaults to 0. The number of entries to skip.\n *\n * @param payload.count Defaults to 50, has a max of 500.\n *\n * @example\n * ```\n * // Retrieving game/achievement comments\n * const gameWallComments = await getComments(\n * authorization,\n * { identifier: 20294, kind: 'game', count: 4, offset: 0 },\n * );\n *\n * // Retrieving comments on a user's wall\n * const userWallComments = await getComments(\n * authorization,\n * { identifier: \"xelnia\", count: 4, offset: 0 },\n * );\n * ```\n *\n * @returns An object containing the amount of comments retrieved,\n * the total comments, and an array of the comments themselves.\n * ```\n * {\n * count: 4,\n * total: 4,\n * results: [\n * {\n * user: \"PlayTester\",\n * submitted: \"2024-07-31T11:22:23.000000Z\",\n * commentText: \"Comment 1\"\n * },\n * // ...\n * ]\n * }\n * ```\n */\nexport const getComments = async (\n authorization: AuthObject,\n payload: {\n identifier: ID;\n kind?: \"game\" | \"achievement\" | \"user\";\n offset?: number;\n count?: number;\n }\n): Promise<CommentsResponse> => {\n const { identifier, kind, offset, count } = payload;\n\n const queryParams: Record<string, number | string> = { i: identifier };\n\n if (kind) {\n queryParams.t = kindMap[kind];\n } else if (typeof identifier === \"number\") {\n throw new TypeError(\n \"'kind' must be specified when looking up an achievement or game.\"\n );\n }\n\n if (offset) {\n queryParams.o = offset;\n }\n\n if (count) {\n queryParams.c = count;\n }\n\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetComments.php\",\n authorization,\n queryParams\n );\n\n const rawResponse = await call<GetCommentsResponse>({ url });\n\n return serializeProperties(rawResponse, {\n shouldCastToNumbers: [\"Count\", \"Total\"],\n });\n};\n","import {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type { GetSetClaimsResponse, SetClaim } from \"./models\";\n\ntype ClaimKind = \"completed\" | \"dropped\" | \"expired\";\n\nexport const getClaims = async (\n authorization: AuthObject,\n payload: { claimKind: ClaimKind }\n): Promise<SetClaim[]> => {\n const { claimKind } = payload;\n\n const url = buildRequestUrl(apiBaseUrl, \"/API_GetClaims.php\", authorization, {\n k: claimKindValueMap[claimKind],\n });\n\n const rawResponse = await call<GetSetClaimsResponse>({ url });\n\n return serializeProperties(rawResponse, {\n shouldMapToBooleans: [\"UserIsJrDev\"],\n });\n};\n\nconst claimKindValueMap: Record<ClaimKind, `${number}`> = {\n completed: \"1\",\n dropped: \"2\",\n expired: \"3\",\n};\n","import type { ID } from \"../utils/internal\";\nimport {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type {\n GetLeaderboardEntriesResponse,\n LeaderboardEntries,\n} from \"./models\";\n\n/**\n * A call to this endpoint will retrieve a given leaderboard's entries, targeted by its ID.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.leaderboardId The target leaderboard ID.\n *\n * @param payload.offset Defaults to 0. The number of entries to skip.\n *\n * @param payload.count Defaults to 100, has a max of 500.\n *\n * @example\n * ```\n * const leaderboardEntries = await getLeaderboardEntries(\n * authorization,\n * { leaderboardId: 14402 }\n * );\n * ```\n *\n * @returns An object containing a leaderboard's entries.\n * ```json\n * {\n * \"count\": 100,\n * \"total\": 1287,\n * \"results\": [\n * {\n * \"rank\": 1,\n * \"user\": \"vani11a\",\n * \"ulid\": \"00003EMFWR7XB8SDPEHB3K56ZQ\",\n * \"score\": 390490,\n * \"formattedScore\": \"390,490\",\n * \"dateSubmitted\": \"2024-07-25T15:51:00+00:00\"\n * }\n * ]\n * }\n * ```\n */\nexport const getLeaderboardEntries = async (\n authorization: AuthObject,\n payload: { leaderboardId: ID; offset?: number; count?: number }\n): Promise<LeaderboardEntries> => {\n const queryParams: Record<string, any> = {};\n queryParams.i = payload.leaderboardId;\n if (payload?.offset) {\n queryParams.o = payload.offset;\n }\n if (payload?.count) {\n queryParams.c = payload.count;\n }\n\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetLeaderboardEntries.php\",\n authorization,\n queryParams\n );\n\n const rawResponse = await call<GetLeaderboardEntriesResponse>({ url });\n\n return serializeProperties(rawResponse);\n};\n","import type { ID } from \"../utils/internal\";\nimport {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type {\n AchievementTicketStats,\n GameTicketStats,\n MostTicketedGames,\n RecentTickets,\n TicketEntity,\n UserTicketStats,\n} from \"./models\";\n\ninterface GetTicketDataAllPayloadValues {\n ticketId?: string | number;\n offset?: number;\n count?: number;\n isGettingMostTicketedGames?: true;\n username?: string;\n gameId?: string | number;\n isGettingTicketsForUnofficialAchievements?: true;\n shouldReturnTicketsList?: true;\n achievementId?: string | number;\n}\n\n/**\n * BEGIN: Function overload definitions\n */\n\n/**\n * A call to this function will retrieve ticket metadata information\n * about a single achievement ticket, targeted by its ticket ID.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.ticketId The ID of the ticket to get information about.\n *\n * @example\n * ```\n * const ticketData = await getTicketData(\n * authorization,\n * { ticketId: 12345 }\n * );\n * ```\n *\n * @returns An object containing metadata about a target ticket.\n */\nexport function getTicketData(\n authorization: AuthObject,\n payload: { ticketId: ID }\n): Promise<TicketEntity>;\n\n/**\n * A call to this function will retrieve ticket metadata information\n * about the latest opened achievement tickets on RetroAchievements.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.count Optional. Defaults to 10. Max is 100.\n * How many tickets to retrieve.\n *\n * @param payload.offset Optional. Defaults to 0.\n * Number of tickets to skip. This can be used for pagination.\n *\n * @example\n * ```\n * const ticketData = await getTicketData(authorization);\n * ```\n *\n * @returns A list of the most recently opened tickets on the site.\n */\nexport function getTicketData(\n authorization: AuthObject,\n payload?: Partial<{ offset: number; count: number }>\n): Promise<RecentTickets>;\n\n/**\n * A call to this function will retrieve the games on the site with\n * the highest count of opened achievement tickets.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.count Optional. Defaults to 10. Max is 100.\n * How many ticketed games to retrieve.\n *\n * @param payload.offset Optional. Defaults to 0.\n * Number of games to skip. This can be used for pagination.\n *\n * @example\n * ```\n * const ticketData = await getTicketData(\n * authorization,\n * { isGettingMostTicketedGames: true }\n * );\n * ```\n *\n * @returns A list of the most recently opened tickets on the site.\n */\nexport function getTicketData(\n authorization: AuthObject,\n payload: { isGettingMostTicketedGames: true; offset?: number; count?: number }\n): Promise<MostTicketedGames>;\n\n/**\n * A call to this function will retrieve an achievement developer's\n * ticket stats, targeted by that developer's username.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.username The developer's account username to retrieve\n * ticket stats for.\n *\n * @example\n * ```\n * const ticketData = await getTicketData(\n * authorization,\n * { username: \"xelnia\" }\n * );\n * ```\n *\n * @returns An achievement developer's ticket stats.\n */\nexport function getTicketData(\n authorization: AuthObject,\n payload: { username: string }\n): Promise<UserTicketStats>;\n\n/**\n * A call to this function will retrieve a game's ticket stats, targeted\n * by the game's ID. If you are unsure of a game's ID, visit its page\n * on the RetroAchievements website and copy the number at the end of the URL.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.gameId The game ID to fetch ticket stats for.\n *\n * @param payload.isGettingTicketsForUnofficialAchievements Optional. Fetch stats\n * for unofficial/non-core achievements that have tickets.\n *\n * @param payload.shouldReturnTicketsList Optional. If true, not only fetches a\n * game's ticket stats, but also returns a list of tickets for the game.\n *\n * @example\n * ```\n * const ticketData = await getTicketData(\n * authorization,\n * { gameId: 14_402 }\n * );\n * ```\n *\n * @returns A game's ticket stats, potentially also including the ticket list.\n */\nexport function getTicketData(\n authorization: AuthObject,\n payload: {\n gameId: ID;\n isGettingTicketsForUnofficialAchievements?: true;\n shouldReturnTicketsList?: true;\n }\n): Promise<GameTicketStats>;\n\n/**\n * A call to this function will retrieve the an achievement's\n * ticket stats, targeted by the achievement's ID. If you are unsure\n * of an achievement's ID, open its page on the RetroAchievements\n * website and copy the number at the end of the URL.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.achievementId The ID of the achievement to fetch ticket\n * stats for.\n *\n * @example\n * ```\n * const ticketData = await getTicketData(\n * authorization,\n * { achievementId: 12345 }\n * );\n * ```\n *\n * @returns An achievement developer's ticket stats.\n */\nexport function getTicketData(\n authorization: AuthObject,\n payload: { achievementId: ID }\n): Promise<AchievementTicketStats>;\n\n/**\n * END: Function overload definitions\n */\n\nexport async function getTicketData(\n authorization: AuthObject,\n payload: GetTicketDataAllPayloadValues = {}\n) {\n const queryParams = buildGetTicketDataQueryParams(payload);\n\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetTicketData.php\",\n authorization,\n queryParams\n );\n\n const rawResponse = await call({ url });\n\n return serializeProperties(rawResponse, {\n shouldCastToNumbers: [\n \"ID\",\n \"AchievementID\",\n \"Points\",\n \"GameID\",\n \"ReportType\",\n \"ReportState\",\n \"OpenTickets\",\n ],\n shouldMapToBooleans: [\"Hardcore\"],\n });\n}\n\nconst buildGetTicketDataQueryParams = (\n payload: GetTicketDataAllPayloadValues\n) => {\n const {\n ticketId,\n isGettingMostTicketedGames,\n username,\n gameId,\n isGettingTicketsForUnofficialAchievements,\n shouldReturnTicketsList,\n achievementId,\n } = payload;\n\n let queryParams: Record<string, string | number> = {};\n\n if (ticketId !== undefined) {\n queryParams[\"i\"] = ticketId;\n } else if (isGettingMostTicketedGames) {\n queryParams[\"f\"] = \"1\";\n queryParams = applyPaginationQueryParams(queryParams, payload);\n } else if (username) {\n queryParams[\"u\"] = username;\n } else if (gameId) {\n queryParams[\"g\"] = gameId;\n\n if (isGettingTicketsForUnofficialAchievements) {\n queryParams[\"f\"] = \"5\";\n }\n\n if (shouldReturnTicketsList) {\n queryParams[\"d\"] = \"1\";\n }\n } else if (achievementId) {\n queryParams[\"a\"] = achievementId;\n } else {\n queryParams = applyPaginationQueryParams(queryParams, payload);\n }\n\n return queryParams;\n};\n\nconst applyPaginationQueryParams = (\n currentParams: Record<string, string | number>,\n payload: Partial<{ count: number; offset: number }>\n) => {\n const modifiedParams = { ...currentParams };\n\n if (payload.count !== undefined) {\n modifiedParams[\"c\"] = payload.count;\n }\n\n if (payload.offset !== undefined) {\n modifiedParams[\"o\"] = payload.offset;\n }\n\n return modifiedParams;\n};\n","import type { AuthObject } from \"./models\";\n\n/**\n * Accepts your RetroAchievements.org username and web API key. After\n * receiving these inputs, the function returns you a value that can be\n * used for the authentication parameter by any of the async calls in this\n * library.\n *\n * Your account's personal Web API Key can be found on the Settings page\n * of RetroAchievements.org. Do not use a Web API Key that is not associated\n * with your account.\n *\n * @returns An `AuthObject` that you can pass to any of the API call functions.\n *\n * @example\n * ```\n * const authorization = buildAuthorization({\n * username: \"Scott\",\n * webApiKey: \"LtjCwW16nJI7cqOyPIQtXk8v1cfF0tmO\"\n * });\n * ```\n */\nexport const buildAuthorization = (options: AuthObject): AuthObject => {\n if (!options.username || !options.webApiKey) {\n throw new Error(`\n buildAuthorization() requires an object containing a\n username and webApiKey. eg:\n\n const authorization = buildAuthorization({\n username: \"myUserName\",\n webApiKey: \"myWebApiKey\"\n })\n `);\n }\n\n return options;\n};\n\n// This function simply returns what it's given, however the return\n// value has the added benefit of type safety.\n","import type { ID } from \"../utils/internal\";\nimport {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type { AchievementCount, GetAchievementCountResponse } from \"./models\";\n\n/**\n * A call to this function will retrieve the list of\n * achievement IDs for a game, targeted by game ID.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.gameId The unique game ID. If you are unsure, open the\n * game's page on the RetroAchievements.org website. For example, Dragster's\n * URL is https://retroachievements.org/game/14402. We can see from the\n * URL that the game ID is \"14402\".\n *\n * @example\n * ```\n * const achievementCount = await getAchievementCount(\n * authorization,\n * { gameId: 14402 }\n * );\n * ```\n *\n * @returns An object containing a gameId and a list of\n * achievementIds.\n * ```\n * { gameId: 14402, achievementIds: [1,2,3,4,5] }\n * ```\n */\nexport const getAchievementCount = async (\n authorization: AuthObject,\n payload: { gameId: ID }\n): Promise<AchievementCount> => {\n const { gameId } = payload;\n\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetAchievementCount.php\",\n authorization,\n { i: gameId }\n );\n\n const rawResponse = await call<GetAchievementCountResponse>({ url });\n\n return serializeProperties(rawResponse);\n};\n","import type { ID } from \"../utils/internal\";\nimport { apiBaseUrl, buildRequestUrl, call } from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type {\n AchievementDistributionFlags,\n GetAchievementDistributionResponse,\n} from \"./models\";\n\n/**\n * A call to this function will retrieve a dictionary\n * of the number of players who have earned a specific\n * number of achievements for a given game ID.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.gameId The unique game ID. If you are unsure, open the\n * game's page on the RetroAchievements.org website. For example, Dragster's\n * URL is https://retroachievements.org/game/14402. We can see from the\n * URL that the game ID is \"14402\".\n *\n * @param payload.flags Optional. By default, only official achievement\n * tallies are returned in the response. Import the `AchievementDistributionFlags`\n * enum for possible values. This lets you see the count of players who have\n * unlocked unofficial achievements.\n *\n * @param payload.hardcore Optional. By default, set to false, with both\n * softcore and hardcore tallies returned in the response. If this option\n * is set to true, only hardcore unlocks will be included in the totals.\n *\n * @example\n * ```\n * const achievementDistribution = await getAchievementDistribution(\n * authorization,\n * { gameId: 14402, hardcore: true }\n * );\n * ```\n *\n * @returns A dictionary where the keys represent the earned achievement\n * count and the values represent the number of players who have unlocked\n * that many achievements.\n * ```\n * {\n * '1': 64,\n * '2': 19,\n * '3': 11,\n * '4': 18,\n * '5': 25,\n * '6': 20,\n * '7': 26,\n * '8': 29,\n * '9': 54,\n * '10': 17,\n * '11': 29,\n * '12': 4\n * }\n * ```\n */\nexport const getAchievementDistribution = async (\n authorization: AuthObject,\n payload: {\n gameId: ID;\n flags?: AchievementDistributionFlags;\n hardcore?: boolean;\n }\n) => {\n const { gameId, flags, hardcore } = payload;\n\n const queryParams: Record<string, any> = { i: gameId };\n\n if (flags !== undefined) {\n queryParams[\"f\"] = flags;\n }\n\n if (hardcore !== undefined) {\n queryParams[\"h\"] = hardcore === true ? 1 : 0;\n }\n\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetAchievementDistribution.php\",\n authorization,\n queryParams\n );\n\n return await call<GetAchievementDistributionResponse>({\n url,\n });\n};\n","import {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type {\n AchievementOfTheWeek,\n GetAchievementOfTheWeekResponse,\n} from \"./models\";\n\n/**\n * A call to this function will retrieve comprehensive\n * metadata about the current Achievement of the Week.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @example\n * ```\n * const achievementOfTheWeek = await getAchievementOfTheWeek(\n * authorization\n * );\n * ```\n *\n * @returns An object containing comprehensive metadata\n * about the current Achievement of the Week.\n * ```\n * {\n * achievement: {\n * id: \"165062\",\n * title: \"The True Hero\",\n * description: \"Receive any Ending as Han [Normal or Hard]\",\n * points: \"10\",\n * trueRatio: \"22\",\n * author: \"BigWeedSmokerMan\",\n * dateCreated: \"2021-08-08 17:47:46\",\n * dateModified: \"2021-08-09 12:20:05\",\n * badgeName: \"185805\",\n * badgeUrl: \"/Badge/185805.png\"\n * },\n * console: { id: \"39\", title: \"Saturn\" },\n * forumTopic: { id: \"14767\" },\n * game: { id: \"14513\", title: \"Guardian Heroes\" },\n * startAt: \"2022-10-10 00:00:00\",\n * totalPlayers: \"219\",\n * unlocks: [\n * {\n * user: \"Tirbaba2\",\n * raPoints: \"72\",\n * raSoftcorePoints: \"72\",\n * dateAwarded: \"2022-10-10 01:42:19\",\n * hardcoreMode: \"1\"\n * }\n * ],\n * unlocksCount: \"40\"\n * }\n * ```\n */\nexport const getAchievementOfTheWeek = async (\n authorization: AuthObject\n): Promise<AchievementOfTheWeek> => {\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetAchievementOfTheWeek.php\",\n authorization\n );\n\n const rawResponse = await call<GetAchievementOfTheWeekResponse>({ url });\n\n return serializeProperties(rawResponse, {\n shouldCastToNumbers: [\n \"ID\",\n \"Points\",\n \"TrueRatio\",\n \"TotalPlayers\",\n \"RAPoints\",\n \"RASoftcorePoints\",\n \"UnlocksCount\",\n ],\n shouldMapToBooleans: [\"HardcoreMode\"],\n });\n};\n","import type { ID } from \"../utils/internal\";\nimport {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type {\n AchievementUnlocksMetadata,\n GetAchievementUnlocksResponse,\n} from \"./models\";\n\n/**\n * A call to this function will retrieve a list of users who\n * have earned a given achievement, targeted by the achievement's ID.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.achievementId The target achievement we want to\n * retrieve the unlocks list for. If unknown, this can be found\n * by navigating to the achievement's page on the RetroAchievements.org\n * website. eg: https://retroachievements.org/achievement/13876 has an\n * ID of 13876.\n *\n * @param payload.offset Defaults to 0. The number of entries to skip.\n *\n * @param payload.count Defaults to 50, has a max of 500.\n *\n * @example\n * ```\n * const achievementUnlocks = await getAchievementUnlocks(\n * authorization,\n * { achievementId: 13876 }\n * );\n * ```\n *\n * @returns An array containing metadata about unlocks for\n * the target achievement.\n * ```\n * [\n * {\n * user: 'Podgicus0305',\n * raPoints: 15544,\n * dateAwarded: '2022-07-12 19:06:34',\n * hardcoreMode: true\n * }\n * ]\n * ```\n */\nexport const getAchievementUnlocks = async (\n authorization: AuthObject,\n payload: { achievementId: ID; offset?: number; count?: number }\n): Promise<AchievementUnlocksMetadata> => {\n const { achievementId, offset, count } = payload;\n\n const queryParams: Record<string, number | string> = { a: achievementId };\n\n if (offset) {\n queryParams.o = offset;\n }\n\n if (count) {\n queryParams.c = count;\n }\n\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetAchievementUnlocks.php\",\n authorization,\n queryParams\n );\n\n const rawResponse = await call<GetAchievementUnlocksResponse>({ url });\n\n return serializeProperties(rawResponse, {\n shouldCastToNumbers: [\n \"ID\",\n \"Points\",\n \"TrueRatio\",\n \"RAPoints\",\n \"RASoftcorePoints\",\n ],\n shouldMapToBooleans: [\"HardcoreMode\"],\n });\n};\n","import {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type {\n DatedUserAchievement,\n DatedUserAchievementsResponse,\n} from \"./models\";\n\n/**\n * A call to this function will retrieve a list of achievements\n * earned by a given user between two provided dates.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.username The user for which to retrieve the\n * list of achievements for.\n *\n * @param payload.fromDate A Date object specifying when\n * the list itself should begin.\n *\n * @param payload.toDate A Date object specifying when\n * the list itself should end.\n *\n * @example\n * ```\n * const achievementsEarnedBetween = await getAchievementsEarnedBetween(\n * authorization,\n * {\n * username: \"xelnia\",\n * fromDate: new Date(\"2022-10-12\"),\n * toDate: new Date(\"2022-10-13\")\n * }\n * );\n * ```\n *\n * @returns An array containing metadata about the user\n * achievements earned during the specified date range.\n * ```\n * [\n * {\n * date: '2022-10-12 07:58:05',\n * hardcoreMode: true,\n * achievementId: 173315,\n * title: 'Your Puny Human Weapons',\n * description: 'Collect all objects in the Weapons Category.',\n * badgeName: '193756',\n * points: 10,\n * author: 'blendedsea',\n * gameTitle: 'Me & My Katamari',\n * gameIcon: '/Images/047357.png',\n * gameId: 3571,\n * consoleName: 'PlayStation Portable',\n * cumulScore: 120,\n * badgeUrl: '/Badge/193756.png',\n * gameUrl: '/game/3571',\n * type: 'progression'\n * }\n * ]\n * ```\n */\nexport const getAchievementsEarnedBetween = async (\n authorization: AuthObject,\n payload: { username: string; fromDate: Date; toDate: Date }\n): Promise<DatedUserAchievement[]> => {\n const { username, fromDate, toDate } = payload;\n\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetAchievementsEarnedBetween.php\",\n authorization,\n {\n u: username,\n f: (fromDate.getTime() / 1000).toFixed(0),\n t: (toDate.getTime() / 1000).toFixed(0),\n }\n );\n\n const rawResponse = await call<DatedUserAchievementsResponse>({ url });\n\n return serializeProperties(rawResponse, {\n shouldCastToNumbers: [\"AchievementID\", \"Points\", \"GameID\"],\n shouldMapToBooleans: [\"HardcoreMode\"],\n });\n};\n","import {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type {\n DatedUserAchievement,\n DatedUserAchievementsResponse,\n} from \"./models\";\n\n/**\n * A call to this function will retrieve a list of achievements\n * earned by a given user on a specified date.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.username The user for which to retrieve the\n * list of achievements for.\n *\n * @param payload.fromDate A Date object specifying when\n * the list itself should begin.\n *\n * @param payload.onDate A Date object specifying the day\n * to query for a user's earned achievements.\n *\n * @example\n * ```\n * const achievementsEarnedOnDay = await getAchievementsEarnedOnDay(\n * authorization,\n * {\n * username: \"xelnia\",\n * onDate: new Date(\"2022-10-13\")\n * }\n * );\n * ```\n *\n * @returns An array containing metadata about the user\n * achievements earned on the specified day.\n * ```\n * [\n * {\n * date: '2022-10-12 07:58:05',\n * hardcoreMode: true,\n * achievementId: 173315,\n * title: 'Your Puny Human Weapons',\n * description: 'Collect all objects in the Weapons Category.',\n * badgeName: '193756',\n * points: 10,\n * author: 'blendedsea',\n * gameTitle: 'Me & My Katamari',\n * gameIcon: '/Images/047357.png',\n * gameId: 3571,\n * consoleName: 'PlayStation Portable',\n * cumulScore: 120,\n * badgeUrl: '/Badge/193756.png',\n * gameUrl: '/game/3571',\n * type: 'progression'\n * }\n * ]\n * ```\n */\nexport const getAchievementsEarnedOnDay = async (\n authorization: AuthObject,\n payload: { username: string; onDate: Date }\n): Promise<DatedUserAchievement[]> => {\n const { username, onDate } = payload;\n\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetAchievementsEarnedOnDay.php\",\n authorization,\n {\n u: username,\n // YYYY-MM-DD\n d: `${onDate.getFullYear()}-${onDate.getMonth() + 1}-${onDate.getDate()}`,\n }\n );\n\n const rawResponse = await call<DatedUserAchievementsResponse>({ url });\n\n return serializeProperties(rawResponse, {\n shouldCastToNumbers: [\"AchievementID\", \"Points\", \"GameID\"],\n shouldMapToBooleans: [\"HardcoreMode\"],\n });\n};\n","import {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type { GetSetClaimsResponse, SetClaim } from \"./models\";\n\n/**\n * A call to this function returns information about all\n * (1000 max) active set claims.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @example\n * ```\n * const activeClaims = await getActiveClaims(authorization);\n * ```\n *\n * @returns An array containing metadata about all active claims.\n * ```\n * [\n * {\n * id: 7044,\n * user: \"blendedsea\",\n * gameId: 19212,\n * gameTitle: \"SpongeBob SquarePants: Battle for Bikini Bottom\",\n * gameIcon: \"/Images/059776.png\",\n * consoleName: \"PlayStation 2\",\n * consoleId: 22,\n * claimType: 0,\n * setType: 0,\n * status: 0,\n * extension: 0,\n * special: 0,\n * created: \"2022-10-04 00:25:06\",\n * doneTime: \"2023-01-04 00:25:06\",\n * updated: \"2022-10-04 00:25:06\",\n * minutesLeft: 112523,\n * userIsJrDev: false\n * }\n * ]\n * ```\n */\nexport const getActiveClaims = async (\n authorization: AuthObject\n): Promise<SetClaim[]> => {\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetActiveClaims.php\",\n authorization\n );\n\n const rawResponse = await call<GetSetClaimsResponse>({ url });\n\n return serializeProperties(rawResponse, {\n shouldMapToBooleans: [\"UserIsJrDev\"],\n });\n};\n","import {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type { FetchedSystem, GetConsoleIdsResponse } from \"./models\";\n\n/**\n * A call to this function will retrieve the complete list\n * of console ID and name pairs on the RetroAchievements.org\n * platform.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.shouldOnlyRetrieveActiveSystems If true, only systems that\n * officially support achievements will be returned.\n *\n * @param payload.shouldOnlyRetrieveGameSystems If true, events and hubs will\n * not be returned.\n *\n * @example\n * ```\n * const consoleIds = await getConsoleIds(authorization);\n * ```\n *\n * @returns An array containing a complete list of console ID\n * and name pairs for RetroAchievements.org.\n * ```json\n * {\n * id: \"1\",\n * name: \"Mega Drive\",\n * iconUrl: \"https://static.retroachievements.org/assets/images/system/md.png\",\n * active: true,\n * isGameSystem: true\n * }\n * ```\n */\nexport const getConsoleIds = async (\n authorization: AuthObject,\n payload?: {\n shouldOnlyRetrieveActiveSystems: boolean;\n shouldOnlyRetrieveGameSystems: boolean;\n }\n): Promise<FetchedSystem[]> => {\n let callPayload: Record<string, any> | undefined;\n\n if (payload?.shouldOnlyRetrieveActiveSystems) {\n callPayload = { ...callPayload, a: 1 };\n }\n if (payload?.shouldOnlyRetrieveGameSystems) {\n callPayload = { ...callPayload, g: 1 };\n }\n\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetConsoleIDs.php\",\n authorization,\n callPayload\n );\n\n const rawResponse = await call<GetConsoleIdsResponse>({ url });\n\n return serializeProperties(rawResponse, {\n shouldCastToNumbers: [\"ID\"],\n });\n};\n","import type { ID } from \"../utils/internal\";\nimport {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type { Game, GetGameResponse } from \"./models\";\n\n/**\n * A call to this function will retrieve basic metadata about\n * a game, targeted via its unique ID.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.gameId The unique game ID. If you are unsure, open the\n * game's page on the RetroAchievements.org website. For example, Dragster's\n * URL is https://retroachievements.org/game/14402. We can see from the\n * URL that the game ID is \"14402\".\n *\n * @example\n * ```\n * const game = await getGame(\n * authorization,\n * { gameId: 14402 }\n * );\n * ```\n *\n * @returns An object containing basic metadata about a target game.\n * ```json\n * {\n * id: 14402,\n * title: \"Dragster\",\n * forumTopicId: 9145,\n * consoleId: 25,\n * consoleName: \"Atari 2600\",\n * flags: 0,\n * imageIcon: \"/Images/026368.png\",\n * gameIcon: \"/Images/026368.png\",\n * imageTitle: \"/Images/026366.png\",\n * imageIngame: \"/Images/026367.png\",\n * imageBoxArt: \"/Images/026365.png\",\n * publisher: \"Activision\",\n * developer: \"David Crane\",\n * genre: \"Racing\",\n * released: \"1980\",\n * gameTitle: \"Dragster\",\n * console: \"Atari 2600\"\n * }\n * ```\n */\nexport const getGame = async (\n authorization: AuthObject,\n payload: { gameId: ID }\n): Promise<Game> => {\n const { gameId } = payload;\n\n const url = buildRequestUrl(apiBaseUrl, \"/API_GetGame.php\", authorization, {\n i: gameId,\n });\n\n const rawResponse = await call<GetGameResponse>({ url });\n\n return serializeProperties(rawResponse, {\n shouldCastToNumbers: [\"ID\", \"ForumTopicID\", \"ConsoleID\", \"Flags\"],\n });\n};\n","import type { ID } from \"../utils/internal\";\nimport {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type { GameExtended, GetGameExtendedResponse } from \"./models\";\n\n/**\n * A call to this function will retrieve extended metadata\n * about a game, targeted via its unique ID.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.gameId The unique game ID. If you are unsure, open the\n * game's page on the RetroAchievements.org website. For example, Dragster's\n * URL is https://retroachievements.org/game/14402. We can see from the\n * URL that the game ID is \"14402\".\n *\n * @example\n * ```\n * const gameExtended = await getGameExtended(\n * authorization,\n * { gameId: 14402 }\n * );\n * ```\n *\n * @returns An object containing extended metadata about a target game.\n * ```json\n * {\n * id: 14402,\n * title: \"Dragster\",\n * consoleId: 25,\n * forumTopicId: 9145,\n * flags: 0,\n * imageIcon: \"/Images/026368.png\",\n * imageTitle: \"/Images/026366.png\",\n * imageIngame: \"/Images/026367.png\",\n * imageBoxArt: \"/Images/026365.png\",\n * publisher: \"Activision\",\n * developer: \"David Crane\",\n * genre: \"Racing\",\n * released: \"1980\",\n * isFinal: false,\n * consoleName: \"Atari 2600\",\n * richPresencePatch: \"2b92fa1bf9635c303b3b7f8feea3ed3c\",\n * numAchievements: 12,\n * numDistinctPlayersCasual: 454,\n * numDistinctPlayersHardcore: 323,\n * claims: [],\n * achievements: {\n * '79434': {\n * id: 79434,\n * numAwarded: 338,\n * numAwardedHardcore: 253,\n * title: \"Novice Dragster Driver 1\",\n * description: \"Complete your very first race in game 1.\",\n * points: 1,\n * trueRatio: 1,\n * author: \"Boldewin\",\n * dateModified: \"2019-08-01 19:03:46\",\n * dateCreated: \"2019-07-31 18:49:57\",\n * badgeName: \"85541\",\n * displayOrder: 0,\n * memAddr: \"f5c41fa0b5fa0d5fbb8a74c598f18582\"\n * }\n * }\n * }\n * ```\n */\nexport const getGameExtended = async (\n authorization: AuthObject,\n payload: { gameId: ID; isRequestingUnofficialAchievements?: boolean }\n): Promise<GameExtended> => {\n const { gameId, isRequestingUnofficialAchievements } = payload;\n\n const params: Record<string, string | number> = {\n i: gameId,\n };\n\n if (isRequestingUnofficialAchievements) {\n params[\"f\"] = 5;\n }\n\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetGameExtended.php\",\n authorization,\n params\n );\n\n const rawResponse = await call<GetGameExtendedResponse>({ url });\n\n return serializeProperties(rawResponse, {\n shouldCastToNumbers: [\n \"ID\",\n \"NumAwarded\",\n \"NumAwardedHardcore\",\n \"Points\",\n \"TrueRatio\",\n \"DisplayOrder\",\n \"NumDistinctPlayersCasual\",\n \"NumDistinctPlayersHardcore\",\n ],\n });\n};\n","import type { ID } from \"../utils/internal\";\nimport {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type { GameHashes, GetGameHashesResponse } from \"./models\";\n\n/**\n * A call to this function will retrieve a list of hashes linked to a game.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.gameId The unique game ID. If you are unsure, open the\n * game's page on the RetroAchievements.org website. For example, Dragster's\n * URL is https://retroachievements.org/game/14402. We can see from the\n * URL that the game ID is \"14402\".\n *\n * @example\n * ```\n * const game = await getGameHashes(\n * authorization,\n * { gameId: 14402 }\n * );\n * ```\n *\n * @returns An object containing a list of game hashes.\n * ```json\n * {\n * \"results\": [\n * {\n * \"md5\": \"1b1d9ac862c387367e904036114c4825\",\n * \"name\": \"Sonic The Hedgehog (USA, Europe) (Ru) (NewGame).md\",\n * \"labels\": [\"nointro\", \"rapatches\"],\n * \"patchUrl\": \"https://github.com/RetroAchievements/RAPatches/raw/main/MD/Translation/Russian/1-Sonic1-Russian.zip\"\n * },\n * {\n * \"md5\": \"1bc674be034e43c96b86487ac69d9293\",\n * \"name\": \"Sonic The Hedgehog (USA, Europe).md\",\n * \"labels\": [\"nointro\"],\n * \"patchUrl\": null\n * }\n * ]\n * }\n * ```\n */\nexport const getGameHashes = async (\n authorization: AuthObject,\n payload: { gameId: ID }\n): Promise<GameHashes> => {\n const { gameId } = payload;\n\n const url = buildRequestUrl(\n apiBaseUrl,\n \"/API_GetGameHashes.php\",\n authorization,\n { i: gameId }\n );\n\n const rawResponse = await call<GetGameHashesResponse>({ url });\n\n return serializeProperties(rawResponse);\n};\n","import type { ID } from \"../utils/internal\";\nimport {\n apiBaseUrl,\n buildRequestUrl,\n call,\n serializeProperties,\n} from \"../utils/internal\";\nimport type { AuthObject } from \"../utils/public\";\nimport type {\n GameInfoAndUserProgress,\n GetGameInfoAndUserProgressResponse,\n} from \"./models\";\n\n/**\n * A call to this function will retrieve extended metadata\n * about a game, in addition to a user's progress about a game.\n * This is targeted via a game's unique ID and a given username.\n *\n * @param authorization An object containing your username and webApiKey.\n * This can be constructed with `buildAuthorization()`.\n *\n * @param payload.gameId The unique game ID. If you are unsure, open the\n * game's page on the RetroAchievements.org website. For example, Dragster's\n * URL is https://retroachievements.org/game/14402. We can see from the\n * URL that the game ID is \"14402\".\n *\n * @param payload.username The user for which to retrieve the\n * game progress for.\n *\n * @param payload.shouldIncludeHighestAwardMetadata Include a \"HighestAwardKind\"\n * and a \"HighestAwardDate\" for the given user and game ID.\n *\n * @example\n * ```\n * const gameInfoAndUserProgress = await getGameInfoAndUserProgress(\n * authorization,\n * { gameId: 14402, username: \"wv_pinball\" }\n * );\n * ```\n *\n * @returns An object containing extended metadata about a target game,\n * with attached progress for a target username.\n * ```json\n * {\n * id: 14402,\n * title: \"Dragster\",\n * consoleId: 25,\n * forumTopicId: 9145,\n * flags: 0,\n * imageIcon: \"/Images/026368.png\",\n * imageTitle: \"/Images/026366.png\",\n * imageIngame: \"/Images/026367.png\",\n * imageBoxArt: \"/Images/026365.png\",\n * publisher: \"Activision\",\n * developer: \"David Crane\",\n * genre: \"Racing\",\n * released: \"1980\",\n * isFinal: false,\n * consoleName: \"Atari 2600\",\n * richPresencePatch: \"2b92fa1bf9635c303b3b7f8feea3ed3c\",\n * numAchievements: 12,\n * numDistinctPlayersCasual: 454,\n * numDistinctPlayersHardcore, 323\n * claims: [],\n * achievements: {\n * '79434': {\n * id: 79434,\n * numAwarded: 338,\n * numAwardedHardcore: 253,\n * title: \"Novice Dragster Driver 1\",\n * description: \"Complete your very first race in game 1.\",\n * points: 1,\n * trueRatio: 1,\n * author: \"Boldewin\",\n * dateModified: \"2019-08-01 19:03:46\",\n * dateCreated: \"2019-07-31 18:49:57\",\n * badgeName: \"85541\",\n * displayOrder: 0,\n * memAddr: \"f5c41fa0b5fa0d5fbb8a74c598f18582\",\n * dateEarned: '2022-08-23 22:56:38',\n * dateEarnedHardcore: '2022-08-23