@retroachievements/api 0.0.0-development

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 (225) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +103 -0
  3. package/dist/__playground.d.ts +7 -0
  4. package/dist/achievement/getAchievementUnlocks.d.ts +45 -0
  5. package/dist/achievement/index.d.ts +2 -0
  6. package/dist/achievement/models/achievement-unlock-entity.model.d.ts +6 -0
  7. package/dist/achievement/models/get-achievement-unlocks-response.model.d.ts +8 -0
  8. package/dist/achievement/models/index.d.ts +2 -0
  9. package/dist/api.cjs.development.js +2363 -0
  10. package/dist/api.cjs.development.js.map +1 -0
  11. package/dist/api.cjs.production.min.js +2 -0
  12. package/dist/api.cjs.production.min.js.map +1 -0
  13. package/dist/api.esm.js +2333 -0
  14. package/dist/api.esm.js.map +1 -0
  15. package/dist/console/getConsoleIds.d.ts +22 -0
  16. package/dist/console/getGameList.d.ts +52 -0
  17. package/dist/console/index.d.ts +3 -0
  18. package/dist/console/models/console-id.model.d.ts +4 -0
  19. package/dist/console/models/game-list.model.d.ts +15 -0
  20. package/dist/console/models/get-console-ids-response.model.d.ts +4 -0
  21. package/dist/console/models/get-game-list-response.model.d.ts +15 -0
  22. package/dist/console/models/index.d.ts +4 -0
  23. package/dist/feed/getAchievementOfTheWeek.d.ts +48 -0
  24. package/dist/feed/getActiveClaims.d.ts +38 -0
  25. package/dist/feed/getTicketData.d.ts +158 -0
  26. package/dist/feed/getTopTenUsers.d.ts +24 -0
  27. package/dist/feed/index.d.ts +5 -0
  28. package/dist/feed/models/achievement-of-the-week.model.d.ts +32 -0
  29. package/dist/feed/models/achievement-ticket-stats-response.model.d.ts +7 -0
  30. package/dist/feed/models/achievement-ticket-stats.model.d.ts +7 -0
  31. package/dist/feed/models/active-claim.model.d.ts +49 -0
  32. package/dist/feed/models/game-ticket-stats.model.d.ts +9 -0
  33. package/dist/feed/models/game-tickets-response.model.d.ts +7 -0
  34. package/dist/feed/models/get-achievement-of-the-week-response.model.d.ts +32 -0
  35. package/dist/feed/models/get-active-claims-response.model.d.ts +19 -0
  36. package/dist/feed/models/get-top-ten-users-response.model.d.ts +10 -0
  37. package/dist/feed/models/index.d.ts +19 -0
  38. package/dist/feed/models/most-ticketed-games-response.model.d.ts +12 -0
  39. package/dist/feed/models/most-ticketed-games.model.d.ts +12 -0
  40. package/dist/feed/models/recent-tickets-response.model.d.ts +6 -0
  41. package/dist/feed/models/recent-tickets.model.d.ts +6 -0
  42. package/dist/feed/models/response-ticket-entity.model.d.ts +24 -0
  43. package/dist/feed/models/ticket-entity.model.d.ts +24 -0
  44. package/dist/feed/models/tickets-by-user-response.model.d.ts +8 -0
  45. package/dist/feed/models/top-ten-users-entity.model.d.ts +5 -0
  46. package/dist/feed/models/top-ten-users.model.d.ts +2 -0
  47. package/dist/feed/models/user-ticket-stats.model.d.ts +8 -0
  48. package/dist/game/getAchievementCount.d.ts +31 -0
  49. package/dist/game/getAchievementDistribution.d.ts +57 -0
  50. package/dist/game/getGame.d.ts +48 -0
  51. package/dist/game/getGameExtended.d.ts +68 -0
  52. package/dist/game/getGameRankAndScore.d.ts +38 -0
  53. package/dist/game/getGameRating.d.ts +38 -0
  54. package/dist/game/index.d.ts +7 -0
  55. package/dist/game/models/achievement-count.model.d.ts +4 -0
  56. package/dist/game/models/achievement-distribution-flags.model.d.ts +4 -0
  57. package/dist/game/models/game-extended-achievement-entity.model.d.ts +15 -0
  58. package/dist/game/models/game-extended-claim-entity.model.d.ts +7 -0
  59. package/dist/game/models/game-extended.model.d.ts +25 -0
  60. package/dist/game/models/game-rank-and-score-entity.model.d.ts +6 -0
  61. package/dist/game/models/game-rating.model.d.ts +9 -0
  62. package/dist/game/models/game.model.d.ts +19 -0
  63. package/dist/game/models/get-achievement-count-response.model.d.ts +4 -0
  64. package/dist/game/models/get-achievement-distribution-response.model.d.ts +1 -0
  65. package/dist/game/models/get-game-extended-response.model.d.ts +50 -0
  66. package/dist/game/models/get-game-rank-and-score-response.model.d.ts +8 -0
  67. package/dist/game/models/get-game-rating-response.model.d.ts +9 -0
  68. package/dist/game/models/get-game-response.model.d.ts +19 -0
  69. package/dist/game/models/index.d.ts +14 -0
  70. package/dist/index.d.ts +6 -0
  71. package/dist/index.js +8 -0
  72. package/dist/user/getAchievementsEarnedBetween.d.ts +59 -0
  73. package/dist/user/getAchievementsEarnedOnDay.d.ts +57 -0
  74. package/dist/user/getGameInfoAndUserProgress.d.ts +80 -0
  75. package/dist/user/getUserGameRankAndScore.d.ts +44 -0
  76. package/dist/user/getUserPoints.d.ts +30 -0
  77. package/dist/user/getUserProgress.d.ts +49 -0
  78. package/dist/user/getUserRecentlyPlayedGames.d.ts +50 -0
  79. package/dist/user/getUserSummary.d.ts +32 -0
  80. package/dist/user/index.d.ts +9 -0
  81. package/dist/user/models/dated-user-achievement.model.d.ts +17 -0
  82. package/dist/user/models/dated-user-achievements-response.model.d.ts +19 -0
  83. package/dist/user/models/game-info-and-user-progress.model.d.ts +12 -0
  84. package/dist/user/models/get-game-info-and-user-progress-response.model.d.ts +14 -0
  85. package/dist/user/models/get-user-game-rank-and-score-response.model.d.ts +8 -0
  86. package/dist/user/models/get-user-points-response.model.d.ts +4 -0
  87. package/dist/user/models/get-user-progress-response.model.d.ts +10 -0
  88. package/dist/user/models/get-user-recently-played-games-response.model.d.ts +16 -0
  89. package/dist/user/models/get-user-summary-response.model.d.ts +82 -0
  90. package/dist/user/models/index.d.ts +14 -0
  91. package/dist/user/models/user-game-rank-and-score.model.d.ts +8 -0
  92. package/dist/user/models/user-points.model.d.ts +4 -0
  93. package/dist/user/models/user-progress.model.d.ts +10 -0
  94. package/dist/user/models/user-recently-played-games.model.d.ts +16 -0
  95. package/dist/user/models/user-summary.model.d.ts +83 -0
  96. package/dist/utils/internal/apiBaseUrl.d.ts +1 -0
  97. package/dist/utils/internal/buildRequestUrl.d.ts +2 -0
  98. package/dist/utils/internal/call.d.ts +20 -0
  99. package/dist/utils/internal/index.d.ts +4 -0
  100. package/dist/utils/internal/serializeProperties.d.ts +4 -0
  101. package/dist/utils/public/buildAuthorization.d.ts +22 -0
  102. package/dist/utils/public/index.d.ts +3 -0
  103. package/dist/utils/public/models/auth-object.model.d.ts +19 -0
  104. package/dist/utils/public/models/index.d.ts +1 -0
  105. package/package.json +117 -0
  106. package/src/__playground.ts +27 -0
  107. package/src/achievement/getAchievementUnlocks.test.ts +71 -0
  108. package/src/achievement/getAchievementUnlocks.ts +80 -0
  109. package/src/achievement/index.ts +2 -0
  110. package/src/achievement/models/achievement-unlock-entity.model.ts +6 -0
  111. package/src/achievement/models/get-achievement-unlocks-response.model.ts +8 -0
  112. package/src/achievement/models/index.ts +2 -0
  113. package/src/console/getConsoleIds.test.ts +53 -0
  114. package/src/console/getConsoleIds.ts +43 -0
  115. package/src/console/getGameList.test.ts +82 -0
  116. package/src/console/getGameList.ts +94 -0
  117. package/src/console/index.ts +3 -0
  118. package/src/console/models/console-id.model.ts +4 -0
  119. package/src/console/models/game-list.model.ts +16 -0
  120. package/src/console/models/get-console-ids-response.model.ts +1 -0
  121. package/src/console/models/get-game-list-response.model.ts +16 -0
  122. package/src/console/models/index.ts +4 -0
  123. package/src/feed/getAchievementOfTheWeek.test.ts +167 -0
  124. package/src/feed/getAchievementOfTheWeek.ts +80 -0
  125. package/src/feed/getActiveClaims.test.ts +81 -0
  126. package/src/feed/getActiveClaims.ts +68 -0
  127. package/src/feed/getTicketData.test.ts +349 -0
  128. package/src/feed/getTicketData.ts +286 -0
  129. package/src/feed/getTopTenUsers.test.ts +101 -0
  130. package/src/feed/getTopTenUsers.ts +51 -0
  131. package/src/feed/index.ts +5 -0
  132. package/src/feed/models/achievement-of-the-week.model.ts +27 -0
  133. package/src/feed/models/achievement-ticket-stats-response.model.ts +7 -0
  134. package/src/feed/models/achievement-ticket-stats.model.ts +7 -0
  135. package/src/feed/models/active-claim.model.ts +66 -0
  136. package/src/feed/models/game-ticket-stats.model.ts +11 -0
  137. package/src/feed/models/game-tickets-response.model.ts +7 -0
  138. package/src/feed/models/get-achievement-of-the-week-response.model.ts +27 -0
  139. package/src/feed/models/get-active-claims-response.model.ts +19 -0
  140. package/src/feed/models/get-top-ten-users-response.model.ts +12 -0
  141. package/src/feed/models/index.ts +19 -0
  142. package/src/feed/models/most-ticketed-games-response.model.ts +12 -0
  143. package/src/feed/models/most-ticketed-games.model.ts +12 -0
  144. package/src/feed/models/recent-tickets-response.model.ts +7 -0
  145. package/src/feed/models/recent-tickets.model.ts +7 -0
  146. package/src/feed/models/response-ticket-entity.model.ts +25 -0
  147. package/src/feed/models/ticket-entity.model.ts +24 -0
  148. package/src/feed/models/tickets-by-user-response.model.ts +8 -0
  149. package/src/feed/models/top-ten-users-entity.model.ts +5 -0
  150. package/src/feed/models/top-ten-users.model.ts +3 -0
  151. package/src/feed/models/user-ticket-stats.model.ts +8 -0
  152. package/src/game/getAchievementCount.test.ts +49 -0
  153. package/src/game/getAchievementCount.ts +52 -0
  154. package/src/game/getAchievementDistribution.test.ts +187 -0
  155. package/src/game/getAchievementDistribution.ts +88 -0
  156. package/src/game/getGame.test.ts +81 -0
  157. package/src/game/getGame.ts +74 -0
  158. package/src/game/getGameExtended.test.ts +121 -0
  159. package/src/game/getGameExtended.ts +103 -0
  160. package/src/game/getGameRankAndScore.test.ts +62 -0
  161. package/src/game/getGameRankAndScore.ts +66 -0
  162. package/src/game/getGameRating.test.ts +59 -0
  163. package/src/game/getGameRating.ts +59 -0
  164. package/src/game/index.ts +7 -0
  165. package/src/game/models/achievement-count.model.ts +4 -0
  166. package/src/game/models/achievement-distribution-flags.model.ts +4 -0
  167. package/src/game/models/game-extended-achievement-entity.model.ts +15 -0
  168. package/src/game/models/game-extended-claim-entity.model.ts +7 -0
  169. package/src/game/models/game-extended.model.ts +26 -0
  170. package/src/game/models/game-rank-and-score-entity.model.ts +6 -0
  171. package/src/game/models/game-rating.model.ts +9 -0
  172. package/src/game/models/game.model.ts +19 -0
  173. package/src/game/models/get-achievement-count-response.model.ts +4 -0
  174. package/src/game/models/get-achievement-distribution-response.model.ts +1 -0
  175. package/src/game/models/get-game-extended-response.model.ts +56 -0
  176. package/src/game/models/get-game-rank-and-score-response.model.ts +8 -0
  177. package/src/game/models/get-game-rating-response.model.ts +9 -0
  178. package/src/game/models/get-game-response.model.ts +19 -0
  179. package/src/game/models/index.ts +14 -0
  180. package/src/index.ts +8 -0
  181. package/src/user/getAchievementsEarnedBetween.test.ts +84 -0
  182. package/src/user/getAchievementsEarnedBetween.ts +88 -0
  183. package/src/user/getAchievementsEarnedOnDay.test.ts +83 -0
  184. package/src/user/getAchievementsEarnedOnDay.ts +87 -0
  185. package/src/user/getGameInfoAndUserProgress.test.ts +135 -0
  186. package/src/user/getGameInfoAndUserProgress.ts +118 -0
  187. package/src/user/getUserGameRankAndScore.test.ts +60 -0
  188. package/src/user/getUserGameRankAndScore.ts +69 -0
  189. package/src/user/getUserPoints.test.ts +49 -0
  190. package/src/user/getUserPoints.ts +51 -0
  191. package/src/user/getUserProgress.test.ts +80 -0
  192. package/src/user/getUserProgress.ts +78 -0
  193. package/src/user/getUserRecentlyPlayedGames.test.ts +76 -0
  194. package/src/user/getUserRecentlyPlayedGames.ts +93 -0
  195. package/src/user/getUserSummary.test.ts +251 -0
  196. package/src/user/getUserSummary.ts +96 -0
  197. package/src/user/index.ts +9 -0
  198. package/src/user/models/dated-user-achievement.model.ts +17 -0
  199. package/src/user/models/dated-user-achievements-response.model.ts +20 -0
  200. package/src/user/models/game-info-and-user-progress.model.ts +19 -0
  201. package/src/user/models/get-game-info-and-user-progress-response.model.ts +28 -0
  202. package/src/user/models/get-user-game-rank-and-score-response.model.ts +9 -0
  203. package/src/user/models/get-user-points-response.model.ts +4 -0
  204. package/src/user/models/get-user-progress-response.model.ts +13 -0
  205. package/src/user/models/get-user-recently-played-games-response.model.ts +17 -0
  206. package/src/user/models/get-user-summary-response.model.ts +92 -0
  207. package/src/user/models/index.ts +14 -0
  208. package/src/user/models/user-game-rank-and-score.model.ts +8 -0
  209. package/src/user/models/user-points.model.ts +4 -0
  210. package/src/user/models/user-progress.model.ts +10 -0
  211. package/src/user/models/user-recently-played-games.model.ts +16 -0
  212. package/src/user/models/user-summary.model.ts +92 -0
  213. package/src/utils/internal/apiBaseUrl.ts +1 -0
  214. package/src/utils/internal/buildRequestUrl.test.ts +51 -0
  215. package/src/utils/internal/buildRequestUrl.ts +32 -0
  216. package/src/utils/internal/call.test.ts +39 -0
  217. package/src/utils/internal/call.ts +29 -0
  218. package/src/utils/internal/index.ts +4 -0
  219. package/src/utils/internal/serializeProperties.test.ts +141 -0
  220. package/src/utils/internal/serializeProperties.ts +75 -0
  221. package/src/utils/public/buildAuthorization.test.ts +36 -0
  222. package/src/utils/public/buildAuthorization.ts +40 -0
  223. package/src/utils/public/index.ts +3 -0
  224. package/src/utils/public/models/auth-object.model.ts +20 -0
  225. package/src/utils/public/models/index.ts +1 -0
@@ -0,0 +1,68 @@
1
+ import {
2
+ apiBaseUrl,
3
+ buildRequestUrl,
4
+ call,
5
+ serializeProperties
6
+ } from "../utils/internal";
7
+ import type { AuthObject } from "../utils/public";
8
+ import type { ActiveClaim, GetActiveClaimsResponse } from "./models";
9
+
10
+ /**
11
+ * A call to this function returns information about all
12
+ * (1000 max) active set claims.
13
+ *
14
+ * @param authorization An object containing your userName and webApiKey.
15
+ * This can be constructed with `buildAuthorization()`.
16
+ *
17
+ * @example
18
+ * ```
19
+ * const activeClaims = await getActiveClaims(authorization);
20
+ * ```
21
+ *
22
+ * @returns An array containing metadata about all active claims.
23
+ * ```
24
+ * [
25
+ * {
26
+ * id: 7044,
27
+ * user: "blendedsea",
28
+ * gameId: 19212,
29
+ * gameTitle: "SpongeBob SquarePants: Battle for Bikini Bottom",
30
+ * gameIcon: "/Images/059776.png",
31
+ * consoleName: "PlayStation 2",
32
+ * claimType: 0,
33
+ * setType: 0,
34
+ * status: 0,
35
+ * extension: 0,
36
+ * special: 0,
37
+ * created: "2022-10-04 00:25:06",
38
+ * doneTime: "2023-01-04 00:25:06",
39
+ * updated: "2022-10-04 00:25:06",
40
+ * minutesLeft: 112523
41
+ * }
42
+ * ]
43
+ * ```
44
+ */
45
+ export const getActiveClaims = async (
46
+ authorization: AuthObject
47
+ ): Promise<ActiveClaim[]> => {
48
+ const url = buildRequestUrl(
49
+ apiBaseUrl,
50
+ "/API_GetActiveClaims.php",
51
+ authorization
52
+ );
53
+
54
+ const rawResponse = await call<GetActiveClaimsResponse>({ url });
55
+
56
+ return serializeProperties(rawResponse, {
57
+ shouldCastToNumbers: [
58
+ "ID",
59
+ "GameID",
60
+ "ClaimType",
61
+ "SetType",
62
+ "Status",
63
+ "Extension",
64
+ "Special",
65
+ "MinutesLeft"
66
+ ]
67
+ });
68
+ };
@@ -0,0 +1,349 @@
1
+ import { rest } from "msw";
2
+ import { setupServer } from "msw/node";
3
+
4
+ import { apiBaseUrl } from "../utils/internal";
5
+ import { buildAuthorization } from "../utils/public";
6
+ import { getTicketData } from "./getTicketData";
7
+ import type {
8
+ AchievementTicketStatsResponse,
9
+ GameTicketsResponse,
10
+ MostTicketedGamesResponse,
11
+ RecentTicketsResponse,
12
+ ResponseTicketEntity,
13
+ TicketsByUserResponse
14
+ } from "./models";
15
+
16
+ const server = setupServer();
17
+
18
+ describe("Function: getTicketData", () => {
19
+ // MSW Setup
20
+ beforeAll(() => server.listen());
21
+ afterEach(() => server.resetHandlers());
22
+ afterAll(() => server.close());
23
+
24
+ it("is defined #sanity", () => {
25
+ expect(getTicketData).toBeDefined();
26
+ });
27
+
28
+ it("given only a ticket ID, retrieves ticket data", async () => {
29
+ // ARRANGE
30
+ const authorization = buildAuthorization({
31
+ userName: "mockUserName",
32
+ webApiKey: "mockWebApiKey"
33
+ });
34
+
35
+ const mockResponse: ResponseTicketEntity = {
36
+ ID: "10000",
37
+ AchievementID: "3237",
38
+ AchievementTitle: "Laura's Weapons",
39
+ AchievementDesc: "Obtained all available weapons as Laura",
40
+ Points: "25",
41
+ BadgeName: "61993",
42
+ AchievementAuthor: "PManningFan1618",
43
+ GameID: "1474",
44
+ ConsoleName: "NES",
45
+ GameTitle: "Friday the 13th",
46
+ GameIcon: "/Images/062848.png",
47
+ ReportedAt: "2017-10-16 06:10:52",
48
+ ReportType: "1",
49
+ ReportState: "2",
50
+ Hardcore: null,
51
+ ReportNotes: "This lacks a ResetIf when the game is reset",
52
+ ReportedBy: "Thoreau",
53
+ ResolvedAt: "2019-11-15 01:50:41",
54
+ ResolvedBy: "televandalist",
55
+ ReportStateDescription: "Resolved",
56
+ ReportTypeDescription: "Triggered at the wrong time",
57
+ URL: "https://retroachievements.org/ticketmanager.php?i=10000"
58
+ };
59
+
60
+ server.use(
61
+ rest.get(`${apiBaseUrl}/API_GetTicketData.php`, (_, res, ctx) =>
62
+ res(ctx.json(mockResponse))
63
+ )
64
+ );
65
+
66
+ // ACT
67
+ const response = await getTicketData(authorization, { ticketId: 10_000 });
68
+
69
+ // ASSERT
70
+ expect(response).toEqual({
71
+ id: 10_000,
72
+ achievementId: 3237,
73
+ achievementTitle: "Laura's Weapons",
74
+ achievementDesc: "Obtained all available weapons as Laura",
75
+ points: 25,
76
+ badgeName: "61993",
77
+ achievementAuthor: "PManningFan1618",
78
+ gameId: 1474,
79
+ consoleName: "NES",
80
+ gameTitle: "Friday the 13th",
81
+ gameIcon: "/Images/062848.png",
82
+ reportedAt: "2017-10-16 06:10:52",
83
+ reportType: 1,
84
+ reportState: 2,
85
+ hardcore: null,
86
+ reportNotes: "This lacks a ResetIf when the game is reset",
87
+ reportedBy: "Thoreau",
88
+ resolvedAt: "2019-11-15 01:50:41",
89
+ resolvedBy: "televandalist",
90
+ reportStateDescription: "Resolved",
91
+ reportTypeDescription: "Triggered at the wrong time",
92
+ url: "https://retroachievements.org/ticketmanager.php?i=10000"
93
+ });
94
+ });
95
+
96
+ it("given no IDs, retrieves a list of recent tickets", async () => {
97
+ // ARRANGE
98
+ const authorization = buildAuthorization({
99
+ userName: "mockUserName",
100
+ webApiKey: "mockWebApiKey"
101
+ });
102
+
103
+ const mockResponse: RecentTicketsResponse = {
104
+ RecentTickets: [
105
+ {
106
+ ID: "55958",
107
+ AchievementID: "111994",
108
+ AchievementTitle: "Mandarin Mayhem Phone Mission #7-A",
109
+ AchievementDesc:
110
+ "Complete the Part 1 of 7th mission on Mandarin Mayhem chapter",
111
+ Points: "5",
112
+ BadgeName: "126387",
113
+ AchievementAuthor: "Hotscrock",
114
+ GameID: "10437",
115
+ ConsoleName: "PlayStation",
116
+ GameTitle: "Grand Theft Auto",
117
+ GameIcon: "/Images/050159.png",
118
+ ReportedAt: "2023-01-28 14:12:06",
119
+ ReportType: "2",
120
+ Hardcore: "1",
121
+ ReportNotes:
122
+ "Instead what popped was 7B achievement. A second game where i did complete both missions successfully did not trigger it either.\n" +
123
+ "RetroAchievements Hash: c39f4c56d4f9c6a1bdf746f5b2309ebf\n" +
124
+ "Emulator: RetroArch (Beetle PSX HW 0.9.44.1)\n" +
125
+ "Emulator Version: 1.14",
126
+ ReportedBy: "Erodion",
127
+ ResolvedAt: null,
128
+ ResolvedBy: null,
129
+ ReportState: "1",
130
+ ReportStateDescription: "Open",
131
+ ReportTypeDescription: "Did not trigger"
132
+ }
133
+ ],
134
+ OpenTickets: 715,
135
+ URL: "https://retroachievements.org/ticketmanager.php"
136
+ };
137
+
138
+ server.use(
139
+ rest.get(`${apiBaseUrl}/API_GetTicketData.php`, (_, res, ctx) =>
140
+ res(ctx.json(mockResponse))
141
+ )
142
+ );
143
+
144
+ // ACT
145
+ const response = await getTicketData(authorization);
146
+
147
+ // ASSERT
148
+ expect(response).toEqual({
149
+ recentTickets: [
150
+ {
151
+ id: 55_958,
152
+ achievementId: 111_994,
153
+ achievementTitle: "Mandarin Mayhem Phone Mission #7-A",
154
+ achievementDesc:
155
+ "Complete the Part 1 of 7th mission on Mandarin Mayhem chapter",
156
+ points: 5,
157
+ badgeName: "126387",
158
+ achievementAuthor: "Hotscrock",
159
+ gameId: 10_437,
160
+ consoleName: "PlayStation",
161
+ gameTitle: "Grand Theft Auto",
162
+ gameIcon: "/Images/050159.png",
163
+ reportedAt: "2023-01-28 14:12:06",
164
+ reportType: 2,
165
+ hardcore: true,
166
+ reportNotes:
167
+ "Instead what popped was 7B achievement. A second game where i did complete both missions successfully did not trigger it either.\n" +
168
+ "RetroAchievements Hash: c39f4c56d4f9c6a1bdf746f5b2309ebf\n" +
169
+ "Emulator: RetroArch (Beetle PSX HW 0.9.44.1)\n" +
170
+ "Emulator Version: 1.14",
171
+ reportedBy: "Erodion",
172
+ resolvedAt: null,
173
+ resolvedBy: null,
174
+ reportState: 1,
175
+ reportStateDescription: "Open",
176
+ reportTypeDescription: "Did not trigger"
177
+ }
178
+ ],
179
+ openTickets: 715,
180
+ url: "https://retroachievements.org/ticketmanager.php"
181
+ });
182
+ });
183
+
184
+ it("can retrieve a list of the most ticketed games", async () => {
185
+ // ARRANGE
186
+ const authorization = buildAuthorization({
187
+ userName: "mockUserName",
188
+ webApiKey: "mockWebApiKey"
189
+ });
190
+
191
+ const mockResponse: MostTicketedGamesResponse = {
192
+ MostReportedGames: [
193
+ {
194
+ GameID: "11588",
195
+ GameTitle: "Driver 2: The Wheelman Is Back",
196
+ GameIcon: "/Images/046592.png",
197
+ Console: "PlayStation",
198
+ OpenTickets: "16"
199
+ },
200
+ {
201
+ GameID: "5515",
202
+ GameTitle: "Ninja Ryuuken Den | Ninja Gaiden",
203
+ GameIcon: "/Images/020735.png",
204
+ Console: "PC Engine",
205
+ OpenTickets: "15"
206
+ }
207
+ ],
208
+ URL: "https://retroachievements.org/ticketmanager.php?f=1"
209
+ };
210
+
211
+ server.use(
212
+ rest.get(`${apiBaseUrl}/API_GetTicketData.php`, (_, res, ctx) =>
213
+ res(ctx.json(mockResponse))
214
+ )
215
+ );
216
+
217
+ // ACT
218
+ const response = await getTicketData(authorization, {
219
+ isGettingMostTicketedGames: true
220
+ });
221
+
222
+ // ASSERT
223
+ expect(response).toEqual({
224
+ mostReportedGames: [
225
+ {
226
+ gameId: 11_588,
227
+ gameTitle: "Driver 2: The Wheelman Is Back",
228
+ gameIcon: "/Images/046592.png",
229
+ console: "PlayStation",
230
+ openTickets: 16
231
+ },
232
+ {
233
+ gameId: 5515,
234
+ gameTitle: "Ninja Ryuuken Den | Ninja Gaiden",
235
+ gameIcon: "/Images/020735.png",
236
+ console: "PC Engine",
237
+ openTickets: 15
238
+ }
239
+ ],
240
+ url: "https://retroachievements.org/ticketmanager.php?f=1"
241
+ });
242
+ });
243
+
244
+ it("can retrieve metadata about a user's tickets", async () => {
245
+ // ARRANGE
246
+ const authorization = buildAuthorization({
247
+ userName: "mockUserName",
248
+ webApiKey: "mockWebApiKey"
249
+ });
250
+
251
+ const mockResponse: TicketsByUserResponse = {
252
+ User: "xelnia",
253
+ Open: 0,
254
+ Closed: 18,
255
+ Resolved: 51,
256
+ Total: 69,
257
+ URL: "https://retroachievements.org/ticketmanager.php?u=Jamiras"
258
+ };
259
+
260
+ server.use(
261
+ rest.get(`${apiBaseUrl}/API_GetTicketData.php`, (_, res, ctx) =>
262
+ res(ctx.json(mockResponse))
263
+ )
264
+ );
265
+
266
+ // ACT
267
+ const response = await getTicketData(authorization, { userName: "xelnia" });
268
+
269
+ // ASSERT
270
+ expect(response).toEqual({
271
+ user: "xelnia",
272
+ open: 0,
273
+ closed: 18,
274
+ resolved: 51,
275
+ total: 69,
276
+ url: "https://retroachievements.org/ticketmanager.php?u=Jamiras"
277
+ });
278
+ });
279
+
280
+ it("can retrieve metadata about a game's tickets", async () => {
281
+ // ARRANGE
282
+ const authorization = buildAuthorization({
283
+ userName: "mockUserName",
284
+ webApiKey: "mockWebApiKey"
285
+ });
286
+
287
+ const mockResponse: GameTicketsResponse = {
288
+ GameID: 10_329,
289
+ GameTitle: "Rampage 2: Universal Tour",
290
+ ConsoleName: "Nintendo 64",
291
+ OpenTickets: 8,
292
+ URL: "https://retroachievements.org/ticketmanager.php?g=10329"
293
+ };
294
+
295
+ server.use(
296
+ rest.get(`${apiBaseUrl}/API_GetTicketData.php`, (_, res, ctx) =>
297
+ res(ctx.json(mockResponse))
298
+ )
299
+ );
300
+
301
+ // ACT
302
+ const response = await getTicketData(authorization, { gameId: 10_329 });
303
+
304
+ // ASSERT
305
+ expect(response).toEqual({
306
+ gameId: 10_329,
307
+ gameTitle: "Rampage 2: Universal Tour",
308
+ consoleName: "Nintendo 64",
309
+ openTickets: 8,
310
+ url: "https://retroachievements.org/ticketmanager.php?g=10329"
311
+ });
312
+ });
313
+
314
+ it("can retrieve metadata about an achievement's tickets", async () => {
315
+ // ARRANGE
316
+ const authorization = buildAuthorization({
317
+ userName: "mockUserName",
318
+ webApiKey: "mockWebApiKey"
319
+ });
320
+
321
+ const mockResponse: AchievementTicketStatsResponse = {
322
+ AchievementID: 283_331,
323
+ AchievementTitle: "Blue Potaras Collector",
324
+ AchievementDescription: "Unlock all Ability Type Z-Items",
325
+ URL: "https://retroachievements.org/ticketmanager.php?a=283331",
326
+ OpenTickets: 1
327
+ };
328
+
329
+ server.use(
330
+ rest.get(`${apiBaseUrl}/API_GetTicketData.php`, (_, res, ctx) =>
331
+ res(ctx.json(mockResponse))
332
+ )
333
+ );
334
+
335
+ // ACT
336
+ const response = await getTicketData(authorization, {
337
+ achievementId: 283_331
338
+ });
339
+
340
+ // ASSERT
341
+ expect(response).toEqual({
342
+ achievementId: 283_331,
343
+ achievementTitle: "Blue Potaras Collector",
344
+ achievementDescription: "Unlock all Ability Type Z-Items",
345
+ url: "https://retroachievements.org/ticketmanager.php?a=283331",
346
+ openTickets: 1
347
+ });
348
+ });
349
+ });
@@ -0,0 +1,286 @@
1
+ import {
2
+ apiBaseUrl,
3
+ buildRequestUrl,
4
+ call,
5
+ serializeProperties
6
+ } from "../utils/internal";
7
+ import type { AuthObject } from "../utils/public";
8
+ import type {
9
+ AchievementTicketStats,
10
+ GameTicketStats,
11
+ MostTicketedGames,
12
+ RecentTickets,
13
+ TicketEntity,
14
+ UserTicketStats
15
+ } from "./models";
16
+
17
+ interface GetTicketDataAllPayloadValues {
18
+ ticketId?: string | number;
19
+ offset?: number;
20
+ count?: number;
21
+ isGettingMostTicketedGames?: true;
22
+ userName?: string;
23
+ gameId?: string | number;
24
+ isGettingTicketsForUnofficialAchievements?: true;
25
+ shouldReturnTicketsList?: true;
26
+ achievementId?: string | number;
27
+ }
28
+
29
+ /**
30
+ * BEGIN: Function overload definitions
31
+ */
32
+
33
+ /**
34
+ * A call to this function will retrieve ticket metadata information
35
+ * about a single ticket by its ticket ID.
36
+ *
37
+ * @param authorization An object containing your userName and webApiKey.
38
+ * This can be constructed with `buildAuthorization()`.
39
+ *
40
+ * @param payload.ticketId The ID of the ticket to get information about.
41
+ *
42
+ * @example
43
+ * ```
44
+ * const ticketData = await getTicketData(
45
+ * authorization,
46
+ * { ticketId: 12345 }
47
+ * );
48
+ * ```
49
+ *
50
+ * @returns An object containing metadata about a target ticket.
51
+ */
52
+ export function getTicketData(
53
+ authorization: AuthObject,
54
+ payload: { ticketId: string | number }
55
+ ): Promise<TicketEntity>;
56
+
57
+ /**
58
+ * A call to this function will retrieve ticket metadata information
59
+ * about the latest opened tickets on RetroAchievements.
60
+ *
61
+ * @param authorization An object containing your userName and webApiKey.
62
+ * This can be constructed with `buildAuthorization()`.
63
+ *
64
+ * @param payload.count Optional. Defaults to 10. Max is 100.
65
+ * How many tickets to retrieve.
66
+ *
67
+ * @param payload.offset Optional. Defaults to 0.
68
+ * Number of tickets to skip. This can be used for pagination.
69
+ *
70
+ * @example
71
+ * ```
72
+ * const ticketData = await getTicketData(authorization);
73
+ * ```
74
+ *
75
+ * @returns A list of the most recently opened tickets on the site.
76
+ */
77
+ export function getTicketData(
78
+ authorization: AuthObject,
79
+ payload?: Partial<{ offset: number; count: number }>
80
+ ): Promise<RecentTickets>;
81
+
82
+ /**
83
+ * A call to this function will retrieve the games on the site with
84
+ * the highest count of opened tickets.
85
+ *
86
+ * @param authorization An object containing your userName and webApiKey.
87
+ * This can be constructed with `buildAuthorization()`.
88
+ *
89
+ * @param payload.count Optional. Defaults to 10. Max is 100.
90
+ * How many ticketed games to retrieve.
91
+ *
92
+ * @param payload.offset Optional. Defaults to 0.
93
+ * Number of games to skip. This can be used for pagination.
94
+ *
95
+ * @example
96
+ * ```
97
+ * const ticketData = await getTicketData(
98
+ * authorization,
99
+ * { isGettingMostTicketedGames: true }
100
+ * );
101
+ * ```
102
+ *
103
+ * @returns A list of the most recently opened tickets on the site.
104
+ */
105
+ export function getTicketData(
106
+ authorization: AuthObject,
107
+ payload: { isGettingMostTicketedGames: true; offset?: number; count?: number }
108
+ ): Promise<MostTicketedGames>;
109
+
110
+ /**
111
+ * A call to this function will retrieve an achievement developer's
112
+ * ticket stats, targeted by that developer's username.
113
+ *
114
+ * @param authorization An object containing your userName and webApiKey.
115
+ * This can be constructed with `buildAuthorization()`.
116
+ *
117
+ * @param payload.userName The developer's account username to retrieve
118
+ * ticket stats for.
119
+ *
120
+ * @example
121
+ * ```
122
+ * const ticketData = await getTicketData(
123
+ * authorization,
124
+ * { userName: "xelnia" }
125
+ * );
126
+ * ```
127
+ *
128
+ * @returns An achievement developer's ticket stats.
129
+ */
130
+ export function getTicketData(
131
+ authorization: AuthObject,
132
+ payload: { userName: string }
133
+ ): Promise<UserTicketStats>;
134
+
135
+ /**
136
+ * A call to this function will retrieve a game's ticket stats, targeted
137
+ * by the game's ID. If you are unsure of a game's ID, visit its page
138
+ * on the RetroAchievements website and copy the number at the end of the URL.
139
+ *
140
+ * @param authorization An object containing your userName and webApiKey.
141
+ * This can be constructed with `buildAuthorization()`.
142
+ *
143
+ * @param payload.gameId The game ID to fetch ticket stats for.
144
+ *
145
+ * @param payload.isGettingTicketsForUnofficialAchievements Optional. Fetch stats
146
+ * for unofficial/non-core achievements that have tickets.
147
+ *
148
+ * @param payload.shouldReturnTicketsList Optional. If true, not only fetches a
149
+ * game's ticket stats, but also returns a list of tickets for the game.
150
+ *
151
+ * @example
152
+ * ```
153
+ * const ticketData = await getTicketData(
154
+ * authorization,
155
+ * { gameId: 14_402 }
156
+ * );
157
+ * ```
158
+ *
159
+ * @returns A game's ticket stats, potentially also including the ticket list.
160
+ */
161
+ export function getTicketData(
162
+ authorization: AuthObject,
163
+ payload: {
164
+ gameId: string | number;
165
+ isGettingTicketsForUnofficialAchievements?: true;
166
+ shouldReturnTicketsList?: true;
167
+ }
168
+ ): Promise<GameTicketStats>;
169
+
170
+ /**
171
+ * A call to this function will retrieve the an achievement's
172
+ * ticket stats, targeted by the achievement's ID. If you are unsure
173
+ * of an achievement's ID, open its page on the RetroAchievements
174
+ * website and copy the number at the end of the URL.
175
+ *
176
+ * @param authorization An object containing your userName and webApiKey.
177
+ * This can be constructed with `buildAuthorization()`.
178
+ *
179
+ * @param payload.achievementId The ID of the achievement to fetch ticket
180
+ * stats for.
181
+ *
182
+ * @example
183
+ * ```
184
+ * const ticketData = await getTicketData(
185
+ * authorization,
186
+ * { achievementId: 12345 }
187
+ * );
188
+ * ```
189
+ *
190
+ * @returns An achievement developer's ticket stats.
191
+ */
192
+ export function getTicketData(
193
+ authorization: AuthObject,
194
+ payload: { achievementId: string | number }
195
+ ): Promise<AchievementTicketStats>;
196
+
197
+ /**
198
+ * END: Function overload definitions
199
+ */
200
+
201
+ export async function getTicketData(
202
+ authorization: AuthObject,
203
+ payload: GetTicketDataAllPayloadValues = {}
204
+ ) {
205
+ const queryParams = buildGetTicketDataQueryParams(payload);
206
+
207
+ const url = buildRequestUrl(
208
+ apiBaseUrl,
209
+ "/API_GetTicketData.php",
210
+ authorization,
211
+ queryParams
212
+ );
213
+
214
+ const rawResponse = await call({ url });
215
+
216
+ return serializeProperties(rawResponse, {
217
+ shouldCastToNumbers: [
218
+ "ID",
219
+ "AchievementID",
220
+ "Points",
221
+ "GameID",
222
+ "ReportType",
223
+ "ReportState",
224
+ "OpenTickets"
225
+ ],
226
+ shouldMapToBooleans: ["Hardcore"]
227
+ });
228
+ }
229
+
230
+ const buildGetTicketDataQueryParams = (
231
+ payload: GetTicketDataAllPayloadValues
232
+ ) => {
233
+ const {
234
+ ticketId,
235
+ isGettingMostTicketedGames,
236
+ userName,
237
+ gameId,
238
+ isGettingTicketsForUnofficialAchievements,
239
+ shouldReturnTicketsList,
240
+ achievementId
241
+ } = payload;
242
+
243
+ let queryParams: Record<string, string | number> = {};
244
+
245
+ if (ticketId !== undefined) {
246
+ queryParams["i"] = ticketId;
247
+ } else if (isGettingMostTicketedGames) {
248
+ queryParams["f"] = "1";
249
+ queryParams = applyPaginationQueryParams(queryParams, payload);
250
+ } else if (userName) {
251
+ queryParams["u"] = userName;
252
+ } else if (gameId) {
253
+ queryParams["g"] = gameId;
254
+
255
+ if (isGettingTicketsForUnofficialAchievements) {
256
+ queryParams["f"] = "5";
257
+ }
258
+
259
+ if (shouldReturnTicketsList) {
260
+ queryParams["d"] = "1";
261
+ }
262
+ } else if (achievementId) {
263
+ queryParams["a"] = achievementId;
264
+ } else {
265
+ queryParams = applyPaginationQueryParams(queryParams, payload);
266
+ }
267
+
268
+ return queryParams;
269
+ };
270
+
271
+ const applyPaginationQueryParams = (
272
+ currentParams: Record<string, string | number>,
273
+ payload: Partial<{ count: number; offset: number }>
274
+ ) => {
275
+ const modifiedParams = { ...currentParams };
276
+
277
+ if (payload.count !== undefined) {
278
+ modifiedParams["c"] = payload.count;
279
+ }
280
+
281
+ if (payload.offset !== undefined) {
282
+ modifiedParams["o"] = payload.offset;
283
+ }
284
+
285
+ return modifiedParams;
286
+ };