@retroachievements/api 2.5.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/README.md +1 -0
  2. package/dist/api.cjs +1 -1
  3. package/dist/api.cjs.map +1 -1
  4. package/dist/api.modern.js +1 -1
  5. package/dist/api.modern.js.map +1 -1
  6. package/dist/api.module.js +1 -1
  7. package/dist/api.module.js.map +1 -1
  8. package/dist/api.umd.js +1 -1
  9. package/dist/api.umd.js.map +1 -1
  10. package/dist/game/models/get-game-hashes-response.model.d.ts +1 -1
  11. package/dist/leaderboard/getUserGameLeaderboards.d.ts +54 -0
  12. package/dist/leaderboard/getUserGameLeaderboards.test.d.ts +1 -0
  13. package/dist/leaderboard/models/get-user-game-leaderboards-response.model.d.ts +19 -0
  14. package/dist/leaderboard/models/index.d.ts +2 -0
  15. package/dist/leaderboard/models/user-game-leaderboards.model.d.ts +19 -0
  16. package/dist/user/models/get-user-recent-achievements-response.model.d.ts +4 -0
  17. package/dist/user/models/user-recent-achievement.model.d.ts +4 -0
  18. package/package.json +1 -1
  19. package/src/game/models/get-game-hashes-response.model.ts +1 -1
  20. package/src/leaderboard/getUserGameLeaderboards.test.ts +88 -0
  21. package/src/leaderboard/getUserGameLeaderboards.ts +85 -0
  22. package/src/leaderboard/models/get-user-game-leaderboards-response.model.ts +19 -0
  23. package/src/leaderboard/models/index.ts +2 -0
  24. package/src/leaderboard/models/user-game-leaderboards.model.ts +19 -0
  25. package/src/user/getUserRecentAchievements.test.ts +6 -0
  26. package/src/user/models/get-user-recent-achievements-response.model.ts +5 -0
  27. package/src/user/models/user-recent-achievement.model.ts +5 -0
  28. package/src/utils/internal/serializeProperties.ts +3 -0
@@ -0,0 +1,19 @@
1
+ export interface GetUserGameLeaderboardsResponse {
2
+ Count: number;
3
+ Total: number;
4
+ Results: Array<{
5
+ ID: number;
6
+ RankAsc: boolean;
7
+ Title: string;
8
+ Description: string;
9
+ Format: string;
10
+ UserEntry: {
11
+ User: string;
12
+ ULID: string;
13
+ Score: number;
14
+ FormattedScore: string;
15
+ Rank: number;
16
+ DateUpdated: string;
17
+ };
18
+ }>;
19
+ }
@@ -1,2 +1,4 @@
1
1
  export * from "./get-leaderboard-entries-response.model";
2
+ export * from "./get-user-game-leaderboards-response.model";
2
3
  export * from "./leaderboard-entries.model";
4
+ export * from "./user-game-leaderboards.model";
@@ -0,0 +1,19 @@
1
+ export interface UserGameLeaderboards {
2
+ count: number;
3
+ total: number;
4
+ results: Array<{
5
+ id: number;
6
+ rankAsc: boolean;
7
+ title: string;
8
+ description: string;
9
+ format: string;
10
+ userEntry: {
11
+ user: string;
12
+ ulid: string;
13
+ score: number;
14
+ formattedScore: string;
15
+ rank: number;
16
+ dateUpdated: string;
17
+ };
18
+ }>;
19
+ }
@@ -1,3 +1,4 @@
1
+ import type { AchievementType } from "../../achievement";
1
2
  interface GetUserRecentAchievementsEntity {
2
3
  Date: string;
3
4
  HardcoreMode: 0 | 1;
@@ -6,7 +7,10 @@ interface GetUserRecentAchievementsEntity {
6
7
  Description: string;
7
8
  BadgeName: string;
8
9
  Points: number;
10
+ TrueRatio: number;
11
+ Type: AchievementType;
9
12
  Author: string;
13
+ AuthorULID: string;
10
14
  GameTitle: string;
11
15
  GameIcon: string;
12
16
  GameID: number;
@@ -1,3 +1,4 @@
1
+ import type { AchievementType } from "../../achievement";
1
2
  export interface UserRecentAchievement {
2
3
  date: string;
3
4
  hardcoreMode: boolean;
@@ -6,7 +7,10 @@ export interface UserRecentAchievement {
6
7
  description: string;
7
8
  badgeName: string;
8
9
  points: number;
10
+ trueRatio: number;
11
+ type: AchievementType;
9
12
  author: string;
13
+ authorUlid: string;
10
14
  gameTitle: string;
11
15
  gameIcon: string;
12
16
  gameId: number;
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "raweb",
11
11
  "retro gaming"
12
12
  ],
13
- "version": "2.5.0",
13
+ "version": "2.7.0",
14
14
  "typings": "dist/index.d.ts",
15
15
  "exports": {
16
16
  ".": {
@@ -2,7 +2,7 @@ interface GameHashResult {
2
2
  MD5: string;
3
3
  Name: string;
4
4
  Labels: string[];
5
- PatchUrl: string;
5
+ PatchUrl: string | null;
6
6
  }
7
7
 
8
8
  export interface GetGameHashesResponse {
@@ -0,0 +1,88 @@
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 { getUserGameLeaderboards } from "./getUserGameLeaderboards";
9
+ import type { GetUserGameLeaderboardsResponse } from "./models";
10
+
11
+ const server = setupServer();
12
+
13
+ describe("Function: getUserGameLeaderboards", () => {
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(getUserGameLeaderboards).toBeDefined();
22
+ });
23
+
24
+ it("given a game ID, retrieves the users leaderboards", async () => {
25
+ // ARRANGE
26
+ const authorization = buildAuthorization({
27
+ username: "mockUserName",
28
+ webApiKey: "mockWebApiKey",
29
+ });
30
+
31
+ const mockResponse: GetUserGameLeaderboardsResponse = {
32
+ Count: 10,
33
+ Total: 64,
34
+ Results: [
35
+ {
36
+ ID: 19_062,
37
+ RankAsc: true,
38
+ Title: "New Zealand One",
39
+ Description: "Complete New Zealand S1 in least time",
40
+ Format: "MILLISECS",
41
+ UserEntry: {
42
+ User: "zuliman92",
43
+ ULID: "00003EMFWR7XB8SDPEHB3K56ZQ",
44
+ Score: 12_620,
45
+ FormattedScore: "2:06.20",
46
+ Rank: 2,
47
+ DateUpdated: "2024-12-12T16:40:59+00:00",
48
+ },
49
+ },
50
+ ],
51
+ };
52
+
53
+ server.use(
54
+ http.get(`${apiBaseUrl}/API_GetUserGameLeaderboards.php`, () =>
55
+ HttpResponse.json(mockResponse)
56
+ )
57
+ );
58
+
59
+ // ACT
60
+ const response = await getUserGameLeaderboards(authorization, {
61
+ gameId: 1,
62
+ username: "zuliman92",
63
+ });
64
+
65
+ // ASSERT
66
+ expect(response).toEqual({
67
+ count: 10,
68
+ total: 64,
69
+ results: [
70
+ {
71
+ id: 19_062,
72
+ rankAsc: true,
73
+ title: "New Zealand One",
74
+ description: "Complete New Zealand S1 in least time",
75
+ format: "MILLISECS",
76
+ userEntry: {
77
+ user: "zuliman92",
78
+ ulid: "00003EMFWR7XB8SDPEHB3K56ZQ",
79
+ score: 12_620,
80
+ formattedScore: "2:06.20",
81
+ rank: 2,
82
+ dateUpdated: "2024-12-12T16:40:59+00:00",
83
+ },
84
+ },
85
+ ],
86
+ });
87
+ });
88
+ });
@@ -0,0 +1,85 @@
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 {
10
+ GetUserGameLeaderboardsResponse,
11
+ UserGameLeaderboards,
12
+ } from "./models";
13
+
14
+ /**
15
+ * A call to this endpoint will retrieve a user's list of leaderboards for a given game, targeted by the game's ID.
16
+ *
17
+ * @param authorization An object containing your username and webApiKey.
18
+ * This can be constructed with `buildAuthorization()`.
19
+ *
20
+ * @param payload.gameId The target game ID.
21
+ *
22
+ * @param payload.offset Defaults to 0. The number of entries to skip.
23
+ *
24
+ * @param payload.count Defaults to 100, has a max of 500.
25
+ *
26
+ * @example
27
+ * ```
28
+ * const gameLeaderboards = await getUserGameLeaderboards(
29
+ * authorization,
30
+ * { gameId: 14402 }
31
+ * );
32
+ * ```
33
+ *
34
+ * @returns An object containing user game leaderboard's.
35
+ * ```json
36
+ * {
37
+ * "count": 10,
38
+ * "total": 64,
39
+ * "results": [
40
+ * {
41
+ * "id": 19062,
42
+ * "rankAsc": true,
43
+ * "title": "New Zealand One",
44
+ * "description": "Complete New Zealand S1 in least time",
45
+ * "format": "MILLISECS",
46
+ * "userEntry": {
47
+ * "user": "zuliman92",
48
+ * "ulid": "00003EMFWR7XB8SDPEHB3K56ZQ",
49
+ * "score": 12620,
50
+ * "formattedScore": "2:06.20",
51
+ * "rank": 2,
52
+ * "dateUpdated": "2024-12-12T16:40:59+00:00"
53
+ * }
54
+ * }
55
+ * ]
56
+ * }
57
+ * ```
58
+ */
59
+ export const getUserGameLeaderboards = async (
60
+ authorization: AuthObject,
61
+ payload: { gameId: ID; username?: string; offset?: number; count?: number }
62
+ ): Promise<UserGameLeaderboards> => {
63
+ const queryParams: Record<string, any> = {};
64
+ queryParams.i = payload.gameId;
65
+ if (payload?.username) {
66
+ queryParams.u = payload.username;
67
+ }
68
+ if (payload?.offset) {
69
+ queryParams.o = payload.offset;
70
+ }
71
+ if (payload?.count) {
72
+ queryParams.c = payload.count;
73
+ }
74
+
75
+ const url = buildRequestUrl(
76
+ apiBaseUrl,
77
+ "/API_GetUserGameLeaderboards.php",
78
+ authorization,
79
+ queryParams
80
+ );
81
+
82
+ const rawResponse = await call<GetUserGameLeaderboardsResponse>({ url });
83
+
84
+ return serializeProperties(rawResponse);
85
+ };
@@ -0,0 +1,19 @@
1
+ export interface GetUserGameLeaderboardsResponse {
2
+ Count: number;
3
+ Total: number;
4
+ Results: Array<{
5
+ ID: number;
6
+ RankAsc: boolean;
7
+ Title: string;
8
+ Description: string;
9
+ Format: string;
10
+ UserEntry: {
11
+ User: string;
12
+ ULID: string;
13
+ Score: number;
14
+ FormattedScore: string;
15
+ Rank: number;
16
+ DateUpdated: string;
17
+ };
18
+ }>;
19
+ }
@@ -1,2 +1,4 @@
1
1
  export * from "./get-leaderboard-entries-response.model";
2
+ export * from "./get-user-game-leaderboards-response.model";
2
3
  export * from "./leaderboard-entries.model";
4
+ export * from "./user-game-leaderboards.model";
@@ -0,0 +1,19 @@
1
+ export interface UserGameLeaderboards {
2
+ count: number;
3
+ total: number;
4
+ results: Array<{
5
+ id: number;
6
+ rankAsc: boolean;
7
+ title: string;
8
+ description: string;
9
+ format: string;
10
+ userEntry: {
11
+ user: string;
12
+ ulid: string;
13
+ score: number;
14
+ formattedScore: string;
15
+ rank: number;
16
+ dateUpdated: string;
17
+ };
18
+ }>;
19
+ }
@@ -36,7 +36,10 @@ describe("Function: getUserRecentAchievements", () => {
36
36
  "Win the Tournament as [You] on Hard with 1 attribute on max. and 1 attribute on min.",
37
37
  BadgeName: "121991",
38
38
  Points: 25,
39
+ TrueRatio: 50,
40
+ Type: "missable",
39
41
  Author: "Som1",
42
+ AuthorULID: "01F13ZKAPPEZ90K3JK82QWYRN2",
40
43
  GameTitle: "WWF King of the Ring",
41
44
  GameIcon: "/Images/062599.png",
42
45
  GameID: 6316,
@@ -68,7 +71,10 @@ describe("Function: getUserRecentAchievements", () => {
68
71
  "Win the Tournament as [You] on Hard with 1 attribute on max. and 1 attribute on min.",
69
72
  badgeName: "121991",
70
73
  points: 25,
74
+ trueRatio: 50,
75
+ type: "missable",
71
76
  author: "Som1",
77
+ authorUlid: "01F13ZKAPPEZ90K3JK82QWYRN2",
72
78
  gameTitle: "WWF King of the Ring",
73
79
  gameIcon: "/Images/062599.png",
74
80
  gameId: 6316,
@@ -1,3 +1,5 @@
1
+ import type { AchievementType } from "../../achievement";
2
+
1
3
  interface GetUserRecentAchievementsEntity {
2
4
  Date: string;
3
5
  HardcoreMode: 0 | 1;
@@ -6,7 +8,10 @@ interface GetUserRecentAchievementsEntity {
6
8
  Description: string;
7
9
  BadgeName: string;
8
10
  Points: number;
11
+ TrueRatio: number;
12
+ Type: AchievementType;
9
13
  Author: string;
14
+ AuthorULID: string;
10
15
  GameTitle: string;
11
16
  GameIcon: string;
12
17
  GameID: number;
@@ -1,3 +1,5 @@
1
+ import type { AchievementType } from "../../achievement";
2
+
1
3
  export interface UserRecentAchievement {
2
4
  date: string;
3
5
  hardcoreMode: boolean;
@@ -6,7 +8,10 @@ export interface UserRecentAchievement {
6
8
  description: string;
7
9
  badgeName: string;
8
10
  points: number;
11
+ trueRatio: number;
12
+ type: AchievementType;
9
13
  author: string;
14
+ authorUlid: string;
10
15
  gameTitle: string;
11
16
  gameIcon: string;
12
17
  gameId: number;
@@ -62,6 +62,9 @@ const naiveCamelCase = (originalValue: string) => {
62
62
  let camelCased =
63
63
  originalValue.charAt(0).toLowerCase() + originalValue.slice(1);
64
64
 
65
+ // "authorULId" -> "authorUlid"
66
+ camelCased = camelCased.replaceAll("ULID", "Ulid");
67
+
65
68
  // "gameID" -> "gameId"
66
69
  camelCased = camelCased.replaceAll("ID", "Id");
67
70