Skip to content

Commit 18c12fb

Browse files
authored
feat: add new getGameHashes() function (#114)
1 parent 29d9910 commit 18c12fb

File tree

9 files changed

+177
-2
lines changed

9 files changed

+177
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ Click the function names to open their complete docs on the docs site.
9595

9696
- [`getGame()`](https://api-docs.retroachievements.org/v1/get-game.html) - Get basic metadata about a game.
9797
- [`getGameExtended()`](https://api-docs.retroachievements.org/v1/get-game-extended.html) - Get extended metadata about a game.
98+
- [`getGameHashes()`](https://api-docs.retroachievements.org/v1/get-game-hashes.html) - Get a list of hashes linked to a game.
9899
- [`getAchievementCount()`](https://api-docs.retroachievements.org/v1/get-achievement-count.html) - Get the list of achievement IDs for a game.
99100
- [`getAchievementDistribution()`](https://api-docs.retroachievements.org/v1/get-achievement-distribution.html) - Get how many players have unlocked how many achievements for a game.
100101
- [`getGameRankAndScore()`](https://api-docs.retroachievements.org/v1/get-game-rank-and-score.html) - Get a list of either the latest masters or highest hardcore points earners for a game.

src/console/getConsoleIds.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ describe("Function: getConsoleIds", () => {
6262
);
6363

6464
// ACT
65-
const response = await getConsoleIds(authorization);
65+
const response = await getConsoleIds(authorization, {
66+
shouldOnlyRetrieveActiveSystems: true,
67+
shouldOnlyRetrieveGameSystems: true,
68+
});
6669

6770
// ASSERT
6871
const expectedResponse: FetchedSystem[] = [

src/feed/getRecentGameAwards.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ describe("Function: getRecentGameAwards", () => {
4949
);
5050

5151
// ACT
52-
const response = await getRecentGameAwards(authorization);
52+
const response = await getRecentGameAwards(authorization, {
53+
startDate: "2025-01-05",
54+
offset: 10,
55+
count: 10,
56+
desiredAwardKinds: ["completed"],
57+
});
5358

5459
const expectedResponse: RecentGameAwards = {
5560
count: 1,

src/game/getGameHashes.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/* eslint-disable sonarjs/no-duplicate-string */
2+
3+
import { http, HttpResponse } from "msw";
4+
import { setupServer } from "msw/node";
5+
6+
import { apiBaseUrl } from "../utils/internal";
7+
import { buildAuthorization } from "../utils/public";
8+
import { getGameHashes } from "./getGameHashes";
9+
import type { GetGameHashesResponse } from "./models";
10+
11+
const server = setupServer();
12+
13+
describe("Function: getGameExtended", () => {
14+
// MSW Setup
15+
beforeAll(() => server.listen());
16+
afterEach(() => server.resetHandlers());
17+
afterAll(() => server.close());
18+
19+
it("is defined #sanity", () => {
20+
// ASSERT
21+
expect(getGameHashes).toBeDefined();
22+
});
23+
24+
it("given a game ID, retrieves extended metadata about the game", async () => {
25+
// ARRANGE
26+
const authorization = buildAuthorization({
27+
username: "mockUserName",
28+
webApiKey: "mockWebApiKey",
29+
});
30+
31+
const mockResponse: GetGameHashesResponse = {
32+
Results: [
33+
{
34+
Name: "Sonic The Hedgehog (USA, Europe) (Ru) (NewGame).md",
35+
MD5: "1b1d9ac862c387367e904036114c4825",
36+
Labels: ["nointro", "rapatches"],
37+
PatchUrl:
38+
"https://github.com/RetroAchievements/RAPatches/raw/main/MD/Translation/Russian/1-Sonic1-Russian.zip",
39+
},
40+
{
41+
Name: "Sonic The Hedgehog (USA, Europe).md",
42+
MD5: "1bc674be034e43c96b86487ac69d9293",
43+
Labels: ["nointro"],
44+
PatchUrl: null,
45+
},
46+
],
47+
};
48+
49+
server.use(
50+
http.get(`${apiBaseUrl}/API_GetGameHashes.php`, () =>
51+
HttpResponse.json(mockResponse)
52+
)
53+
);
54+
55+
// ACT
56+
const response = await getGameHashes(authorization, { gameId: 1 });
57+
58+
// ASSERT
59+
expect(response).toEqual({
60+
results: [
61+
{
62+
name: "Sonic The Hedgehog (USA, Europe) (Ru) (NewGame).md",
63+
md5: "1b1d9ac862c387367e904036114c4825",
64+
labels: ["nointro", "rapatches"],
65+
patchUrl:
66+
"https://github.com/RetroAchievements/RAPatches/raw/main/MD/Translation/Russian/1-Sonic1-Russian.zip",
67+
},
68+
{
69+
name: "Sonic The Hedgehog (USA, Europe).md",
70+
md5: "1bc674be034e43c96b86487ac69d9293",
71+
labels: ["nointro"],
72+
patchUrl: null,
73+
},
74+
],
75+
});
76+
});
77+
});

src/game/getGameHashes.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import type { ID } from "../utils/internal";
2+
import {
3+
apiBaseUrl,
4+
buildRequestUrl,
5+
call,
6+
serializeProperties,
7+
} from "../utils/internal";
8+
import type { AuthObject } from "../utils/public";
9+
import type { GameHashes, GetGameHashesResponse } from "./models";
10+
11+
/**
12+
* A call to this function will retrieve a list of hashes linked to a game.
13+
*
14+
* @param authorization An object containing your username and webApiKey.
15+
* This can be constructed with `buildAuthorization()`.
16+
*
17+
* @param payload.gameId The unique game ID. If you are unsure, open the
18+
* game's page on the RetroAchievements.org website. For example, Dragster's
19+
* URL is https://retroachievements.org/game/14402. We can see from the
20+
* URL that the game ID is "14402".
21+
*
22+
* @example
23+
* ```
24+
* const game = await getGameHashes(
25+
* authorization,
26+
* { gameId: 14402 }
27+
* );
28+
* ```
29+
*
30+
* @returns An object containing a list of game hashes.
31+
* ```json
32+
* {
33+
* "Results": [
34+
* {
35+
* "MD5": "1b1d9ac862c387367e904036114c4825",
36+
* "Name": "Sonic The Hedgehog (USA, Europe) (Ru) (NewGame).md",
37+
* "Labels": ["nointro", "rapatches"],
38+
* "PatchUrl": "https://github.com/RetroAchievements/RAPatches/raw/main/MD/Translation/Russian/1-Sonic1-Russian.zip"
39+
* },
40+
* {
41+
* "MD5": "1bc674be034e43c96b86487ac69d9293",
42+
* "Name": "Sonic The Hedgehog (USA, Europe).md",
43+
* "Labels": ["nointro"],
44+
* "PatchUrl": null
45+
* }
46+
* ]
47+
* }
48+
* ```
49+
*/
50+
export const getGameHashes = async (
51+
authorization: AuthObject,
52+
payload: { gameId: ID }
53+
): Promise<GameHashes> => {
54+
const { gameId } = payload;
55+
56+
const url = buildRequestUrl(
57+
apiBaseUrl,
58+
"/API_GetGameHashes.php",
59+
authorization,
60+
{ i: gameId }
61+
);
62+
63+
const rawResponse = await call<GetGameHashesResponse>({ url });
64+
65+
return serializeProperties(rawResponse);
66+
};

src/game/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from "./getAchievementCount";
22
export * from "./getAchievementDistribution";
33
export * from "./getGame";
44
export * from "./getGameExtended";
5+
export * from "./getGameHashes";
56
export * from "./getGameRankAndScore";
67
export * from "./getGameRating";
78
export * from "./models";

src/game/models/game-hashes.model.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
interface GameHash {
2+
md5: string;
3+
name: string;
4+
labels: string[];
5+
patchUrl: string;
6+
}
7+
8+
export interface GameHashes {
9+
results: GameHash[];
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
interface GameHashResult {
2+
MD5: string;
3+
Name: string;
4+
Labels: string[];
5+
PatchUrl: string;
6+
}
7+
8+
export interface GetGameHashesResponse {
9+
Results: GameHashResult[];
10+
}

src/game/models/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ export * from "./game.model";
44
export * from "./game-extended.model";
55
export * from "./game-extended-achievement-entity.model";
66
export * from "./game-extended-claim-entity.model";
7+
export * from "./game-hashes.model";
78
export * from "./game-rank-and-score-entity.model";
89
export * from "./game-rating.model";
910
export * from "./get-achievement-count-response.model";
1011
export * from "./get-achievement-distribution-response.model";
1112
export * from "./get-game-extended-response.model";
13+
export * from "./get-game-hashes-response.model";
1214
export * from "./get-game-rank-and-score-response.model";
1315
export * from "./get-game-rating-response.model";
1416
export * from "./get-game-response.model";

0 commit comments

Comments
 (0)