clashofclans.js 2.0.0-dev.86dfaef → 2.0.0-dev.dedb83d

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.
@@ -141,15 +141,21 @@ export declare class Client extends EventEmitter {
141
141
  private static maintenanceEnd;
142
142
  /** @internal */
143
143
  on<K extends keyof ClientEvents>(event: K, listeners: (...args: ClientEvents[K]) => void): this;
144
+ /** @internal */
145
+ on<S extends keyof CustomEvents>(event: Exclude<S, keyof ClientEvents>, listeners: (...args: CustomEvents[S]) => void): this;
144
146
  /** @internal */ on<S extends string | symbol>(event: Exclude<S, keyof ClientEvents>, listeners: (...args: any[]) => void): this;
145
147
  /** @internal */
146
148
  once<K extends keyof ClientEvents>(event: K, listeners: (...args: ClientEvents[K]) => void): this;
149
+ /** @internal */
150
+ once<S extends keyof CustomEvents>(event: Exclude<S, keyof ClientEvents>, listeners: (...args: CustomEvents[S]) => void): this;
147
151
  /** @internal */ once<S extends string | symbol>(event: Exclude<S, keyof ClientEvents>, listeners: (...args: any[]) => void): this;
148
152
  /** @internal */
149
153
  emit<K extends keyof ClientEvents>(event: K, ...args: ClientEvents[K]): boolean;
154
+ /** @internal */
155
+ emit<S extends keyof CustomEvents>(event: Exclude<S, keyof ClientEvents>, ...args: CustomEvents[S]): this;
150
156
  /** @internal */ emit<S extends string | symbol>(event: Exclude<S, keyof ClientEvents>, ...args: any[]): boolean;
151
157
  }
152
- export interface ClientEvents {
158
+ interface ClientEvents {
153
159
  [EVENTS.NEW_SEASON_START]: [id: string];
154
160
  [EVENTS.MAINTENANCE_START]: [];
155
161
  [EVENTS.MAINTENANCE_END]: [duration: number];
@@ -161,3 +167,9 @@ export interface ClientEvents {
161
167
  [EVENTS.WAR_LOOP_END]: [];
162
168
  [EVENTS.ERROR]: [error: unknown];
163
169
  }
170
+ interface CustomEvents {
171
+ [key: `clan${string}`]: [oldClan: Clan, newClan: Clan];
172
+ [key: `war${string}`]: [oldWar: ClanWar, newWar: ClanWar];
173
+ [key: `player${string}`]: [oldPlayer: Player, newPlayer: Player];
174
+ }
175
+ export {};
@@ -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.notInWarError, status, path, maxAge);
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 === 403) {
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().getDate();
133
- try {
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 (!(date >= 1 && date <= 10))
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
- return [];
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.notInWarError, status, path, maxAge);
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} class. */
3
+ /** Represents Event Manager of the {@link Client}. */
4
4
  export declare class EventManager {
5
5
  private readonly client;
6
6
  private readonly _clanTags;
@@ -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} class. */
7
+ /** Represents Event Manager of the {@link Client}. */
8
8
  class EventManager {
9
9
  constructor(client) {
10
10
  this.client = client;
@@ -100,7 +100,7 @@ class EventManager {
100
100
  * @returns
101
101
  */
102
102
  setClanEvent(event) {
103
- this._events.clans.push({ name: event.name, fn: event.filter });
103
+ this._events.clans.push(event);
104
104
  return this;
105
105
  }
106
106
  /**
@@ -109,7 +109,7 @@ class EventManager {
109
109
  * In order to emit the custom event, you must have this filter function that returns a boolean.
110
110
  */
111
111
  setWarEvent(event) {
112
- this._events.wars.push({ name: event.name, fn: event.filter });
112
+ this._events.wars.push(event);
113
113
  return this;
114
114
  }
115
115
  /**
@@ -118,7 +118,7 @@ class EventManager {
118
118
  * In order to emit the custom event, you must have this filter function that returns a boolean.
119
119
  */
120
120
  setPlayerEvent(event) {
121
- this._events.players.push({ name: event.name, fn: event.filter });
121
+ this._events.players.push(event);
122
122
  return this;
123
123
  }
124
124
  async maintenanceHandler() {
@@ -164,7 +164,7 @@ class EventManager {
164
164
  for (const tag of this._playerTags)
165
165
  await this.runPlayerUpdate(tag);
166
166
  this.client.emit(Constants_1.EVENTS.PLAYER_LOOP_END);
167
- setTimeout(this.playerUpdateHandler.bind(this), 100000);
167
+ setTimeout(this.playerUpdateHandler.bind(this), 10000);
168
168
  }
169
169
  async warUpdateHandler() {
170
170
  this.client.emit(Constants_1.EVENTS.WAR_LOOP_START);
@@ -182,9 +182,9 @@ class EventManager {
182
182
  const cached = this._clans.get(clan.tag);
183
183
  if (!cached)
184
184
  return this._clans.set(clan.tag, clan);
185
- for (const { name, fn } of this._events.clans) {
185
+ for (const { name, filter } of this._events.clans) {
186
186
  try {
187
- if (!fn(cached, clan))
187
+ if (!filter(cached, clan))
188
188
  continue;
189
189
  this.client.emit(name, cached, clan);
190
190
  }
@@ -203,9 +203,9 @@ class EventManager {
203
203
  const cached = this._players.get(player.tag);
204
204
  if (!cached)
205
205
  return this._players.set(player.tag, player);
206
- for (const { name, fn } of this._events.players) {
206
+ for (const { name, filter } of this._events.players) {
207
207
  try {
208
- if (!fn(cached, player))
208
+ if (!filter(cached, player))
209
209
  continue;
210
210
  this.client.emit(name, cached, player);
211
211
  }
@@ -222,14 +222,14 @@ class EventManager {
222
222
  const clanWars = await this.client._getClanWars(tag).catch(() => null);
223
223
  if (!clanWars?.length)
224
224
  return null;
225
- clanWars.forEach((war, i) => {
226
- const key = `WAR:${i}:${tag}`;
225
+ clanWars.forEach(async (war, state) => {
226
+ const key = `${tag}:${state}`;
227
227
  const cached = this._wars.get(key);
228
228
  if (!cached)
229
229
  return this._wars.set(key, war);
230
- for (const { name, fn } of this._events.wars) {
230
+ for (const { name, filter } of this._events.wars) {
231
231
  try {
232
- if (!fn(cached, war))
232
+ if (!filter(cached, war))
233
233
  continue;
234
234
  this.client.emit(name, cached, war);
235
235
  }
@@ -237,6 +237,22 @@ class EventManager {
237
237
  this.client.emit(Constants_1.EVENTS.ERROR, error);
238
238
  }
239
239
  }
240
+ // check for war end
241
+ if (state === 1 && cached.warTag !== war.warTag) {
242
+ const data = await this.client.getLeagueWar({ clanTag: tag, round: 'PREVIOUS_ROUND' }).catch(() => null);
243
+ if (data && data.warTag === cached.warTag) {
244
+ for (const { name, filter } of this._events.wars) {
245
+ try {
246
+ if (!filter(cached, data))
247
+ continue;
248
+ this.client.emit(name, cached, data);
249
+ }
250
+ catch (error) {
251
+ this.client.emit(Constants_1.EVENTS.ERROR, error);
252
+ }
253
+ }
254
+ }
255
+ }
240
256
  return this._wars.set(key, war);
241
257
  });
242
258
  }
@@ -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 notInWarError: {
19
+ export declare const NotInWarError: {
20
20
  message: string;
21
21
  reason: string;
22
22
  };
23
- export declare const privateWarLogError: {
23
+ export declare const PrivateWarLogError: {
24
24
  message: string;
25
25
  reason: string;
26
26
  };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.privateWarLogError = exports.notInWarError = exports.HTTPError = void 0;
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.notInWarError = {
37
+ exports.NotInWarError = {
38
38
  message: 'Clan is not in war at this moment.',
39
39
  reason: 'notInWar'
40
40
  };
41
- exports.privateWarLogError = {
41
+ exports.PrivateWarLogError = {
42
42
  message: 'Access denied, clan war log is private.',
43
43
  reason: 'privateWarLog'
44
44
  };
@@ -79,7 +79,7 @@ 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.privateWarLogError, res.status, path, maxAge);
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
85
  if (this.cached && maxAge > 0 && options.cache !== false)
@@ -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/dist/util/Util.js CHANGED
@@ -18,6 +18,8 @@ class Util extends null {
18
18
  /** Get URL search params. */
19
19
  static queryString(options = {}) {
20
20
  const query = new URLSearchParams(options);
21
+ for (const key of ['cache', 'force', 'retryLimit', 'ignoreRateLimit', 'restRequestTimeout'])
22
+ query.delete(key);
21
23
  return query.toString();
22
24
  }
23
25
  static getSeasonEnd(month, autoFix = true) {
@@ -41,7 +43,7 @@ class Util extends null {
41
43
  }
42
44
  static async allSettled(values) {
43
45
  return (await Promise.allSettled(values))
44
- .filter((res) => res.status === 'fulfilled' && res.value)
46
+ .filter((res) => res.status === 'fulfilled')
45
47
  .map((res) => res.value);
46
48
  }
47
49
  static async delay(ms) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clashofclans.js",
3
- "version": "2.0.0-dev.86dfaef",
3
+ "version": "2.0.0-dev.dedb83d",
4
4
  "description": "JavaScript library for interacting with the Clash of Clans API",
5
5
  "author": "SUVAJIT <suvajit.me@gmail.com>",
6
6
  "license": "MIT",
@@ -95,15 +95,15 @@
95
95
  "@types/keyv": "^3.1.3",
96
96
  "@types/node": "^16.10.3",
97
97
  "@types/node-fetch": "^2.5.12",
98
- "@typescript-eslint/eslint-plugin": "^5.0.0",
99
- "@typescript-eslint/parser": "^5.0.0",
100
- "eslint": "^7.28.0",
98
+ "@typescript-eslint/eslint-plugin": "^5.4.0",
99
+ "@typescript-eslint/parser": "^5.4.0",
100
+ "eslint": "^8.3.0",
101
101
  "eslint-config-marine": "^9.0.6",
102
102
  "eslint-config-prettier": "^8.3.0",
103
103
  "eslint-plugin-prettier": "^4.0.0",
104
104
  "prettier": "^2.4.1",
105
105
  "rimraf": "^3.0.2",
106
- "typescript": "^4.4.3"
106
+ "typescript": "^4.5.2"
107
107
  },
108
108
  "engines": {
109
109
  "node": ">=14.x"