clashofclans.js 2.0.0-dev.dedb83d → 2.0.1-dev.ba82327
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.
- package/CHANGELOG.md +13 -5
- package/README.md +4 -3
- package/dist/client/Client.d.ts +29 -11
- package/dist/client/Client.js +38 -18
- package/dist/client/EventManager.d.ts +12 -12
- package/dist/client/EventManager.js +45 -26
- package/dist/rest/HTTPError.d.ts +8 -5
- package/dist/rest/HTTPError.js +4 -6
- package/dist/rest/RESTManager.d.ts +49 -144
- package/dist/rest/RESTManager.js +27 -4
- package/dist/rest/RequestHandler.d.ts +14 -7
- package/dist/rest/RequestHandler.js +39 -18
- package/dist/rest/Throttler.d.ts +0 -4
- package/dist/struct/Clan.d.ts +3 -2
- package/dist/struct/Clan.js +3 -3
- package/dist/struct/ClanMember.d.ts +2 -1
- package/dist/struct/ClanMember.js +2 -2
- package/dist/struct/ClanWarLeagueGroup.d.ts +6 -4
- package/dist/struct/ClanWarLeagueGroup.js +9 -8
- package/dist/struct/Player.d.ts +2 -1
- package/dist/struct/Player.js +7 -5
- package/dist/struct/PlayerClan.d.ts +9 -4
- package/dist/struct/PlayerClan.js +4 -4
- package/dist/struct/Ranking.d.ts +25 -5
- package/dist/struct/Ranking.js +21 -5
- package/dist/struct/Unit.d.ts +37 -4
- package/dist/struct/Unit.js +49 -9
- package/dist/types/index.d.ts +4 -6
- package/dist/util/raw.json +1 -0
- package/package.json +1 -1
|
@@ -2,150 +2,55 @@ import { RequestHandler, SearchOptions, ClanSearchOptions, ClientOptions, Overri
|
|
|
2
2
|
import { APIClan, APIClanList, APIClanMemberList, APIClanRankingList, APIClanVersusRankingList, APIClanWar, APIClanWarLeagueGroup, APIClanWarLog, APIGoldPassSeason, APILabelList, APILeague, APILeagueList, APILeagueSeasonList, APILocation, APILocationList, APIPlayer, APIPlayerRankingList, APIPlayerSeasonRankingList, APIPlayerVersusRankingList, APIVerifyToken, APIWarLeague, APIWarLeagueList } from '../types';
|
|
3
3
|
/** Represents a REST Manager of the client. */
|
|
4
4
|
export declare class RESTManager {
|
|
5
|
+
/** Request Handler for the RESTManager. */
|
|
5
6
|
readonly handler: RequestHandler;
|
|
6
7
|
constructor(options?: ClientOptions);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
postPlayerToken(playerTag: string, token: string, options?: OverrideOptions): Promise<{
|
|
56
|
-
data: APIVerifyToken;
|
|
57
|
-
maxAge: number;
|
|
58
|
-
status: number;
|
|
59
|
-
path: string;
|
|
60
|
-
}>;
|
|
61
|
-
getLeagues(options?: SearchOptions): Promise<{
|
|
62
|
-
data: APILeagueList;
|
|
63
|
-
maxAge: number;
|
|
64
|
-
status: number;
|
|
65
|
-
path: string;
|
|
66
|
-
}>;
|
|
67
|
-
getLeague(leagueId: string | number, options?: OverrideOptions): Promise<{
|
|
68
|
-
data: APILeague;
|
|
69
|
-
maxAge: number;
|
|
70
|
-
status: number;
|
|
71
|
-
path: string;
|
|
72
|
-
}>;
|
|
73
|
-
getLeagueSeasons(leagueId: number, options?: SearchOptions): Promise<{
|
|
74
|
-
data: APILeagueSeasonList;
|
|
75
|
-
maxAge: number;
|
|
76
|
-
status: number;
|
|
77
|
-
path: string;
|
|
78
|
-
}>;
|
|
79
|
-
getSeasonRankings(leagueId: number, seasonId: string, options?: SearchOptions): Promise<{
|
|
80
|
-
data: APIPlayerSeasonRankingList;
|
|
81
|
-
maxAge: number;
|
|
82
|
-
status: number;
|
|
83
|
-
path: string;
|
|
84
|
-
}>;
|
|
85
|
-
getWarLeagues(options?: SearchOptions): Promise<{
|
|
86
|
-
data: APIWarLeagueList;
|
|
87
|
-
maxAge: number;
|
|
88
|
-
status: number;
|
|
89
|
-
path: string;
|
|
90
|
-
}>;
|
|
91
|
-
getWarLeague(leagueId: number, options?: OverrideOptions): Promise<{
|
|
92
|
-
data: APIWarLeague;
|
|
93
|
-
maxAge: number;
|
|
94
|
-
status: number;
|
|
95
|
-
path: string;
|
|
96
|
-
}>;
|
|
97
|
-
getLocations(options?: SearchOptions): Promise<{
|
|
98
|
-
data: APILocationList;
|
|
99
|
-
maxAge: number;
|
|
100
|
-
status: number;
|
|
101
|
-
path: string;
|
|
102
|
-
}>;
|
|
103
|
-
getLocation(locationId: number, options?: OverrideOptions): Promise<{
|
|
104
|
-
data: APILocation;
|
|
105
|
-
maxAge: number;
|
|
106
|
-
status: number;
|
|
107
|
-
path: string;
|
|
108
|
-
}>;
|
|
109
|
-
getClanRanks(locationId: number | string, options?: SearchOptions): Promise<{
|
|
110
|
-
data: APIClanRankingList;
|
|
111
|
-
maxAge: number;
|
|
112
|
-
status: number;
|
|
113
|
-
path: string;
|
|
114
|
-
}>;
|
|
115
|
-
getPlayerRanks(locationId: number | string, options?: SearchOptions): Promise<{
|
|
116
|
-
data: APIPlayerRankingList;
|
|
117
|
-
maxAge: number;
|
|
118
|
-
status: number;
|
|
119
|
-
path: string;
|
|
120
|
-
}>;
|
|
121
|
-
getVersusClanRanks(locationId: number | string, options?: SearchOptions): Promise<{
|
|
122
|
-
data: APIClanVersusRankingList;
|
|
123
|
-
maxAge: number;
|
|
124
|
-
status: number;
|
|
125
|
-
path: string;
|
|
126
|
-
}>;
|
|
127
|
-
getVersusPlayerRanks(locationId: number | string, options?: SearchOptions): Promise<{
|
|
128
|
-
data: APIPlayerVersusRankingList;
|
|
129
|
-
maxAge: number;
|
|
130
|
-
status: number;
|
|
131
|
-
path: string;
|
|
132
|
-
}>;
|
|
133
|
-
getClanLabels(options?: SearchOptions): Promise<{
|
|
134
|
-
data: APILabelList;
|
|
135
|
-
maxAge: number;
|
|
136
|
-
status: number;
|
|
137
|
-
path: string;
|
|
138
|
-
}>;
|
|
139
|
-
getPlayerLabels(options?: SearchOptions): Promise<{
|
|
140
|
-
data: APILabelList;
|
|
141
|
-
maxAge: number;
|
|
142
|
-
status: number;
|
|
143
|
-
path: string;
|
|
144
|
-
}>;
|
|
145
|
-
getGoldPassSeason(options?: OverrideOptions): Promise<{
|
|
146
|
-
data: APIGoldPassSeason;
|
|
147
|
-
maxAge: number;
|
|
148
|
-
status: number;
|
|
149
|
-
path: string;
|
|
150
|
-
}>;
|
|
8
|
+
/** Search all clans by name and/or filtering the results using various criteria. */
|
|
9
|
+
getClans(query: ClanSearchOptions, options?: OverrideOptions): Promise<import("./RequestHandler").Response<APIClanList>>;
|
|
10
|
+
/** Get info about a clan. */
|
|
11
|
+
getClan(clanTag: string, options?: OverrideOptions): Promise<import("./RequestHandler").Response<APIClan>>;
|
|
12
|
+
/** Get list of clan members. */
|
|
13
|
+
getClanMembers(clanTag: string, options?: SearchOptions): Promise<import("./RequestHandler").Response<APIClanMemberList>>;
|
|
14
|
+
/** Get clan war log. */
|
|
15
|
+
getClanWarLog(clanTag: string, options?: SearchOptions): Promise<import("./RequestHandler").Response<APIClanWarLog>>;
|
|
16
|
+
/** Get info about currently running war in the clan. */
|
|
17
|
+
getCurrentWar(clanTag: string, options?: OverrideOptions): Promise<import("./RequestHandler").Response<APIClanWar>>;
|
|
18
|
+
/** Get info about clan war league. */
|
|
19
|
+
getClanWarLeagueGroup(clanTag: string, options?: OverrideOptions): Promise<import("./RequestHandler").Response<APIClanWarLeagueGroup>>;
|
|
20
|
+
/** Get info about a CWL round by WarTag. */
|
|
21
|
+
getClanWarLeagueRound(warTag: string, options?: OverrideOptions): Promise<import("./RequestHandler").Response<APIClanWar>>;
|
|
22
|
+
/** Get info about a player by tag. */
|
|
23
|
+
getPlayer(playerTag: string, options?: OverrideOptions): Promise<import("./RequestHandler").Response<APIPlayer>>;
|
|
24
|
+
/** Verify Player API token that can be found from the Game settings. */
|
|
25
|
+
verifyPlayerToken(playerTag: string, token: string, options?: OverrideOptions): Promise<import("./RequestHandler").Response<APIVerifyToken>>;
|
|
26
|
+
/** Get list of Leagues. */
|
|
27
|
+
getLeagues(options?: SearchOptions): Promise<import("./RequestHandler").Response<APILeagueList>>;
|
|
28
|
+
/** Get a League info. */
|
|
29
|
+
getLeague(leagueId: string | number, options?: OverrideOptions): Promise<import("./RequestHandler").Response<APILeague>>;
|
|
30
|
+
/** Get Legend League season Ids. */
|
|
31
|
+
getLeagueSeasons(leagueId: number, options?: SearchOptions): Promise<import("./RequestHandler").Response<APILeagueSeasonList>>;
|
|
32
|
+
/** Get Legend League season rankings by season Id. */
|
|
33
|
+
getSeasonRankings(leagueId: number, seasonId: string, options?: SearchOptions): Promise<import("./RequestHandler").Response<APIPlayerSeasonRankingList>>;
|
|
34
|
+
/** Get list of Clan War Leagues. */
|
|
35
|
+
getWarLeagues(options?: SearchOptions): Promise<import("./RequestHandler").Response<APIWarLeagueList>>;
|
|
36
|
+
/** Get info about a Clan War League. */
|
|
37
|
+
getWarLeague(leagueId: number, options?: OverrideOptions): Promise<import("./RequestHandler").Response<APIWarLeague>>;
|
|
38
|
+
/** Get list of Locations. */
|
|
39
|
+
getLocations(options?: SearchOptions): Promise<import("./RequestHandler").Response<APILocationList>>;
|
|
40
|
+
/** Get info about a Location. */
|
|
41
|
+
getLocation(locationId: number, options?: OverrideOptions): Promise<import("./RequestHandler").Response<APILocation>>;
|
|
42
|
+
/** Get clan rankings for a specific location. */
|
|
43
|
+
getClanRanks(locationId: number | string, options?: SearchOptions): Promise<import("./RequestHandler").Response<APIClanRankingList>>;
|
|
44
|
+
/** Get player rankings for a specific location. */
|
|
45
|
+
getPlayerRanks(locationId: number | string, options?: SearchOptions): Promise<import("./RequestHandler").Response<APIPlayerRankingList>>;
|
|
46
|
+
/** Get clan versus rankings for a specific location. */
|
|
47
|
+
getVersusClanRanks(locationId: number | string, options?: SearchOptions): Promise<import("./RequestHandler").Response<APIClanVersusRankingList>>;
|
|
48
|
+
/** Get player versus rankings for a specific location. */
|
|
49
|
+
getVersusPlayerRanks(locationId: number | string, options?: SearchOptions): Promise<import("./RequestHandler").Response<APIPlayerVersusRankingList>>;
|
|
50
|
+
/** Get list of clan labels. */
|
|
51
|
+
getClanLabels(options?: SearchOptions): Promise<import("./RequestHandler").Response<APILabelList>>;
|
|
52
|
+
/** Get list of player labels. */
|
|
53
|
+
getPlayerLabels(options?: SearchOptions): Promise<import("./RequestHandler").Response<APILabelList>>;
|
|
54
|
+
/** Get info about gold pass season. */
|
|
55
|
+
getGoldPassSeason(options?: OverrideOptions): Promise<import("./RequestHandler").Response<APIGoldPassSeason>>;
|
|
151
56
|
}
|
package/dist/rest/RESTManager.js
CHANGED
|
@@ -8,90 +8,113 @@ class RESTManager {
|
|
|
8
8
|
constructor(options) {
|
|
9
9
|
this.handler = new RequestHandler_1.RequestHandler(options);
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return this.handler.request(`/clans?${query}
|
|
11
|
+
/** Search all clans by name and/or filtering the results using various criteria. */
|
|
12
|
+
getClans(query, options) {
|
|
13
|
+
return this.handler.request(`/clans?${Util_1.Util.queryString(query)}`, options);
|
|
14
14
|
}
|
|
15
|
+
/** Get info about a clan. */
|
|
15
16
|
getClan(clanTag, options) {
|
|
16
17
|
return this.handler.request(`/clans/${Util_1.Util.encodeTag(clanTag)}`, options);
|
|
17
18
|
}
|
|
19
|
+
/** Get list of clan members. */
|
|
18
20
|
getClanMembers(clanTag, options) {
|
|
19
21
|
const query = Util_1.Util.queryString(options);
|
|
20
22
|
return this.handler.request(`/clans/${Util_1.Util.encodeTag(clanTag)}/members?${query}`, options);
|
|
21
23
|
}
|
|
24
|
+
/** Get clan war log. */
|
|
22
25
|
getClanWarLog(clanTag, options) {
|
|
23
26
|
const query = Util_1.Util.queryString(options);
|
|
24
27
|
return this.handler.request(`/clans/${Util_1.Util.encodeTag(clanTag)}/warlog?${query}`, options);
|
|
25
28
|
}
|
|
29
|
+
/** Get info about currently running war in the clan. */
|
|
26
30
|
getCurrentWar(clanTag, options) {
|
|
27
31
|
return this.handler.request(`/clans/${Util_1.Util.encodeTag(clanTag)}/currentwar`, options);
|
|
28
32
|
}
|
|
33
|
+
/** Get info about clan war league. */
|
|
29
34
|
getClanWarLeagueGroup(clanTag, options) {
|
|
30
35
|
return this.handler.request(`/clans/${Util_1.Util.encodeTag(clanTag)}/currentwar/leaguegroup`, options);
|
|
31
36
|
}
|
|
37
|
+
/** Get info about a CWL round by WarTag. */
|
|
32
38
|
getClanWarLeagueRound(warTag, options) {
|
|
33
39
|
return this.handler.request(`/clanwarleagues/wars/${Util_1.Util.encodeTag(warTag)}`, options);
|
|
34
40
|
}
|
|
41
|
+
/** Get info about a player by tag. */
|
|
35
42
|
getPlayer(playerTag, options) {
|
|
36
43
|
return this.handler.request(`/players/${Util_1.Util.encodeTag(playerTag)}`, options);
|
|
37
44
|
}
|
|
38
|
-
|
|
45
|
+
/** Verify Player API token that can be found from the Game settings. */
|
|
46
|
+
verifyPlayerToken(playerTag, token, options) {
|
|
39
47
|
const opts = { method: 'POST', body: JSON.stringify({ token }), ...options };
|
|
40
48
|
return this.handler.request(`/players/${Util_1.Util.encodeTag(playerTag)}/verifytoken`, opts);
|
|
41
49
|
}
|
|
50
|
+
/** Get list of Leagues. */
|
|
42
51
|
getLeagues(options) {
|
|
43
52
|
const query = Util_1.Util.queryString(options);
|
|
44
53
|
return this.handler.request(`/leagues?${query}`, options);
|
|
45
54
|
}
|
|
55
|
+
/** Get a League info. */
|
|
46
56
|
getLeague(leagueId, options) {
|
|
47
57
|
return this.handler.request(`/leagues/${leagueId}`, options);
|
|
48
58
|
}
|
|
59
|
+
/** Get Legend League season Ids. */
|
|
49
60
|
getLeagueSeasons(leagueId, options) {
|
|
50
61
|
const query = Util_1.Util.queryString(options);
|
|
51
62
|
return this.handler.request(`/leagues/${leagueId}/seasons?${query}`, options);
|
|
52
63
|
}
|
|
64
|
+
/** Get Legend League season rankings by season Id. */
|
|
53
65
|
getSeasonRankings(leagueId, seasonId, options) {
|
|
54
66
|
const query = Util_1.Util.queryString(options);
|
|
55
67
|
return this.handler.request(`/leagues/${leagueId}/seasons/${seasonId}?${query}`, options);
|
|
56
68
|
}
|
|
69
|
+
/** Get list of Clan War Leagues. */
|
|
57
70
|
getWarLeagues(options) {
|
|
58
71
|
const query = Util_1.Util.queryString(options);
|
|
59
72
|
return this.handler.request(`/warleagues?${query}`, options);
|
|
60
73
|
}
|
|
74
|
+
/** Get info about a Clan War League. */
|
|
61
75
|
getWarLeague(leagueId, options) {
|
|
62
76
|
return this.handler.request(`/warleagues/${leagueId}`, options);
|
|
63
77
|
}
|
|
78
|
+
/** Get list of Locations. */
|
|
64
79
|
getLocations(options) {
|
|
65
80
|
const query = Util_1.Util.queryString(options);
|
|
66
81
|
return this.handler.request(`/locations?${query}`, options);
|
|
67
82
|
}
|
|
83
|
+
/** Get info about a Location. */
|
|
68
84
|
getLocation(locationId, options) {
|
|
69
85
|
return this.handler.request(`/locations/${locationId}`, options);
|
|
70
86
|
}
|
|
87
|
+
/** Get clan rankings for a specific location. */
|
|
71
88
|
getClanRanks(locationId, options) {
|
|
72
89
|
const query = Util_1.Util.queryString(options);
|
|
73
90
|
return this.handler.request(`/locations/${locationId}/rankings/clans?${query}`, options);
|
|
74
91
|
}
|
|
92
|
+
/** Get player rankings for a specific location. */
|
|
75
93
|
getPlayerRanks(locationId, options) {
|
|
76
94
|
const query = Util_1.Util.queryString(options);
|
|
77
95
|
return this.handler.request(`/locations/${locationId}/rankings/players?${query}`, options);
|
|
78
96
|
}
|
|
97
|
+
/** Get clan versus rankings for a specific location. */
|
|
79
98
|
getVersusClanRanks(locationId, options) {
|
|
80
99
|
const query = Util_1.Util.queryString(options);
|
|
81
100
|
return this.handler.request(`/locations/${locationId}/rankings/clans-versus?${query}`, options);
|
|
82
101
|
}
|
|
102
|
+
/** Get player versus rankings for a specific location. */
|
|
83
103
|
getVersusPlayerRanks(locationId, options) {
|
|
84
104
|
const query = Util_1.Util.queryString(options);
|
|
85
105
|
return this.handler.request(`/locations/${locationId}/rankings/players-versus?${query}`, options);
|
|
86
106
|
}
|
|
107
|
+
/** Get list of clan labels. */
|
|
87
108
|
getClanLabels(options) {
|
|
88
109
|
const query = Util_1.Util.queryString(options);
|
|
89
110
|
return this.handler.request(`/labels/clans?${query}`, options);
|
|
90
111
|
}
|
|
112
|
+
/** Get list of player labels. */
|
|
91
113
|
getPlayerLabels(options) {
|
|
92
114
|
const query = Util_1.Util.queryString(options);
|
|
93
115
|
return this.handler.request(`/labels/players?${query}`, options);
|
|
94
116
|
}
|
|
117
|
+
/** Get info about gold pass season. */
|
|
95
118
|
getGoldPassSeason(options) {
|
|
96
119
|
return this.handler.request('/goldpass/seasons/current', options);
|
|
97
120
|
}
|
|
@@ -11,19 +11,14 @@ export declare class RequestHandler {
|
|
|
11
11
|
private keys;
|
|
12
12
|
private readonly baseURL;
|
|
13
13
|
private readonly retryLimit;
|
|
14
|
-
private readonly cached;
|
|
15
14
|
private readonly restRequestTimeout;
|
|
16
15
|
private readonly throttler?;
|
|
16
|
+
private readonly cached;
|
|
17
17
|
constructor(options?: ClientOptions);
|
|
18
18
|
private get _keys();
|
|
19
19
|
private get _key();
|
|
20
20
|
setKeys(keys: string[]): this;
|
|
21
|
-
request<T>(path: string, options?: RequestOptions): Promise<
|
|
22
|
-
data: T;
|
|
23
|
-
maxAge: number;
|
|
24
|
-
status: number;
|
|
25
|
-
path: string;
|
|
26
|
-
}>;
|
|
21
|
+
request<T>(path: string, options?: RequestOptions): Promise<Response<T>>;
|
|
27
22
|
private exec;
|
|
28
23
|
init(options: InitOptions): Promise<string[]>;
|
|
29
24
|
private reValidateKeys;
|
|
@@ -97,9 +92,21 @@ export interface OverrideOptions {
|
|
|
97
92
|
restRequestTimeout?: number;
|
|
98
93
|
}
|
|
99
94
|
export interface RequestOptions extends OverrideOptions {
|
|
95
|
+
/** The request body. */
|
|
100
96
|
body?: string;
|
|
97
|
+
/** The request method. */
|
|
101
98
|
method?: string;
|
|
102
99
|
}
|
|
100
|
+
export interface Response<T> {
|
|
101
|
+
/** The response body. */
|
|
102
|
+
data: T;
|
|
103
|
+
/** Path of the request for this response. */
|
|
104
|
+
path: string;
|
|
105
|
+
/** HTTP status code of this response. */
|
|
106
|
+
status: number;
|
|
107
|
+
/** The maxAge of this response. */
|
|
108
|
+
maxAge: number;
|
|
109
|
+
}
|
|
103
110
|
/**
|
|
104
111
|
* Clan search options for a request.
|
|
105
112
|
*
|
|
@@ -21,6 +21,7 @@ const HTTPError_1 = require("./HTTPError");
|
|
|
21
21
|
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
22
22
|
const https_1 = __importDefault(require("https"));
|
|
23
23
|
const keyv_1 = __importDefault(require("keyv"));
|
|
24
|
+
const IP_REGEX = /\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}/g;
|
|
24
25
|
const agent = new https_1.default.Agent({ keepAlive: true });
|
|
25
26
|
/** Represents a Request Handler. */
|
|
26
27
|
class RequestHandler {
|
|
@@ -50,8 +51,9 @@ class RequestHandler {
|
|
|
50
51
|
}
|
|
51
52
|
async request(path, options = {}) {
|
|
52
53
|
const cached = (await this.cached?.get(path)) ?? null;
|
|
53
|
-
if (cached && options.force !== true)
|
|
54
|
-
return { data: cached, maxAge:
|
|
54
|
+
if (cached && options.force !== true) {
|
|
55
|
+
return { data: cached.data, maxAge: cached.ttl - Date.now(), status: 200, path };
|
|
56
|
+
}
|
|
55
57
|
if (!this.throttler || options.ignoreRateLimit)
|
|
56
58
|
return this.exec(path, options);
|
|
57
59
|
await this.throttler.wait();
|
|
@@ -74,16 +76,18 @@ class RequestHandler {
|
|
|
74
76
|
if (!res && retries < (options.retryLimit ?? this.retryLimit))
|
|
75
77
|
return this.exec(path, options, ++retries);
|
|
76
78
|
if (res?.status === 403 && data?.reason === 'accessDenied.invalidIp' && this.email && this.password) {
|
|
77
|
-
await this.login();
|
|
78
|
-
|
|
79
|
+
const keys = await this.reValidateKeys().then(() => this.login());
|
|
80
|
+
if (keys.length)
|
|
81
|
+
return this.exec(path, options, ++retries);
|
|
79
82
|
}
|
|
80
83
|
const maxAge = Number(res?.headers.get('cache-control')?.split('=')?.[1] ?? 0) * 1000;
|
|
81
84
|
if (res?.status === 403 && !data?.message)
|
|
82
85
|
throw new HTTPError_1.HTTPError(HTTPError_1.PrivateWarLogError, res.status, path, maxAge);
|
|
83
86
|
if (!res?.ok)
|
|
84
87
|
throw new HTTPError_1.HTTPError(data, res?.status ?? 504, path, maxAge, options.method);
|
|
85
|
-
if (this.cached && maxAge > 0 && options.cache !== false)
|
|
86
|
-
await this.cached.set(path, data, maxAge);
|
|
88
|
+
if (this.cached && maxAge > 0 && options.cache !== false) {
|
|
89
|
+
await this.cached.set(path, { data, ttl: Date.now() + maxAge }, maxAge);
|
|
90
|
+
}
|
|
87
91
|
return { data, maxAge, status: res.status, path };
|
|
88
92
|
}
|
|
89
93
|
async init(options) {
|
|
@@ -107,33 +111,38 @@ class RequestHandler {
|
|
|
107
111
|
if (res?.status === 403) {
|
|
108
112
|
const index = this.keys.indexOf(key);
|
|
109
113
|
this.keys.splice(index, 1);
|
|
110
|
-
|
|
114
|
+
process.emitWarning(`Pre-defined key #${index + 1} is no longer valid. Removed from the key list.`);
|
|
111
115
|
}
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
118
|
async login() {
|
|
115
119
|
const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/login`, {
|
|
116
120
|
method: 'POST',
|
|
121
|
+
timeout: 10000,
|
|
117
122
|
headers: { 'Content-Type': 'application/json' },
|
|
118
123
|
body: JSON.stringify({ email: this.email, password: this.password })
|
|
119
124
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
125
|
+
const data = await res.json();
|
|
126
|
+
if (!res.ok)
|
|
127
|
+
throw new Error(`Invalid email or password. ${JSON.stringify(data)}`);
|
|
128
|
+
const ip = await this.getIp(data.temporaryAPIToken);
|
|
129
|
+
if (!ip)
|
|
130
|
+
throw new Error('Failed to get the IP address.');
|
|
131
|
+
return this.getKeys(res.headers.get('set-cookie'), ip);
|
|
124
132
|
}
|
|
125
|
-
async getKeys(cookie) {
|
|
126
|
-
const ip = await this.getIp();
|
|
133
|
+
async getKeys(cookie, ip) {
|
|
127
134
|
const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/apikey/list`, {
|
|
128
135
|
method: 'POST',
|
|
136
|
+
timeout: 10000,
|
|
129
137
|
headers: { 'Content-Type': 'application/json', cookie }
|
|
130
138
|
});
|
|
131
139
|
const data = await res.json();
|
|
140
|
+
if (!res.ok)
|
|
141
|
+
throw new Error(`Failed to retrieve the API Keys. ${JSON.stringify(data)}`);
|
|
132
142
|
// Get all available keys from the developer site.
|
|
133
143
|
const keys = (data.keys ?? []);
|
|
134
144
|
// Revoke keys for specified key name but not matching current IP address.
|
|
135
|
-
const
|
|
136
|
-
for (const key of expiredKeys) {
|
|
145
|
+
for (const key of keys.filter((key) => key.name === this.keyName && !key.cidrRanges.includes(ip))) {
|
|
137
146
|
if (!(await this.revokeKey(key.id, cookie)))
|
|
138
147
|
continue;
|
|
139
148
|
const index = keys.findIndex(({ id }) => id === key.id);
|
|
@@ -153,7 +162,7 @@ class RequestHandler {
|
|
|
153
162
|
keys.push(key);
|
|
154
163
|
}
|
|
155
164
|
if (this.keys.length < this.keyCount && keys.length === 10) {
|
|
156
|
-
|
|
165
|
+
process.emitWarning(`${this.keyCount} key(s) were requested but failed to create ${this.keyCount - this.keys.length} more key(s).`);
|
|
157
166
|
}
|
|
158
167
|
if (!this.keys.length) {
|
|
159
168
|
throw new Error([
|
|
@@ -166,6 +175,7 @@ class RequestHandler {
|
|
|
166
175
|
async revokeKey(keyId, cookie) {
|
|
167
176
|
const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/apikey/revoke`, {
|
|
168
177
|
method: 'POST',
|
|
178
|
+
timeout: 10000,
|
|
169
179
|
body: JSON.stringify({ id: keyId }),
|
|
170
180
|
headers: { 'Content-Type': 'application/json', cookie }
|
|
171
181
|
});
|
|
@@ -174,6 +184,7 @@ class RequestHandler {
|
|
|
174
184
|
async createKey(cookie, ip) {
|
|
175
185
|
const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/apikey/create`, {
|
|
176
186
|
method: 'POST',
|
|
187
|
+
timeout: 10000,
|
|
177
188
|
headers: { 'Content-Type': 'application/json', cookie },
|
|
178
189
|
body: JSON.stringify({
|
|
179
190
|
cidrRanges: [ip],
|
|
@@ -182,10 +193,20 @@ class RequestHandler {
|
|
|
182
193
|
})
|
|
183
194
|
});
|
|
184
195
|
const data = await res.json();
|
|
196
|
+
if (!res.ok)
|
|
197
|
+
throw new Error(`Failed to create API Key. ${JSON.stringify(data)}`);
|
|
185
198
|
return data.key;
|
|
186
199
|
}
|
|
187
|
-
async getIp() {
|
|
188
|
-
|
|
200
|
+
async getIp(token) {
|
|
201
|
+
try {
|
|
202
|
+
const decoded = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
|
|
203
|
+
const props = decoded.limits.find((limit) => limit.hasOwnProperty('cidrs'));
|
|
204
|
+
return props.cidrs[0].match(IP_REGEX)[0];
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
const body = await (0, node_fetch_1.default)('https://api.ipify.org', { timeout: 10000 }).then((res) => res.text());
|
|
208
|
+
return body.match(IP_REGEX)?.[0] ?? null;
|
|
209
|
+
}
|
|
189
210
|
}
|
|
190
211
|
}
|
|
191
212
|
exports.RequestHandler = RequestHandler;
|
package/dist/rest/Throttler.d.ts
CHANGED
package/dist/struct/Clan.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OverrideOptions } from '../rest/RequestHandler';
|
|
1
2
|
import { ChatLanguage } from './ChatLanguage';
|
|
2
3
|
import { ClanMember } from './ClanMember';
|
|
3
4
|
import { Client } from '../client/Client';
|
|
@@ -58,6 +59,6 @@ export declare class Clan {
|
|
|
58
59
|
*/
|
|
59
60
|
members: ClanMember[];
|
|
60
61
|
constructor(client: Client, data: APIClan);
|
|
61
|
-
/** Get {@link Player}
|
|
62
|
-
fetchMembers(): Promise<Player[]>;
|
|
62
|
+
/** Get {@link Player} info for every Player in the clan. */
|
|
63
|
+
fetchMembers(options?: OverrideOptions): Promise<Player[]>;
|
|
63
64
|
}
|
package/dist/struct/Clan.js
CHANGED
|
@@ -34,9 +34,9 @@ class Clan {
|
|
|
34
34
|
this.labels = data.labels.map((label) => new Label_1.Label(label));
|
|
35
35
|
this.members = data.memberList?.map((mem) => new ClanMember_1.ClanMember(this.client, mem)) ?? []; // eslint-disable-line
|
|
36
36
|
}
|
|
37
|
-
/** Get {@link Player}
|
|
38
|
-
async fetchMembers() {
|
|
39
|
-
return (await Promise.allSettled(this.members.map((m) => this.client.getPlayer(m.tag, { ignoreRateLimit: true }))))
|
|
37
|
+
/** Get {@link Player} info for every Player in the clan. */
|
|
38
|
+
async fetchMembers(options) {
|
|
39
|
+
return (await Promise.allSettled(this.members.map((m) => this.client.getPlayer(m.tag, { ...options, ignoreRateLimit: true }))))
|
|
40
40
|
.filter((res) => res.status === 'fulfilled')
|
|
41
41
|
.map((res) => res.value);
|
|
42
42
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OverrideOptions } from '../rest/RequestHandler';
|
|
1
2
|
import { Client } from '../client/Client';
|
|
2
3
|
import { APIClanMember } from '../types';
|
|
3
4
|
import { League } from './League';
|
|
@@ -27,5 +28,5 @@ export declare class ClanMember {
|
|
|
27
28
|
received: number;
|
|
28
29
|
constructor(client: Client, data: APIClanMember);
|
|
29
30
|
/** Fetch detailed clan info for the member's clan. */
|
|
30
|
-
fetch(): Promise<import("./Player").Player>;
|
|
31
|
+
fetch(options?: OverrideOptions): Promise<import("./Player").Player>;
|
|
31
32
|
}
|
|
@@ -21,8 +21,8 @@ class ClanMember {
|
|
|
21
21
|
this.received = data.donationsReceived;
|
|
22
22
|
}
|
|
23
23
|
/** Fetch detailed clan info for the member's clan. */
|
|
24
|
-
async fetch() {
|
|
25
|
-
return this.client.getPlayer(this.tag);
|
|
24
|
+
async fetch(options) {
|
|
25
|
+
return this.client.getPlayer(this.tag, options);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
exports.ClanMember = ClanMember;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { APIClanWarLeagueClan, APIClanWarLeagueClanMember, APIClanWarLeagueGroup, APIClanWarLeagueRound } from '../types';
|
|
2
|
+
import { OverrideOptions } from '../rest/RequestHandler';
|
|
2
3
|
import { Client } from '../client/Client';
|
|
3
4
|
import { ClanWar } from './ClanWar';
|
|
4
5
|
import { Player } from './Player';
|
|
@@ -27,8 +28,8 @@ export declare class ClanWarLeagueClan {
|
|
|
27
28
|
/** An array of members that are in the CWL group. */
|
|
28
29
|
members: ClanWarLeagueClanMember[];
|
|
29
30
|
constructor(client: Client, data: APIClanWarLeagueClan);
|
|
30
|
-
/** Get {@link Player}
|
|
31
|
-
fetchMembers(): Promise<Player[]>;
|
|
31
|
+
/** Get {@link Player} info for every members that are in the CWL group. */
|
|
32
|
+
fetchMembers(options?: OverrideOptions): Promise<Player[]>;
|
|
32
33
|
}
|
|
33
34
|
/** Represents a Round of CWL Group. */
|
|
34
35
|
export declare class ClanWarLeagueRound {
|
|
@@ -53,9 +54,10 @@ export declare class ClanWarLeagueGroup {
|
|
|
53
54
|
/**
|
|
54
55
|
* This returns an array of {@link ClanWar} which fetches all wars in parallel.
|
|
55
56
|
* @param clanTag Optional clan tag. If present, this will only return wars which belong to this clan.
|
|
57
|
+
* @param options Override options for the request.
|
|
56
58
|
*/
|
|
57
|
-
getWars(clanTag?: string): Promise<ClanWar[]>;
|
|
59
|
+
getWars(clanTag?: string, options?: OverrideOptions): Promise<ClanWar[]>;
|
|
58
60
|
private _getCurrentWars;
|
|
59
|
-
/** Returns
|
|
61
|
+
/** Returns the index of the round for this specified warTag. */
|
|
60
62
|
getRoundIndex(warTag: string): number | null;
|
|
61
63
|
}
|
|
@@ -21,9 +21,9 @@ class ClanWarLeagueClan {
|
|
|
21
21
|
this.badge = new Badge_1.Badge(data.badgeUrls);
|
|
22
22
|
this.members = data.members.map((mem) => new ClanWarLeagueClanMember(mem));
|
|
23
23
|
}
|
|
24
|
-
/** Get {@link Player}
|
|
25
|
-
async fetchMembers() {
|
|
26
|
-
return (await Promise.allSettled(this.members.map((m) => this.client.getPlayer(m.tag, { ignoreRateLimit: true }))))
|
|
24
|
+
/** Get {@link Player} info for every members that are in the CWL group. */
|
|
25
|
+
async fetchMembers(options) {
|
|
26
|
+
return (await Promise.allSettled(this.members.map((m) => this.client.getPlayer(m.tag, { ...options, ignoreRateLimit: true }))))
|
|
27
27
|
.filter((res) => res.status === 'fulfilled')
|
|
28
28
|
.map((res) => res.value);
|
|
29
29
|
}
|
|
@@ -49,19 +49,20 @@ class ClanWarLeagueGroup {
|
|
|
49
49
|
/**
|
|
50
50
|
* This returns an array of {@link ClanWar} which fetches all wars in parallel.
|
|
51
51
|
* @param clanTag Optional clan tag. If present, this will only return wars which belong to this clan.
|
|
52
|
+
* @param options Override options for the request.
|
|
52
53
|
*/
|
|
53
|
-
async getWars(clanTag) {
|
|
54
|
+
async getWars(clanTag, options) {
|
|
54
55
|
const rounds = this.rounds.filter((round) => !round.warTags.includes('#0'));
|
|
55
56
|
if (!rounds.length)
|
|
56
57
|
return [];
|
|
57
58
|
const warTags = rounds.map((round) => round.warTags).flat();
|
|
58
|
-
const wars = await Promise.allSettled(warTags.map((warTag) => this.client.getClanWarLeagueRound({ warTag, clanTag }, { ignoreRateLimit: true })));
|
|
59
|
+
const wars = await Promise.allSettled(warTags.map((warTag) => this.client.getClanWarLeagueRound({ warTag, clanTag }, { ...options, ignoreRateLimit: true })));
|
|
59
60
|
return wars
|
|
60
61
|
.filter((res) => res.status === 'fulfilled')
|
|
61
62
|
.map((res) => res.value)
|
|
62
63
|
.filter((war) => (clanTag ? war.clan.tag === clanTag : true));
|
|
63
64
|
}
|
|
64
|
-
async _getCurrentWars(clanTag) {
|
|
65
|
+
async _getCurrentWars(clanTag, options) {
|
|
65
66
|
const rounds = this.rounds.filter((round) => !round.warTags.includes('#0'));
|
|
66
67
|
if (!rounds.length)
|
|
67
68
|
return [];
|
|
@@ -70,13 +71,13 @@ class ClanWarLeagueGroup {
|
|
|
70
71
|
.map((round) => round.warTags)
|
|
71
72
|
.flat()
|
|
72
73
|
.reverse();
|
|
73
|
-
const wars = await Promise.allSettled(warTags.map((warTag) => this.client.getClanWarLeagueRound({ warTag, clanTag }, { ignoreRateLimit: true })));
|
|
74
|
+
const wars = await Promise.allSettled(warTags.map((warTag) => this.client.getClanWarLeagueRound({ warTag, clanTag }, { ...options, ignoreRateLimit: true })));
|
|
74
75
|
return wars
|
|
75
76
|
.filter((res) => res.status === 'fulfilled')
|
|
76
77
|
.map((res) => res.value)
|
|
77
78
|
.filter((war) => war.clan.tag === clanTag);
|
|
78
79
|
}
|
|
79
|
-
/** Returns
|
|
80
|
+
/** Returns the index of the round for this specified warTag. */
|
|
80
81
|
getRoundIndex(warTag) {
|
|
81
82
|
return this.rounds.find((round) => round.warTags.includes(warTag))?.round ?? null;
|
|
82
83
|
}
|