@retroachievements/api 2.6.0 → 2.8.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 (34) 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 +1 -1
  12. package/dist/leaderboard/index.d.ts +1 -0
  13. package/dist/user/getUsersIFollow.d.ts +46 -0
  14. package/dist/user/getUsersIFollow.test.d.ts +1 -0
  15. package/dist/user/index.d.ts +1 -0
  16. package/dist/user/models/get-user-recent-achievements-response.model.d.ts +4 -0
  17. package/dist/user/models/get-users-i-follow-response.model.d.ts +11 -0
  18. package/dist/user/models/index.d.ts +2 -0
  19. package/dist/user/models/user-recent-achievement.model.d.ts +4 -0
  20. package/dist/user/models/users-i-follow.model.d.ts +11 -0
  21. package/package.json +1 -1
  22. package/src/game/models/get-game-hashes-response.model.ts +1 -1
  23. package/src/leaderboard/getUserGameLeaderboards.ts +2 -4
  24. package/src/leaderboard/index.ts +1 -0
  25. package/src/user/getUserRecentAchievements.test.ts +6 -0
  26. package/src/user/getUsersIFollow.test.ts +124 -0
  27. package/src/user/getUsersIFollow.ts +75 -0
  28. package/src/user/index.ts +1 -0
  29. package/src/user/models/get-user-recent-achievements-response.model.ts +5 -0
  30. package/src/user/models/get-users-i-follow-response.model.ts +11 -0
  31. package/src/user/models/index.ts +2 -0
  32. package/src/user/models/user-recent-achievement.model.ts +5 -0
  33. package/src/user/models/users-i-follow.model.ts +11 -0
  34. package/src/utils/internal/serializeProperties.ts +3 -0
@@ -0,0 +1,46 @@
1
+ import type { AuthObject } from "../utils/public";
2
+ import type { UsersIFollow } from "./models";
3
+ /**
4
+ * A call to this function will retrieve the list of users that the
5
+ * caller is following.
6
+ *
7
+ * @param authorization An object containing your username and webApiKey.
8
+ * This can be constructed with `buildAuthorization()`.
9
+ *
10
+ * @param payload.offset The number of entries to skip. The API will default
11
+ * to 0 if the parameter is not specified.
12
+ *
13
+ * @param payload.count The number of entries to return. The API will
14
+ * default to 100 if the parameter is not specified. The max number
15
+ * of entries that can be returned is 500.
16
+ *
17
+ * @example
18
+ * ```
19
+ * const usersIFollow = await getUsersIFollow(authorization);
20
+ * ```
21
+ *
22
+ * @returns An object containing a list of users that the caller is
23
+ * following.
24
+ * ```json
25
+ * {
26
+ * "count": 1,
27
+ * "total": 1,
28
+ * "results": [
29
+ * {
30
+ * "user": "Example",
31
+ * "ulid": "0123456789ABCDEFGHIJKLMNO",
32
+ * "points": 9001,
33
+ * "pointsSoftcore": 101,
34
+ * "isFollowingMe": false
35
+ * }
36
+ * ]
37
+ * }
38
+ * ```
39
+ *
40
+ * @throws If the API was given invalid parameters (422) or if the
41
+ * API is currently down (503).
42
+ */
43
+ export declare const getUsersIFollow: (authorization: AuthObject, payload?: {
44
+ offset?: number;
45
+ count?: number;
46
+ }) => Promise<UsersIFollow>;
@@ -0,0 +1 @@
1
+ export {};
@@ -11,6 +11,7 @@ export * from "./getUserProfile";
11
11
  export * from "./getUserProgress";
12
12
  export * from "./getUserRecentAchievements";
13
13
  export * from "./getUserRecentlyPlayedGames";
14
+ export * from "./getUsersIFollow";
14
15
  export * from "./getUserSummary";
15
16
  export * from "./getUserWantToPlayList";
16
17
  export * from "./models";
@@ -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;
@@ -0,0 +1,11 @@
1
+ export interface GetUsersIFollowResponse {
2
+ Count: number;
3
+ Total: number;
4
+ Results: Array<{
5
+ User: string;
6
+ ULID: string;
7
+ Points: number;
8
+ PointsSoftcore: number;
9
+ IsFollowingMe: boolean;
10
+ }>;
11
+ }
@@ -14,6 +14,7 @@ export * from "./get-user-recent-achievements-response.model";
14
14
  export * from "./get-user-recently-played-games-response.model";
15
15
  export * from "./get-user-summary-response.model";
16
16
  export * from "./get-user-want-to-play-list-response.model";
17
+ export * from "./get-users-i-follow-response.model";
17
18
  export * from "./user-awards.model";
18
19
  export * from "./user-claims.model";
19
20
  export * from "./user-claims-response.model";
@@ -28,3 +29,4 @@ export * from "./user-recent-achievement.model";
28
29
  export * from "./user-recently-played-games.model";
29
30
  export * from "./user-summary.model";
30
31
  export * from "./user-want-to-play-list.model";
32
+ export * from "./users-i-follow.model";
@@ -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;
@@ -0,0 +1,11 @@
1
+ export interface UsersIFollow {
2
+ count: number;
3
+ total: number;
4
+ results: Array<{
5
+ user: string;
6
+ ulid: string;
7
+ points: number;
8
+ pointsSoftcore: number;
9
+ isFollowingMe: boolean;
10
+ }>;
11
+ }
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "raweb",
11
11
  "retro gaming"
12
12
  ],
13
- "version": "2.6.0",
13
+ "version": "2.8.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 {
@@ -58,13 +58,11 @@ import type {
58
58
  */
59
59
  export const getUserGameLeaderboards = async (
60
60
  authorization: AuthObject,
61
- payload: { gameId: ID; username?: string; offset?: number; count?: number }
61
+ payload: { gameId: ID; username: string; offset?: number; count?: number }
62
62
  ): Promise<UserGameLeaderboards> => {
63
63
  const queryParams: Record<string, any> = {};
64
64
  queryParams.i = payload.gameId;
65
- if (payload?.username) {
66
- queryParams.u = payload.username;
67
- }
65
+ queryParams.u = payload.username;
68
66
  if (payload?.offset) {
69
67
  queryParams.o = payload.offset;
70
68
  }
@@ -1,2 +1,3 @@
1
1
  export * from "./getLeaderboardEntries";
2
+ export * from "./getUserGameLeaderboards";
2
3
  export * from "./models";
@@ -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,
@@ -0,0 +1,124 @@
1
+ import { http, HttpResponse } from "msw";
2
+ import { setupServer } from "msw/node";
3
+
4
+ import { apiBaseUrl } from "../utils/internal";
5
+ import { buildAuthorization } from "../utils/public";
6
+ import { getUsersIFollow } from "./getUsersIFollow";
7
+ import type { GetUsersIFollowResponse, UsersIFollow } from "./models";
8
+
9
+ const server = setupServer();
10
+
11
+ describe("Function: getUsersIFollow", () => {
12
+ // MSW Setup
13
+ beforeAll(() => server.listen());
14
+ afterEach(() => server.resetHandlers());
15
+ afterAll(() => server.close());
16
+
17
+ it("is defined #sanity", () => {
18
+ // ASSERT
19
+ expect(getUsersIFollow).toBeDefined();
20
+ });
21
+
22
+ it("using defaults, retrieves the list of users that the caller follows", async () => {
23
+ // ARRANGE
24
+ const authorization = buildAuthorization({
25
+ username: "mockUserName",
26
+ webApiKey: "mockWebApiKey",
27
+ });
28
+
29
+ const mockResponse = mockGetUsersIFollowResponse;
30
+
31
+ server.use(
32
+ http.get(`${apiBaseUrl}/API_GetUsersIFollow.php`, (info) => {
33
+ const url = new URL(info.request.url);
34
+ expect(url.searchParams.has("c")).toBeFalsy();
35
+ expect(url.searchParams.has("o")).toBeFalsy();
36
+ return HttpResponse.json(mockResponse);
37
+ })
38
+ );
39
+
40
+ // ACT
41
+ const response = await getUsersIFollow(authorization);
42
+ expect(response).toEqual(mockUsersIFollowValue);
43
+ });
44
+
45
+ it.each([{ offset: 1, count: 1 }, { offset: 5 }, { count: 20 }])(
46
+ "calls the 'Users I Follow' endpoint with a given offset ($offset) and/or count ($count)",
47
+ async (mockPayload) => {
48
+ // ARRANGE
49
+ const authorization = buildAuthorization({
50
+ username: "mockUserName",
51
+ webApiKey: "mockWebApiKey",
52
+ });
53
+
54
+ server.use(
55
+ http.get(`${apiBaseUrl}/API_GetUsersIFollow.php`, (info) => {
56
+ const url = new URL(info.request.url);
57
+ const c = url.searchParams.get("c");
58
+ const o = url.searchParams.get("o");
59
+ expect(String(c)).toEqual(String(mockPayload.count ?? null));
60
+ expect(String(o)).toEqual(String(mockPayload.offset ?? null));
61
+ return HttpResponse.json(mockGetUsersIFollowResponse);
62
+ })
63
+ );
64
+
65
+ // ACT
66
+ await getUsersIFollow(authorization, mockPayload);
67
+ }
68
+ );
69
+
70
+ it.each([
71
+ { status: 503, statusText: "The API is currently down" },
72
+ { status: 422, statusText: "HTTP Error: Status 422 Unprocessable Entity" },
73
+ ])(
74
+ "given the API returns a $status, throws an error",
75
+ async ({ status, statusText }) => {
76
+ // ARRANGE
77
+ const authorization = buildAuthorization({
78
+ username: "mockUserName",
79
+ webApiKey: "mockWebApiKey",
80
+ });
81
+
82
+ const mockResponse = `<html><body>${statusText}</body></html>`;
83
+
84
+ server.use(
85
+ http.get(`${apiBaseUrl}/API_GetUsersIFollow.php`, () =>
86
+ HttpResponse.json(mockResponse, { status, statusText })
87
+ )
88
+ );
89
+
90
+ // ASSERT
91
+ await expect(
92
+ getUsersIFollow(authorization, { count: 0 })
93
+ ).rejects.toThrow();
94
+ }
95
+ );
96
+ });
97
+
98
+ const mockGetUsersIFollowResponse: GetUsersIFollowResponse = {
99
+ Count: 1,
100
+ Total: 1,
101
+ Results: [
102
+ {
103
+ User: "Example",
104
+ ULID: "0123456789ABCDEFGHIJKLMNO",
105
+ Points: 9001,
106
+ PointsSoftcore: 101,
107
+ IsFollowingMe: false,
108
+ },
109
+ ],
110
+ };
111
+
112
+ const mockUsersIFollowValue: UsersIFollow = {
113
+ count: 1,
114
+ total: 1,
115
+ results: [
116
+ {
117
+ user: "Example",
118
+ ulid: "0123456789ABCDEFGHIJKLMNO",
119
+ points: 9001,
120
+ pointsSoftcore: 101,
121
+ isFollowingMe: false,
122
+ },
123
+ ],
124
+ };
@@ -0,0 +1,75 @@
1
+ import {
2
+ apiBaseUrl,
3
+ buildRequestUrl,
4
+ call,
5
+ serializeProperties,
6
+ } from "../utils/internal";
7
+ import type { AuthObject } from "../utils/public";
8
+ import type { GetUsersIFollowResponse, UsersIFollow } from "./models";
9
+
10
+ /**
11
+ * A call to this function will retrieve the list of users that the
12
+ * caller is following.
13
+ *
14
+ * @param authorization An object containing your username and webApiKey.
15
+ * This can be constructed with `buildAuthorization()`.
16
+ *
17
+ * @param payload.offset The number of entries to skip. The API will default
18
+ * to 0 if the parameter is not specified.
19
+ *
20
+ * @param payload.count The number of entries to return. The API will
21
+ * default to 100 if the parameter is not specified. The max number
22
+ * of entries that can be returned is 500.
23
+ *
24
+ * @example
25
+ * ```
26
+ * const usersIFollow = await getUsersIFollow(authorization);
27
+ * ```
28
+ *
29
+ * @returns An object containing a list of users that the caller is
30
+ * following.
31
+ * ```json
32
+ * {
33
+ * "count": 1,
34
+ * "total": 1,
35
+ * "results": [
36
+ * {
37
+ * "user": "Example",
38
+ * "ulid": "0123456789ABCDEFGHIJKLMNO",
39
+ * "points": 9001,
40
+ * "pointsSoftcore": 101,
41
+ * "isFollowingMe": false
42
+ * }
43
+ * ]
44
+ * }
45
+ * ```
46
+ *
47
+ * @throws If the API was given invalid parameters (422) or if the
48
+ * API is currently down (503).
49
+ */
50
+ export const getUsersIFollow = async (
51
+ authorization: AuthObject,
52
+ payload?: { offset?: number; count?: number }
53
+ ): Promise<UsersIFollow> => {
54
+ const queryParams: Record<string, number> = {};
55
+ if (payload?.offset !== null && payload?.offset !== undefined) {
56
+ queryParams.o = payload.offset;
57
+ }
58
+ if (payload?.count !== null && payload?.count !== undefined) {
59
+ queryParams.c = payload.count;
60
+ }
61
+
62
+ const url = buildRequestUrl(
63
+ apiBaseUrl,
64
+ "/API_GetUsersIFollow.php",
65
+ authorization,
66
+ queryParams
67
+ );
68
+
69
+ const rawResponse = await call<GetUsersIFollowResponse>({ url });
70
+
71
+ return serializeProperties(rawResponse, {
72
+ shouldCastToNumbers: ["Points", "PointsSoftcore"],
73
+ shouldMapToBooleans: ["IsFollowingMe"],
74
+ });
75
+ };
package/src/user/index.ts CHANGED
@@ -11,6 +11,7 @@ export * from "./getUserProfile";
11
11
  export * from "./getUserProgress";
12
12
  export * from "./getUserRecentAchievements";
13
13
  export * from "./getUserRecentlyPlayedGames";
14
+ export * from "./getUsersIFollow";
14
15
  export * from "./getUserSummary";
15
16
  export * from "./getUserWantToPlayList";
16
17
  export * from "./models";
@@ -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;
@@ -0,0 +1,11 @@
1
+ export interface GetUsersIFollowResponse {
2
+ Count: number;
3
+ Total: number;
4
+ Results: Array<{
5
+ User: string;
6
+ ULID: string;
7
+ Points: number;
8
+ PointsSoftcore: number;
9
+ IsFollowingMe: boolean;
10
+ }>;
11
+ }
@@ -14,6 +14,7 @@ export * from "./get-user-recent-achievements-response.model";
14
14
  export * from "./get-user-recently-played-games-response.model";
15
15
  export * from "./get-user-summary-response.model";
16
16
  export * from "./get-user-want-to-play-list-response.model";
17
+ export * from "./get-users-i-follow-response.model";
17
18
  export * from "./user-awards.model";
18
19
  export * from "./user-claims.model";
19
20
  export * from "./user-claims-response.model";
@@ -28,3 +29,4 @@ export * from "./user-recent-achievement.model";
28
29
  export * from "./user-recently-played-games.model";
29
30
  export * from "./user-summary.model";
30
31
  export * from "./user-want-to-play-list.model";
32
+ export * from "./users-i-follow.model";
@@ -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;
@@ -0,0 +1,11 @@
1
+ export interface UsersIFollow {
2
+ count: number;
3
+ total: number;
4
+ results: Array<{
5
+ user: string;
6
+ ulid: string;
7
+ points: number;
8
+ pointsSoftcore: number;
9
+ isFollowingMe: boolean;
10
+ }>;
11
+ }
@@ -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