clashofclans.js 2.0.0-dev.30ea324 → 2.0.0-dev.3a1efb5
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 +1 -1
- package/README.md +5 -5
- package/dist/client/Client.d.ts +52 -22
- package/dist/client/Client.js +61 -37
- package/dist/client/EventManager.d.ts +46 -20
- package/dist/client/EventManager.js +97 -51
- package/dist/rest/HTTPError.d.ts +17 -1
- package/dist/rest/HTTPError.js +26 -7
- package/dist/rest/RESTManager.d.ts +24 -0
- package/dist/rest/RequestHandler.d.ts +84 -3
- package/dist/rest/RequestHandler.js +43 -16
- package/dist/rest/Throttler.d.ts +0 -4
- package/dist/struct/Clan.d.ts +2 -1
- package/dist/struct/Clan.js +2 -2
- package/dist/struct/ClanMember.d.ts +2 -1
- package/dist/struct/ClanMember.js +2 -2
- package/dist/struct/ClanWar.d.ts +6 -4
- package/dist/struct/ClanWar.js +17 -3
- package/dist/struct/ClanWarLeagueGroup.d.ts +3 -2
- package/dist/struct/ClanWarLeagueGroup.js +10 -9
- package/dist/struct/ClanWarLog.d.ts +2 -2
- package/dist/struct/ClanWarLog.js +2 -2
- package/dist/struct/Player.d.ts +2 -1
- package/dist/struct/Player.js +2 -2
- package/dist/struct/PlayerClan.d.ts +2 -1
- package/dist/struct/PlayerClan.js +2 -2
- package/dist/types/index.d.ts +3 -5
- package/dist/util/Constants.d.ts +5 -0
- package/dist/util/Constants.js +6 -1
- package/dist/util/Util.js +3 -1
- package/package.json +5 -5
package/dist/rest/HTTPError.d.ts
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
/** Represents an HTTP Error. */
|
|
2
2
|
export declare class HTTPError extends Error {
|
|
3
|
+
/** The message of this error. */
|
|
4
|
+
message: string;
|
|
5
|
+
/** The HTTP method of this request. */
|
|
3
6
|
method: string;
|
|
7
|
+
/** The reason of this error. */
|
|
4
8
|
reason: string;
|
|
9
|
+
/** The HTTP status code of this request. */
|
|
5
10
|
status: number;
|
|
11
|
+
/** The path of this request. */
|
|
6
12
|
path: string;
|
|
7
|
-
|
|
13
|
+
/** Maximum number of milliseconds the results can be cached. */
|
|
14
|
+
maxAge: number;
|
|
15
|
+
constructor(error: any, status: number, path: string, maxAge: number, method?: string);
|
|
8
16
|
}
|
|
17
|
+
export declare const NotInWarError: {
|
|
18
|
+
message: string;
|
|
19
|
+
reason: string;
|
|
20
|
+
};
|
|
21
|
+
export declare const PrivateWarLogError: {
|
|
22
|
+
message: string;
|
|
23
|
+
reason: string;
|
|
24
|
+
};
|
package/dist/rest/HTTPError.js
CHANGED
|
@@ -1,23 +1,42 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HTTPError = void 0;
|
|
3
|
+
exports.PrivateWarLogError = exports.NotInWarError = exports.HTTPError = void 0;
|
|
4
4
|
const messages = {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
500: 'Unknown error happened when handling the request.',
|
|
6
|
+
504: 'The user aborted this request.',
|
|
7
|
+
404: 'Requested resource was not found.',
|
|
8
|
+
400: 'Client provided incorrect parameters for the request.',
|
|
9
|
+
503: 'Service is temporarily unavailable because of maintenance.',
|
|
10
|
+
429: 'Request was throttled, because amount of requests was above the threshold defined for the used API token.',
|
|
11
|
+
403: 'Access denied, either because of missing/incorrect credentials or used API token does not grant access to the requested resource.'
|
|
7
12
|
};
|
|
8
13
|
const reasons = {
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
503: 'serviceUnavailable',
|
|
15
|
+
429: 'tooManyRequests',
|
|
16
|
+
400: 'badRequest',
|
|
17
|
+
403: 'forbidden',
|
|
18
|
+
500: 'unknownError',
|
|
19
|
+
404: 'notFound',
|
|
20
|
+
504: 'requestAborted'
|
|
11
21
|
};
|
|
12
22
|
/** Represents an HTTP Error. */
|
|
13
23
|
class HTTPError extends Error {
|
|
14
|
-
constructor(error, status, path, method
|
|
24
|
+
constructor(error, status, path, maxAge, method) {
|
|
15
25
|
super();
|
|
16
26
|
this.message = error?.message ?? messages[status];
|
|
17
27
|
this.reason = error?.reason ?? reasons[status];
|
|
18
28
|
this.path = path;
|
|
19
|
-
this.method = method;
|
|
29
|
+
this.method = method ?? 'GET';
|
|
20
30
|
this.status = status;
|
|
31
|
+
this.maxAge = maxAge;
|
|
21
32
|
}
|
|
22
33
|
}
|
|
23
34
|
exports.HTTPError = HTTPError;
|
|
35
|
+
exports.NotInWarError = {
|
|
36
|
+
message: 'Clan is not in war at this moment.',
|
|
37
|
+
reason: 'notInWar'
|
|
38
|
+
};
|
|
39
|
+
exports.PrivateWarLogError = {
|
|
40
|
+
message: 'Access denied, clan war log is private.',
|
|
41
|
+
reason: 'privateWarLog'
|
|
42
|
+
};
|
|
@@ -8,120 +8,144 @@ export declare class RESTManager {
|
|
|
8
8
|
data: APIClanList;
|
|
9
9
|
maxAge: number;
|
|
10
10
|
status: number;
|
|
11
|
+
path: string;
|
|
11
12
|
}>;
|
|
12
13
|
getClan(clanTag: string, options?: OverrideOptions): Promise<{
|
|
13
14
|
data: APIClan;
|
|
14
15
|
maxAge: number;
|
|
15
16
|
status: number;
|
|
17
|
+
path: string;
|
|
16
18
|
}>;
|
|
17
19
|
getClanMembers(clanTag: string, options?: SearchOptions): Promise<{
|
|
18
20
|
data: APIClanMemberList;
|
|
19
21
|
maxAge: number;
|
|
20
22
|
status: number;
|
|
23
|
+
path: string;
|
|
21
24
|
}>;
|
|
22
25
|
getClanWarLog(clanTag: string, options?: SearchOptions): Promise<{
|
|
23
26
|
data: APIClanWarLog;
|
|
24
27
|
maxAge: number;
|
|
25
28
|
status: number;
|
|
29
|
+
path: string;
|
|
26
30
|
}>;
|
|
27
31
|
getCurrentWar(clanTag: string, options?: OverrideOptions): Promise<{
|
|
28
32
|
data: APIClanWar;
|
|
29
33
|
maxAge: number;
|
|
30
34
|
status: number;
|
|
35
|
+
path: string;
|
|
31
36
|
}>;
|
|
32
37
|
getClanWarLeagueGroup(clanTag: string, options?: OverrideOptions): Promise<{
|
|
33
38
|
data: APIClanWarLeagueGroup;
|
|
34
39
|
maxAge: number;
|
|
35
40
|
status: number;
|
|
41
|
+
path: string;
|
|
36
42
|
}>;
|
|
37
43
|
getClanWarLeagueRound(warTag: string, options?: OverrideOptions): Promise<{
|
|
38
44
|
data: APIClanWar;
|
|
39
45
|
maxAge: number;
|
|
40
46
|
status: number;
|
|
47
|
+
path: string;
|
|
41
48
|
}>;
|
|
42
49
|
getPlayer(playerTag: string, options?: OverrideOptions): Promise<{
|
|
43
50
|
data: APIPlayer;
|
|
44
51
|
maxAge: number;
|
|
45
52
|
status: number;
|
|
53
|
+
path: string;
|
|
46
54
|
}>;
|
|
47
55
|
postPlayerToken(playerTag: string, token: string, options?: OverrideOptions): Promise<{
|
|
48
56
|
data: APIVerifyToken;
|
|
49
57
|
maxAge: number;
|
|
50
58
|
status: number;
|
|
59
|
+
path: string;
|
|
51
60
|
}>;
|
|
52
61
|
getLeagues(options?: SearchOptions): Promise<{
|
|
53
62
|
data: APILeagueList;
|
|
54
63
|
maxAge: number;
|
|
55
64
|
status: number;
|
|
65
|
+
path: string;
|
|
56
66
|
}>;
|
|
57
67
|
getLeague(leagueId: string | number, options?: OverrideOptions): Promise<{
|
|
58
68
|
data: APILeague;
|
|
59
69
|
maxAge: number;
|
|
60
70
|
status: number;
|
|
71
|
+
path: string;
|
|
61
72
|
}>;
|
|
62
73
|
getLeagueSeasons(leagueId: number, options?: SearchOptions): Promise<{
|
|
63
74
|
data: APILeagueSeasonList;
|
|
64
75
|
maxAge: number;
|
|
65
76
|
status: number;
|
|
77
|
+
path: string;
|
|
66
78
|
}>;
|
|
67
79
|
getSeasonRankings(leagueId: number, seasonId: string, options?: SearchOptions): Promise<{
|
|
68
80
|
data: APIPlayerSeasonRankingList;
|
|
69
81
|
maxAge: number;
|
|
70
82
|
status: number;
|
|
83
|
+
path: string;
|
|
71
84
|
}>;
|
|
72
85
|
getWarLeagues(options?: SearchOptions): Promise<{
|
|
73
86
|
data: APIWarLeagueList;
|
|
74
87
|
maxAge: number;
|
|
75
88
|
status: number;
|
|
89
|
+
path: string;
|
|
76
90
|
}>;
|
|
77
91
|
getWarLeague(leagueId: number, options?: OverrideOptions): Promise<{
|
|
78
92
|
data: APIWarLeague;
|
|
79
93
|
maxAge: number;
|
|
80
94
|
status: number;
|
|
95
|
+
path: string;
|
|
81
96
|
}>;
|
|
82
97
|
getLocations(options?: SearchOptions): Promise<{
|
|
83
98
|
data: APILocationList;
|
|
84
99
|
maxAge: number;
|
|
85
100
|
status: number;
|
|
101
|
+
path: string;
|
|
86
102
|
}>;
|
|
87
103
|
getLocation(locationId: number, options?: OverrideOptions): Promise<{
|
|
88
104
|
data: APILocation;
|
|
89
105
|
maxAge: number;
|
|
90
106
|
status: number;
|
|
107
|
+
path: string;
|
|
91
108
|
}>;
|
|
92
109
|
getClanRanks(locationId: number | string, options?: SearchOptions): Promise<{
|
|
93
110
|
data: APIClanRankingList;
|
|
94
111
|
maxAge: number;
|
|
95
112
|
status: number;
|
|
113
|
+
path: string;
|
|
96
114
|
}>;
|
|
97
115
|
getPlayerRanks(locationId: number | string, options?: SearchOptions): Promise<{
|
|
98
116
|
data: APIPlayerRankingList;
|
|
99
117
|
maxAge: number;
|
|
100
118
|
status: number;
|
|
119
|
+
path: string;
|
|
101
120
|
}>;
|
|
102
121
|
getVersusClanRanks(locationId: number | string, options?: SearchOptions): Promise<{
|
|
103
122
|
data: APIClanVersusRankingList;
|
|
104
123
|
maxAge: number;
|
|
105
124
|
status: number;
|
|
125
|
+
path: string;
|
|
106
126
|
}>;
|
|
107
127
|
getVersusPlayerRanks(locationId: number | string, options?: SearchOptions): Promise<{
|
|
108
128
|
data: APIPlayerVersusRankingList;
|
|
109
129
|
maxAge: number;
|
|
110
130
|
status: number;
|
|
131
|
+
path: string;
|
|
111
132
|
}>;
|
|
112
133
|
getClanLabels(options?: SearchOptions): Promise<{
|
|
113
134
|
data: APILabelList;
|
|
114
135
|
maxAge: number;
|
|
115
136
|
status: number;
|
|
137
|
+
path: string;
|
|
116
138
|
}>;
|
|
117
139
|
getPlayerLabels(options?: SearchOptions): Promise<{
|
|
118
140
|
data: APILabelList;
|
|
119
141
|
maxAge: number;
|
|
120
142
|
status: number;
|
|
143
|
+
path: string;
|
|
121
144
|
}>;
|
|
122
145
|
getGoldPassSeason(options?: OverrideOptions): Promise<{
|
|
123
146
|
data: APIGoldPassSeason;
|
|
124
147
|
maxAge: number;
|
|
125
148
|
status: number;
|
|
149
|
+
path: string;
|
|
126
150
|
}>;
|
|
127
151
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { QueueThrottler, BatchThrottler } from './Throttler';
|
|
2
|
+
import Keyv from 'keyv';
|
|
2
3
|
/** Represents a Request Handler. */
|
|
3
4
|
export declare class RequestHandler {
|
|
4
5
|
#private;
|
|
@@ -6,13 +7,13 @@ export declare class RequestHandler {
|
|
|
6
7
|
private password;
|
|
7
8
|
private keyCount;
|
|
8
9
|
private keyName;
|
|
9
|
-
private keyDescription
|
|
10
|
+
private keyDescription?;
|
|
10
11
|
private keys;
|
|
11
12
|
private readonly baseURL;
|
|
12
13
|
private readonly retryLimit;
|
|
13
|
-
private readonly cached;
|
|
14
14
|
private readonly restRequestTimeout;
|
|
15
15
|
private readonly throttler?;
|
|
16
|
+
private readonly cached;
|
|
16
17
|
constructor(options?: ClientOptions);
|
|
17
18
|
private get _keys();
|
|
18
19
|
private get _key();
|
|
@@ -21,54 +22,134 @@ export declare class RequestHandler {
|
|
|
21
22
|
data: T;
|
|
22
23
|
maxAge: number;
|
|
23
24
|
status: number;
|
|
25
|
+
path: string;
|
|
24
26
|
}>;
|
|
25
27
|
private exec;
|
|
26
28
|
init(options: InitOptions): Promise<string[]>;
|
|
29
|
+
private reValidateKeys;
|
|
27
30
|
private login;
|
|
28
31
|
private getKeys;
|
|
29
32
|
private revokeKey;
|
|
30
33
|
private createKey;
|
|
31
34
|
private getIp;
|
|
32
35
|
}
|
|
36
|
+
/** Options for a client. */
|
|
33
37
|
export interface ClientOptions {
|
|
38
|
+
/** Keys from Clash of Clans API developer site. */
|
|
34
39
|
keys?: string[];
|
|
35
|
-
|
|
40
|
+
/** Base URL of the Clash of Clans API. */
|
|
36
41
|
baseURL?: string;
|
|
42
|
+
/**
|
|
43
|
+
* How many times to retry on 5XX errors.
|
|
44
|
+
*/
|
|
37
45
|
retryLimit?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Whether enable or disable internal caching.
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* const client = new Client({ cache: true });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
cache?: boolean | Keyv;
|
|
54
|
+
/** Time to wait before cancelling a REST request, in milliseconds. */
|
|
38
55
|
restRequestTimeout?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Throttler class which handles rate-limit
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* const client = new Client({ throttler: new QueueThrottler(1000 / 10) });
|
|
61
|
+
* ```
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* const client = new Client({ throttler: new BatchThrottler(30) });
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
39
67
|
throttler?: QueueThrottler | BatchThrottler;
|
|
40
68
|
}
|
|
69
|
+
/** Search options for request. */
|
|
41
70
|
export interface SearchOptions extends OverrideOptions {
|
|
71
|
+
/** Limit the number of items returned in the response. */
|
|
42
72
|
limit?: number;
|
|
73
|
+
/**
|
|
74
|
+
* Return only items that occur after this marker.
|
|
75
|
+
* Before marker can be found from the response, inside the 'paging' property.
|
|
76
|
+
* Note that only after or before can be specified for a request, not both.
|
|
77
|
+
*/
|
|
43
78
|
after?: string;
|
|
79
|
+
/**
|
|
80
|
+
* Return only items that occur before this marker.
|
|
81
|
+
* Before marker can be found from the response, inside the 'paging' property.
|
|
82
|
+
* Note that only after or before can be specified for a request, not both.
|
|
83
|
+
*/
|
|
44
84
|
before?: string;
|
|
45
85
|
}
|
|
86
|
+
/** Override options for a request. */
|
|
46
87
|
export interface OverrideOptions {
|
|
88
|
+
/** Whether to cache this response. */
|
|
89
|
+
cache?: boolean;
|
|
90
|
+
/** Whether to skip the cache check and request the API. */
|
|
91
|
+
force?: boolean;
|
|
92
|
+
/** How many times to retry on 5XX errors. */
|
|
47
93
|
retryLimit?: string;
|
|
94
|
+
/** Whether to ignore throttlers. */
|
|
48
95
|
ignoreRateLimit?: boolean;
|
|
96
|
+
/** Time to wait before cancelling a REST request, in milliseconds. */
|
|
49
97
|
restRequestTimeout?: number;
|
|
50
98
|
}
|
|
51
99
|
export interface RequestOptions extends OverrideOptions {
|
|
52
100
|
body?: string;
|
|
53
101
|
method?: string;
|
|
54
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Clan search options for a request.
|
|
105
|
+
*
|
|
106
|
+
* ::info
|
|
107
|
+
* If name is used as part of search query, it needs to be at least three characters long.
|
|
108
|
+
* Name search parameter is interpreted as wild card search, so it may appear anywhere in the clan name.
|
|
109
|
+
* :::
|
|
110
|
+
*/
|
|
55
111
|
export interface ClanSearchOptions {
|
|
112
|
+
/** Search clans by name. */
|
|
56
113
|
name?: string;
|
|
114
|
+
/** Filter by minimum number of clan members. */
|
|
57
115
|
minMembers?: number;
|
|
116
|
+
/** Filter by maximum number of clan members. */
|
|
58
117
|
maxMembers?: number;
|
|
118
|
+
/** Filter by minimum amount of clan points. */
|
|
59
119
|
minClanPoints?: number;
|
|
120
|
+
/** Filter by minimum clan level. */
|
|
60
121
|
minClanLevel?: number;
|
|
122
|
+
/** Filter by clan war frequency. */
|
|
61
123
|
warFrequency?: string;
|
|
124
|
+
/** Filter by clan location identifier. For list of available locations, refer to getLocations operation. */
|
|
62
125
|
locationId?: string;
|
|
126
|
+
/** Comma separated list of label IDs to use for filtering results. */
|
|
63
127
|
labelIds?: string;
|
|
128
|
+
/** Limit the number of items returned in the response. */
|
|
64
129
|
limit?: number;
|
|
130
|
+
/**
|
|
131
|
+
* Return only items that occur after this marker.
|
|
132
|
+
* Before marker can be found from the response, inside the 'paging' property.
|
|
133
|
+
* Note that only after or before can be specified for a request, not both.
|
|
134
|
+
*/
|
|
65
135
|
after?: string;
|
|
136
|
+
/**
|
|
137
|
+
* Return only items that occur before this marker.
|
|
138
|
+
* Before marker can be found from the response, inside the 'paging' property.
|
|
139
|
+
* Note that only after or before can be specified for a request, not both.
|
|
140
|
+
*/
|
|
66
141
|
before?: string;
|
|
67
142
|
}
|
|
143
|
+
/** Login options for a client. */
|
|
68
144
|
export interface InitOptions {
|
|
145
|
+
/** Developer site email address. */
|
|
69
146
|
email: string;
|
|
147
|
+
/** Developer site password. */
|
|
70
148
|
password: string;
|
|
149
|
+
/** Name of API key(s). */
|
|
71
150
|
keyName?: string;
|
|
151
|
+
/** Number of allowed API keys. */
|
|
72
152
|
keyCount?: number;
|
|
153
|
+
/** Description of API key(s). */
|
|
73
154
|
keyDescription?: string;
|
|
74
155
|
}
|
|
@@ -30,8 +30,11 @@ class RequestHandler {
|
|
|
30
30
|
this.retryLimit = options?.retryLimit ?? 0;
|
|
31
31
|
this.throttler = options?.throttler ?? null;
|
|
32
32
|
this.baseURL = options?.baseURL ?? Constants_1.API_BASE_URL;
|
|
33
|
-
this.cached = options?.cache ? new keyv_1.default() : null;
|
|
34
33
|
this.restRequestTimeout = options?.restRequestTimeout ?? 0;
|
|
34
|
+
if (options?.cache instanceof keyv_1.default)
|
|
35
|
+
this.cached = options.cache;
|
|
36
|
+
else
|
|
37
|
+
this.cached = options?.cache ? new keyv_1.default() : null;
|
|
35
38
|
}
|
|
36
39
|
get _keys() {
|
|
37
40
|
return Array.isArray(this.keys) ? this.keys : [this.keys];
|
|
@@ -47,8 +50,8 @@ class RequestHandler {
|
|
|
47
50
|
}
|
|
48
51
|
async request(path, options = {}) {
|
|
49
52
|
const cached = (await this.cached?.get(path)) ?? null;
|
|
50
|
-
if (cached)
|
|
51
|
-
return { data: cached, maxAge:
|
|
53
|
+
if (cached && options.force !== true)
|
|
54
|
+
return { data: cached.data, maxAge: cached.ttl - Date.now(), status: 200, path };
|
|
52
55
|
if (!this.throttler || options.ignoreRateLimit)
|
|
53
56
|
return this.exec(path, options);
|
|
54
57
|
await this.throttler.wait();
|
|
@@ -74,23 +77,41 @@ class RequestHandler {
|
|
|
74
77
|
await this.login();
|
|
75
78
|
return this.exec(path, options, ++retries);
|
|
76
79
|
}
|
|
80
|
+
const maxAge = Number(res?.headers.get('cache-control')?.split('=')?.[1] ?? 0) * 1000;
|
|
81
|
+
if (res?.status === 403 && !data?.message)
|
|
82
|
+
throw new HTTPError_1.HTTPError(HTTPError_1.PrivateWarLogError, res.status, path, maxAge);
|
|
77
83
|
if (!res?.ok)
|
|
78
|
-
throw new HTTPError_1.HTTPError(data, res?.status ?? 504, path, options.method);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return { data, maxAge, status: res.status };
|
|
84
|
+
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, ttl: Date.now() + maxAge }, maxAge);
|
|
87
|
+
}
|
|
88
|
+
return { data, maxAge, status: res.status, path };
|
|
83
89
|
}
|
|
84
|
-
init(options) {
|
|
90
|
+
async init(options) {
|
|
85
91
|
if (!(options.email && options.password))
|
|
86
92
|
throw ReferenceError('Missing email and password.');
|
|
87
|
-
this.keyDescription = options.keyDescription
|
|
93
|
+
this.keyDescription = options.keyDescription;
|
|
88
94
|
this.keyName = options.keyName ?? 'clashofclans.js.keys';
|
|
89
95
|
this.keyCount = Math.min(options.keyCount ?? 1, 10);
|
|
90
96
|
this.password = options.password;
|
|
91
97
|
this.email = options.email;
|
|
98
|
+
await this.reValidateKeys();
|
|
92
99
|
return this.login();
|
|
93
100
|
}
|
|
101
|
+
async reValidateKeys() {
|
|
102
|
+
for (const key of this.keys) {
|
|
103
|
+
const res = await (0, node_fetch_1.default)(`${this.baseURL}/locations?limit=1`, {
|
|
104
|
+
method: 'GET',
|
|
105
|
+
timeout: 10000,
|
|
106
|
+
headers: { 'Authorization': `Bearer ${key}`, 'Content-Type': 'application/json' }
|
|
107
|
+
}).catch(() => null);
|
|
108
|
+
if (res?.status === 403) {
|
|
109
|
+
const index = this.keys.indexOf(key);
|
|
110
|
+
this.keys.splice(index, 1);
|
|
111
|
+
console.warn(`[WARN] Pre-defined key #${index + 1} is no longer valid. Removed from the key list.`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
94
115
|
async login() {
|
|
95
116
|
const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/login`, {
|
|
96
117
|
method: 'POST',
|
|
@@ -112,17 +133,19 @@ class RequestHandler {
|
|
|
112
133
|
// Get all available keys from the developer site.
|
|
113
134
|
const keys = (data.keys ?? []);
|
|
114
135
|
// Revoke keys for specified key name but not matching current IP address.
|
|
115
|
-
const
|
|
116
|
-
for (const key of expiredKeys) {
|
|
136
|
+
for (const key of keys.filter((key) => key.name === this.keyName && !key.cidrRanges.includes(ip))) {
|
|
117
137
|
if (!(await this.revokeKey(key.id, cookie)))
|
|
118
138
|
continue;
|
|
119
139
|
const index = keys.findIndex(({ id }) => id === key.id);
|
|
120
140
|
keys.splice(index, 1);
|
|
121
141
|
}
|
|
122
142
|
// Filter keys for current IP address and specified key name.
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
143
|
+
for (const key of keys.filter((key) => key.name === this.keyName && key.cidrRanges.includes(ip))) {
|
|
144
|
+
if (this.keys.length >= this.keyCount)
|
|
145
|
+
break;
|
|
146
|
+
if (!this.keys.includes(key.key))
|
|
147
|
+
this.keys.push(key.key);
|
|
148
|
+
}
|
|
126
149
|
// Create keys within limits (maximum of 10 keys per account)
|
|
127
150
|
while (this.keys.length < this.keyCount && keys.length < 10) {
|
|
128
151
|
const key = await this.createKey(cookie, ip);
|
|
@@ -152,7 +175,11 @@ class RequestHandler {
|
|
|
152
175
|
const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/apikey/create`, {
|
|
153
176
|
method: 'POST',
|
|
154
177
|
headers: { 'Content-Type': 'application/json', cookie },
|
|
155
|
-
body: JSON.stringify({
|
|
178
|
+
body: JSON.stringify({
|
|
179
|
+
cidrRanges: [ip],
|
|
180
|
+
name: this.keyName,
|
|
181
|
+
description: this.keyDescription ?? new Date().toUTCString()
|
|
182
|
+
})
|
|
156
183
|
});
|
|
157
184
|
const data = await res.json();
|
|
158
185
|
return data.key;
|
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';
|
|
@@ -59,5 +60,5 @@ export declare class Clan {
|
|
|
59
60
|
members: ClanMember[];
|
|
60
61
|
constructor(client: Client, data: APIClan);
|
|
61
62
|
/** Get {@link Player} information for every Player in the clan. */
|
|
62
|
-
fetchMembers(): Promise<Player[]>;
|
|
63
|
+
fetchMembers(options?: OverrideOptions): Promise<Player[]>;
|
|
63
64
|
}
|
package/dist/struct/Clan.js
CHANGED
|
@@ -35,8 +35,8 @@ class Clan {
|
|
|
35
35
|
this.members = data.memberList?.map((mem) => new ClanMember_1.ClanMember(this.client, mem)) ?? []; // eslint-disable-line
|
|
36
36
|
}
|
|
37
37
|
/** Get {@link Player} information for every Player in the clan. */
|
|
38
|
-
async fetchMembers() {
|
|
39
|
-
return (await Promise.allSettled(this.members.map((m) => this.client.getPlayer(m.tag, { ignoreRateLimit: true }))))
|
|
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;
|
package/dist/struct/ClanWar.d.ts
CHANGED
|
@@ -116,12 +116,12 @@ export declare class ClanWar {
|
|
|
116
116
|
opponent: WarClan;
|
|
117
117
|
/** The war's unique tag. This is `null` unless this is a CWL. */
|
|
118
118
|
warTag: string | null;
|
|
119
|
-
/**
|
|
119
|
+
/** Maximum number of milliseconds the results can be cached. */
|
|
120
120
|
maxAge: number;
|
|
121
121
|
constructor(client: Client, data: APIClanWar, extra: {
|
|
122
122
|
clanTag?: string;
|
|
123
123
|
warTag?: string;
|
|
124
|
-
maxAge
|
|
124
|
+
maxAge: number;
|
|
125
125
|
});
|
|
126
126
|
/** Return a {@link ClanWarMember} with the tag provided. */
|
|
127
127
|
getMember(tag: string): ClanWarMember | null;
|
|
@@ -129,7 +129,9 @@ export declare class ClanWar {
|
|
|
129
129
|
getAttack(attackerTag: string, defenderTag: string): ClanWarAttack | null;
|
|
130
130
|
/** Return a list of {@link ClanWarAttack} for the defenderTag provided. */
|
|
131
131
|
getDefenses(defenderTag: string): ClanWarAttack[];
|
|
132
|
-
/** Returns either `friendly`, `cwl` or `
|
|
133
|
-
get type():
|
|
132
|
+
/** Returns either `friendly`, `cwl` or `normal`. */
|
|
133
|
+
get type(): "friendly" | "cwl" | "normal";
|
|
134
134
|
private get _isFriendly();
|
|
135
|
+
/** Returns the war status, based off the home clan. */
|
|
136
|
+
get status(): "win" | "lose" | "tie" | "pending";
|
|
135
137
|
}
|
package/dist/struct/ClanWar.js
CHANGED
|
@@ -147,7 +147,7 @@ class ClanWar {
|
|
|
147
147
|
}
|
|
148
148
|
this.clan = new WarClan(this, clan);
|
|
149
149
|
this.opponent = new WarClan(this, opponent);
|
|
150
|
-
this.maxAge =
|
|
150
|
+
this.maxAge = extra.maxAge;
|
|
151
151
|
}
|
|
152
152
|
/** Return a {@link ClanWarMember} with the tag provided. */
|
|
153
153
|
getMember(tag) {
|
|
@@ -168,17 +168,31 @@ class ClanWar {
|
|
|
168
168
|
}
|
|
169
169
|
return this.opponent.attacks.filter((atk) => atk.defenderTag === defenderTag);
|
|
170
170
|
}
|
|
171
|
-
/** Returns either `friendly`, `cwl` or `
|
|
171
|
+
/** Returns either `friendly`, `cwl` or `normal`. */
|
|
172
172
|
get type() {
|
|
173
173
|
if (this._isFriendly)
|
|
174
174
|
return 'friendly';
|
|
175
175
|
if (this.warTag)
|
|
176
176
|
return 'cwl';
|
|
177
|
-
return '
|
|
177
|
+
return 'normal';
|
|
178
178
|
}
|
|
179
179
|
get _isFriendly() {
|
|
180
180
|
const preparationTime = this.startTime.getTime() - this.preparationStartTime.getTime();
|
|
181
181
|
return Constants_1.FRIENDLY_WAR_PREPARATION_TIMES.includes(preparationTime);
|
|
182
182
|
}
|
|
183
|
+
/** Returns the war status, based off the home clan. */
|
|
184
|
+
get status() {
|
|
185
|
+
if (this.state === 'preparation')
|
|
186
|
+
return 'pending';
|
|
187
|
+
if (this.clan.stars > this.opponent.stars)
|
|
188
|
+
return 'win';
|
|
189
|
+
if (this.clan.stars === this.opponent.stars) {
|
|
190
|
+
if (this.clan.destruction > this.opponent.destruction)
|
|
191
|
+
return 'win';
|
|
192
|
+
if (this.clan.destruction === this.opponent.destruction)
|
|
193
|
+
return 'tie';
|
|
194
|
+
}
|
|
195
|
+
return 'lose';
|
|
196
|
+
}
|
|
183
197
|
}
|
|
184
198
|
exports.ClanWar = ClanWar;
|
|
@@ -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';
|
|
@@ -28,7 +29,7 @@ export declare class ClanWarLeagueClan {
|
|
|
28
29
|
members: ClanWarLeagueClanMember[];
|
|
29
30
|
constructor(client: Client, data: APIClanWarLeagueClan);
|
|
30
31
|
/** Get {@link Player} information for every members that are in the CWL group. */
|
|
31
|
-
fetchMembers(): Promise<Player[]>;
|
|
32
|
+
fetchMembers(options?: OverrideOptions): Promise<Player[]>;
|
|
32
33
|
}
|
|
33
34
|
/** Represents a Round of CWL Group. */
|
|
34
35
|
export declare class ClanWarLeagueRound {
|
|
@@ -54,7 +55,7 @@ export declare class ClanWarLeagueGroup {
|
|
|
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.
|
|
56
57
|
*/
|
|
57
|
-
getWars(clanTag?: string): Promise<ClanWar[]>;
|
|
58
|
+
getWars(clanTag?: string, options?: OverrideOptions): Promise<ClanWar[]>;
|
|
58
59
|
private _getCurrentWars;
|
|
59
60
|
/** Returns # (1-7) of the round for the specified warTag. */
|
|
60
61
|
getRoundIndex(warTag: string): number | null;
|