clashofclans.js 2.0.0-dev.0a8e422 → 2.0.0-dev.75d755c
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/README.md +1 -1
- package/dist/client/Client.d.ts +5 -10
- package/dist/client/Client.js +12 -11
- package/dist/client/EventManager.d.ts +13 -13
- package/dist/client/EventManager.js +57 -34
- package/dist/rest/HTTPError.d.ts +2 -2
- package/dist/rest/HTTPError.js +3 -3
- package/dist/rest/RequestHandler.d.ts +1 -1
- package/dist/rest/RequestHandler.js +5 -4
- package/dist/struct/ClanWarLeagueGroup.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ const client = new Client({
|
|
|
44
44
|
throttler: new BatchThrottler(30)
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
client.events.addClans(['#8P2QG08P']);
|
|
47
|
+
client.events.addClans(['#8QU8J9LP', '#8P2QG08P']);
|
|
48
48
|
client.events.setClanEvent({
|
|
49
49
|
name: 'clanDescriptionChange',
|
|
50
50
|
filter: (oldClan, newClan) => {
|
package/dist/client/Client.d.ts
CHANGED
|
@@ -155,8 +155,7 @@ export declare class Client extends EventEmitter {
|
|
|
155
155
|
emit<S extends keyof CustomEvents>(event: Exclude<S, keyof ClientEvents>, ...args: CustomEvents[S]): this;
|
|
156
156
|
/** @internal */ emit<S extends string | symbol>(event: Exclude<S, keyof ClientEvents>, ...args: any[]): boolean;
|
|
157
157
|
}
|
|
158
|
-
|
|
159
|
-
export interface ClientEvents {
|
|
158
|
+
interface ClientEvents {
|
|
160
159
|
[EVENTS.NEW_SEASON_START]: [id: string];
|
|
161
160
|
[EVENTS.MAINTENANCE_START]: [];
|
|
162
161
|
[EVENTS.MAINTENANCE_END]: [duration: number];
|
|
@@ -168,13 +167,9 @@ export interface ClientEvents {
|
|
|
168
167
|
[EVENTS.WAR_LOOP_END]: [];
|
|
169
168
|
[EVENTS.ERROR]: [error: unknown];
|
|
170
169
|
}
|
|
171
|
-
|
|
172
|
-
* Custom events that can be emitted by the client.
|
|
173
|
-
*
|
|
174
|
-
* TypeScript 4.5 now can narrow values that have template string types, and also recognizes template string types as discriminants.
|
|
175
|
-
*/
|
|
176
|
-
export interface CustomEvents {
|
|
170
|
+
interface CustomEvents {
|
|
177
171
|
[key: `clan${string}`]: [oldClan: Clan, newClan: Clan];
|
|
178
|
-
[key: `
|
|
179
|
-
[key: `
|
|
172
|
+
[key: `war${string}`]: [oldWar: ClanWar, newWar: ClanWar];
|
|
173
|
+
[key: `player${string}`]: [oldPlayer: Player, newPlayer: Player];
|
|
180
174
|
}
|
|
175
|
+
export {};
|
package/dist/client/Client.js
CHANGED
|
@@ -66,7 +66,7 @@ class Client extends events_1.EventEmitter {
|
|
|
66
66
|
async getClanWar(clanTag, options) {
|
|
67
67
|
const { data, maxAge, path, status } = await this.rest.getCurrentWar(clanTag, options);
|
|
68
68
|
if (data.state === 'notInWar') {
|
|
69
|
-
throw new HTTPError_1.HTTPError(HTTPError_1.
|
|
69
|
+
throw new HTTPError_1.HTTPError(HTTPError_1.NotInWarError, status, path, maxAge);
|
|
70
70
|
}
|
|
71
71
|
return new struct_1.ClanWar(this, data, { clanTag, maxAge });
|
|
72
72
|
}
|
|
@@ -87,11 +87,11 @@ class Client extends events_1.EventEmitter {
|
|
|
87
87
|
return await this.getClanWar(args.clanTag, options);
|
|
88
88
|
}
|
|
89
89
|
catch (e) {
|
|
90
|
-
if (e instanceof HTTPError_1.HTTPError && e.status
|
|
90
|
+
if (e instanceof HTTPError_1.HTTPError && [200, 403].includes(e.status)) {
|
|
91
91
|
return this.getLeagueWar({ clanTag: args.clanTag, round: args.round });
|
|
92
92
|
}
|
|
93
|
+
throw e;
|
|
93
94
|
}
|
|
94
|
-
return null;
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
97
|
* Get info about currently running CWL round.
|
|
@@ -129,17 +129,18 @@ class Client extends events_1.EventEmitter {
|
|
|
129
129
|
return data._getCurrentWars(clanTag);
|
|
130
130
|
}
|
|
131
131
|
async _getClanWars(clanTag, options) {
|
|
132
|
-
const date = new Date().
|
|
133
|
-
|
|
132
|
+
const date = new Date().getUTCDate();
|
|
133
|
+
if (!(date >= 1 && date <= 10)) {
|
|
134
134
|
return [await this.getClanWar(clanTag, options)];
|
|
135
135
|
}
|
|
136
|
+
try {
|
|
137
|
+
return this._getCurrentLeagueWars(clanTag);
|
|
138
|
+
}
|
|
136
139
|
catch (e) {
|
|
137
|
-
if (
|
|
138
|
-
return [];
|
|
139
|
-
if (e instanceof HTTPError_1.HTTPError && [200, 403].includes(e.status)) {
|
|
140
|
-
return this._getCurrentLeagueWars(clanTag);
|
|
140
|
+
if (e instanceof HTTPError_1.HTTPError && [404].includes(e.status)) {
|
|
141
|
+
return [await this.getClanWar(clanTag)];
|
|
141
142
|
}
|
|
142
|
-
|
|
143
|
+
throw e;
|
|
143
144
|
}
|
|
144
145
|
}
|
|
145
146
|
/** Get information about clan war league. */
|
|
@@ -152,7 +153,7 @@ class Client extends events_1.EventEmitter {
|
|
|
152
153
|
const args = typeof warTag === 'string' ? { warTag } : { warTag: warTag.warTag, clanTag: warTag.clanTag };
|
|
153
154
|
const { data, maxAge, status, path } = await this.rest.getClanWarLeagueRound(args.warTag, options);
|
|
154
155
|
if (data.state === 'notInWar') {
|
|
155
|
-
throw new HTTPError_1.HTTPError(HTTPError_1.
|
|
156
|
+
throw new HTTPError_1.HTTPError(HTTPError_1.NotInWarError, status, path, maxAge);
|
|
156
157
|
}
|
|
157
158
|
return new struct_1.ClanWar(this, data, { warTag: args.warTag, clanTag: args.clanTag, maxAge });
|
|
158
159
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Clan, ClanWar, Player } from '../struct';
|
|
2
2
|
import { Client } from './Client';
|
|
3
|
-
/** Represents Event Manager of the {@link Client}
|
|
3
|
+
/** Represents Event Manager of the {@link Client}. */
|
|
4
4
|
export declare class EventManager {
|
|
5
5
|
private readonly client;
|
|
6
6
|
private readonly _clanTags;
|
|
@@ -15,18 +15,18 @@ export declare class EventManager {
|
|
|
15
15
|
constructor(client: Client);
|
|
16
16
|
/** Initialize the Event Manager to start pulling. */
|
|
17
17
|
init(): Promise<string[]>;
|
|
18
|
-
/** Add
|
|
19
|
-
addClans(
|
|
20
|
-
/** Delete
|
|
21
|
-
deleteClans(
|
|
22
|
-
/** Add
|
|
23
|
-
addPlayers(
|
|
24
|
-
/** Delete
|
|
25
|
-
deletePlayers(
|
|
26
|
-
/** Add
|
|
27
|
-
addWars(
|
|
28
|
-
/** Delete
|
|
29
|
-
deleteWars(
|
|
18
|
+
/** Add clan tags to clan events. */
|
|
19
|
+
addClans(tags: string[] | string): this;
|
|
20
|
+
/** Delete clan tags from clan events. */
|
|
21
|
+
deleteClans(tags: string[] | string): this;
|
|
22
|
+
/** Add player tags for player events. */
|
|
23
|
+
addPlayers(tags: string[] | string): this;
|
|
24
|
+
/** Delete player tags from player events. */
|
|
25
|
+
deletePlayers(tags: string[] | string): this;
|
|
26
|
+
/** Add clan tags for war events. */
|
|
27
|
+
addWars(tags: string[] | string): this;
|
|
28
|
+
/** Delete clan tags from war events. */
|
|
29
|
+
deleteWars(tags: string[] | string): this;
|
|
30
30
|
/**
|
|
31
31
|
* Set your own custom clan event.
|
|
32
32
|
*
|
|
@@ -4,7 +4,7 @@ exports.EventManager = void 0;
|
|
|
4
4
|
const HTTPError_1 = require("../rest/HTTPError");
|
|
5
5
|
const Constants_1 = require("../util/Constants");
|
|
6
6
|
const Util_1 = require("../util/Util");
|
|
7
|
-
/** Represents Event Manager of the {@link Client}
|
|
7
|
+
/** Represents Event Manager of the {@link Client}. */
|
|
8
8
|
class EventManager {
|
|
9
9
|
constructor(client) {
|
|
10
10
|
this.client = client;
|
|
@@ -31,45 +31,52 @@ class EventManager {
|
|
|
31
31
|
this.warUpdateHandler();
|
|
32
32
|
return Promise.resolve(this.client.eventNames());
|
|
33
33
|
}
|
|
34
|
-
/** Add
|
|
35
|
-
addClans(
|
|
36
|
-
for (const tag of tags) {
|
|
34
|
+
/** Add clan tags to clan events. */
|
|
35
|
+
addClans(tags) {
|
|
36
|
+
for (const tag of Array.isArray(tags) ? tags : [tags]) {
|
|
37
37
|
this._clanTags.add(this.client.util.parseTag(tag));
|
|
38
38
|
}
|
|
39
39
|
return this;
|
|
40
40
|
}
|
|
41
|
-
/** Delete
|
|
42
|
-
deleteClans(
|
|
43
|
-
for (const tag of tags) {
|
|
44
|
-
this.
|
|
41
|
+
/** Delete clan tags from clan events. */
|
|
42
|
+
deleteClans(tags) {
|
|
43
|
+
for (const tag of Array.isArray(tags) ? tags : [tags]) {
|
|
44
|
+
const key = this.client.util.parseTag(tag);
|
|
45
|
+
this._clans.delete(key);
|
|
46
|
+
this._clanTags.delete(key);
|
|
45
47
|
}
|
|
46
48
|
return this;
|
|
47
49
|
}
|
|
48
|
-
/** Add
|
|
49
|
-
addPlayers(
|
|
50
|
-
for (const tag of tags) {
|
|
50
|
+
/** Add player tags for player events. */
|
|
51
|
+
addPlayers(tags) {
|
|
52
|
+
for (const tag of Array.isArray(tags) ? tags : [tags]) {
|
|
51
53
|
this._playerTags.add(this.client.util.parseTag(tag));
|
|
52
54
|
}
|
|
53
55
|
return this;
|
|
54
56
|
}
|
|
55
|
-
/** Delete
|
|
56
|
-
deletePlayers(
|
|
57
|
-
for (const tag of tags) {
|
|
58
|
-
this.
|
|
57
|
+
/** Delete player tags from player events. */
|
|
58
|
+
deletePlayers(tags) {
|
|
59
|
+
for (const tag of Array.isArray(tags) ? tags : [tags]) {
|
|
60
|
+
const key = this.client.util.parseTag(tag);
|
|
61
|
+
this._players.delete(key);
|
|
62
|
+
this._playerTags.delete(key);
|
|
59
63
|
}
|
|
60
64
|
return this;
|
|
61
65
|
}
|
|
62
|
-
/** Add
|
|
63
|
-
addWars(
|
|
64
|
-
for (const tag of tags) {
|
|
66
|
+
/** Add clan tags for war events. */
|
|
67
|
+
addWars(tags) {
|
|
68
|
+
for (const tag of Array.isArray(tags) ? tags : [tags]) {
|
|
65
69
|
this._warTags.add(this.client.util.parseTag(tag));
|
|
66
70
|
}
|
|
67
71
|
return this;
|
|
68
72
|
}
|
|
69
|
-
/** Delete
|
|
70
|
-
deleteWars(
|
|
71
|
-
for (const tag of tags) {
|
|
72
|
-
this.
|
|
73
|
+
/** Delete clan tags from war events. */
|
|
74
|
+
deleteWars(tags) {
|
|
75
|
+
for (const tag of Array.isArray(tags) ? tags : [tags]) {
|
|
76
|
+
const key = this.client.util.parseTag(tag);
|
|
77
|
+
this._wars.delete(`${key}:${1}`);
|
|
78
|
+
this._wars.delete(`${key}:${2}`);
|
|
79
|
+
this._warTags.delete(key);
|
|
73
80
|
}
|
|
74
81
|
return this;
|
|
75
82
|
}
|
|
@@ -100,7 +107,7 @@ class EventManager {
|
|
|
100
107
|
* @returns
|
|
101
108
|
*/
|
|
102
109
|
setClanEvent(event) {
|
|
103
|
-
this._events.clans.push(
|
|
110
|
+
this._events.clans.push(event);
|
|
104
111
|
return this;
|
|
105
112
|
}
|
|
106
113
|
/**
|
|
@@ -109,7 +116,7 @@ class EventManager {
|
|
|
109
116
|
* In order to emit the custom event, you must have this filter function that returns a boolean.
|
|
110
117
|
*/
|
|
111
118
|
setWarEvent(event) {
|
|
112
|
-
this._events.wars.push(
|
|
119
|
+
this._events.wars.push(event);
|
|
113
120
|
return this;
|
|
114
121
|
}
|
|
115
122
|
/**
|
|
@@ -118,7 +125,7 @@ class EventManager {
|
|
|
118
125
|
* In order to emit the custom event, you must have this filter function that returns a boolean.
|
|
119
126
|
*/
|
|
120
127
|
setPlayerEvent(event) {
|
|
121
|
-
this._events.players.push(
|
|
128
|
+
this._events.players.push(event);
|
|
122
129
|
return this;
|
|
123
130
|
}
|
|
124
131
|
async maintenanceHandler() {
|
|
@@ -164,7 +171,7 @@ class EventManager {
|
|
|
164
171
|
for (const tag of this._playerTags)
|
|
165
172
|
await this.runPlayerUpdate(tag);
|
|
166
173
|
this.client.emit(Constants_1.EVENTS.PLAYER_LOOP_END);
|
|
167
|
-
setTimeout(this.playerUpdateHandler.bind(this),
|
|
174
|
+
setTimeout(this.playerUpdateHandler.bind(this), 10000);
|
|
168
175
|
}
|
|
169
176
|
async warUpdateHandler() {
|
|
170
177
|
this.client.emit(Constants_1.EVENTS.WAR_LOOP_START);
|
|
@@ -182,9 +189,9 @@ class EventManager {
|
|
|
182
189
|
const cached = this._clans.get(clan.tag);
|
|
183
190
|
if (!cached)
|
|
184
191
|
return this._clans.set(clan.tag, clan);
|
|
185
|
-
for (const { name,
|
|
192
|
+
for (const { name, filter } of this._events.clans) {
|
|
186
193
|
try {
|
|
187
|
-
if (!
|
|
194
|
+
if (!filter(cached, clan))
|
|
188
195
|
continue;
|
|
189
196
|
this.client.emit(name, cached, clan);
|
|
190
197
|
}
|
|
@@ -203,9 +210,9 @@ class EventManager {
|
|
|
203
210
|
const cached = this._players.get(player.tag);
|
|
204
211
|
if (!cached)
|
|
205
212
|
return this._players.set(player.tag, player);
|
|
206
|
-
for (const { name,
|
|
213
|
+
for (const { name, filter } of this._events.players) {
|
|
207
214
|
try {
|
|
208
|
-
if (!
|
|
215
|
+
if (!filter(cached, player))
|
|
209
216
|
continue;
|
|
210
217
|
this.client.emit(name, cached, player);
|
|
211
218
|
}
|
|
@@ -222,14 +229,14 @@ class EventManager {
|
|
|
222
229
|
const clanWars = await this.client._getClanWars(tag).catch(() => null);
|
|
223
230
|
if (!clanWars?.length)
|
|
224
231
|
return null;
|
|
225
|
-
clanWars.forEach((war,
|
|
226
|
-
const key =
|
|
232
|
+
clanWars.forEach(async (war, state) => {
|
|
233
|
+
const key = `${tag}:${state}`;
|
|
227
234
|
const cached = this._wars.get(key);
|
|
228
235
|
if (!cached)
|
|
229
236
|
return this._wars.set(key, war);
|
|
230
|
-
for (const { name,
|
|
237
|
+
for (const { name, filter } of this._events.wars) {
|
|
231
238
|
try {
|
|
232
|
-
if (!
|
|
239
|
+
if (!filter(cached, war))
|
|
233
240
|
continue;
|
|
234
241
|
this.client.emit(name, cached, war);
|
|
235
242
|
}
|
|
@@ -237,6 +244,22 @@ class EventManager {
|
|
|
237
244
|
this.client.emit(Constants_1.EVENTS.ERROR, error);
|
|
238
245
|
}
|
|
239
246
|
}
|
|
247
|
+
// check for war end
|
|
248
|
+
if (state === 1 && cached.warTag !== war.warTag) {
|
|
249
|
+
const data = await this.client.getLeagueWar({ clanTag: tag, round: 'PREVIOUS_ROUND' }).catch(() => null);
|
|
250
|
+
if (data && data.warTag === cached.warTag) {
|
|
251
|
+
for (const { name, filter } of this._events.wars) {
|
|
252
|
+
try {
|
|
253
|
+
if (!filter(cached, data))
|
|
254
|
+
continue;
|
|
255
|
+
this.client.emit(name, cached, data);
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
this.client.emit(Constants_1.EVENTS.ERROR, error);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
240
263
|
return this._wars.set(key, war);
|
|
241
264
|
});
|
|
242
265
|
}
|
package/dist/rest/HTTPError.d.ts
CHANGED
|
@@ -16,11 +16,11 @@ export declare class HTTPError extends Error {
|
|
|
16
16
|
maxAge: number;
|
|
17
17
|
constructor(error: any, status: number, path: string, maxAge: number, method?: string);
|
|
18
18
|
}
|
|
19
|
-
export declare const
|
|
19
|
+
export declare const NotInWarError: {
|
|
20
20
|
message: string;
|
|
21
21
|
reason: string;
|
|
22
22
|
};
|
|
23
|
-
export declare const
|
|
23
|
+
export declare const PrivateWarLogError: {
|
|
24
24
|
message: string;
|
|
25
25
|
reason: string;
|
|
26
26
|
};
|
package/dist/rest/HTTPError.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.PrivateWarLogError = exports.NotInWarError = exports.HTTPError = void 0;
|
|
4
4
|
const messages = {
|
|
5
5
|
500: 'Unknown error happened when handling the request.',
|
|
6
6
|
504: 'The user aborted this request.',
|
|
@@ -34,11 +34,11 @@ class HTTPError extends Error {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
exports.HTTPError = HTTPError;
|
|
37
|
-
exports.
|
|
37
|
+
exports.NotInWarError = {
|
|
38
38
|
message: 'Clan is not in war at this moment.',
|
|
39
39
|
reason: 'notInWar'
|
|
40
40
|
};
|
|
41
|
-
exports.
|
|
41
|
+
exports.PrivateWarLogError = {
|
|
42
42
|
message: 'Access denied, clan war log is private.',
|
|
43
43
|
reason: 'privateWarLog'
|
|
44
44
|
};
|
|
@@ -11,9 +11,9 @@ 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();
|
|
@@ -51,7 +51,7 @@ class RequestHandler {
|
|
|
51
51
|
async request(path, options = {}) {
|
|
52
52
|
const cached = (await this.cached?.get(path)) ?? null;
|
|
53
53
|
if (cached && options.force !== true)
|
|
54
|
-
return { data: cached, maxAge:
|
|
54
|
+
return { data: cached.data, maxAge: cached.ttl - Date.now(), status: 200, path };
|
|
55
55
|
if (!this.throttler || options.ignoreRateLimit)
|
|
56
56
|
return this.exec(path, options);
|
|
57
57
|
await this.throttler.wait();
|
|
@@ -79,11 +79,12 @@ class RequestHandler {
|
|
|
79
79
|
}
|
|
80
80
|
const maxAge = Number(res?.headers.get('cache-control')?.split('=')?.[1] ?? 0) * 1000;
|
|
81
81
|
if (res?.status === 403 && !data?.message)
|
|
82
|
-
throw new HTTPError_1.HTTPError(HTTPError_1.
|
|
82
|
+
throw new HTTPError_1.HTTPError(HTTPError_1.PrivateWarLogError, res.status, path, maxAge);
|
|
83
83
|
if (!res?.ok)
|
|
84
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, maxAge);
|
|
85
|
+
if (this.cached && maxAge > 0 && options.cache !== false) {
|
|
86
|
+
await this.cached.set(path, { data, ttl: Date.now() + maxAge }, maxAge);
|
|
87
|
+
}
|
|
87
88
|
return { data, maxAge, status: res.status, path };
|
|
88
89
|
}
|
|
89
90
|
async init(options) {
|
|
@@ -68,7 +68,8 @@ class ClanWarLeagueGroup {
|
|
|
68
68
|
const warTags = rounds
|
|
69
69
|
.slice(-2)
|
|
70
70
|
.map((round) => round.warTags)
|
|
71
|
-
.flat()
|
|
71
|
+
.flat()
|
|
72
|
+
.reverse();
|
|
72
73
|
const wars = await Promise.allSettled(warTags.map((warTag) => this.client.getClanWarLeagueRound({ warTag, clanTag }, { ignoreRateLimit: true })));
|
|
73
74
|
return wars
|
|
74
75
|
.filter((res) => res.status === 'fulfilled')
|
package/package.json
CHANGED