clashofclans.js 3.0.0-dev.ec60c82 → 3.0.0

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 CHANGED
@@ -2,121 +2,140 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## 3.0.0 (11-01-2023)
6
+
7
+ ### Bug Fixes
8
+
9
+ - Conflict with the same name of builder base and home base troops. (#123)
10
+ - Fix the issue with the `Client#getLeagueWar()` method.
11
+ - Typings and documentation for clan capital.
12
+
13
+ ### Features
14
+
15
+ - Added `Client#getCapitalRaidSeasons()` method.
16
+ - Added `Client#getCapitalLeagues()` method.
17
+ - Added `Client#getClanCapitalRanks()` method.
18
+
19
+ ### Breaking Changes
20
+
21
+ - Using PascalCase instead of SCREAMING_SNAKE_CASE ([#115](https://github.com/clashperk/clashofclans.js/pull/115))
22
+ - `Client#events` and `EventManager` have been removed in favor of `PollingClient` ([#117](https://github.com/clashperk/clashofclans.js/pull/117), [#127](https://github.com/clashperk/clashofclans.js/pull/127))
23
+
5
24
  ## 2.8.0 (2022-07-22)
6
25
 
7
26
  ### Features
8
27
 
9
- - Better Throttler with JS generator function. ([#111](https://github.com/clashperk/clashofclans.js/pull/111))
10
- - Updated raw data from game files. ([#111](https://github.com/clashperk/clashofclans.js/pull/111))
11
- - New method Util#parseArmyLink has been added. ([#110](https://github.com/clashperk/clashofclans.js/pull/110))
28
+ - Better Throttler with JS generator function. ([#111](https://github.com/clashperk/clashofclans.js/pull/111))
29
+ - Updated raw data from game files. ([#111](https://github.com/clashperk/clashofclans.js/pull/111))
30
+ - New method Util#parseArmyLink has been added. ([#110](https://github.com/clashperk/clashofclans.js/pull/110))
12
31
 
13
32
  ## 2.7.0 (2022-05-22)
14
33
 
15
34
  ### Features
16
35
 
17
- - Some useful QOL methods have been added. ([#106](https://github.com/clashperk/clashofclans.js/pull/106))
36
+ - Some useful QOL methods have been added. ([#106](https://github.com/clashperk/clashofclans.js/pull/106))
18
37
 
19
38
  ## 2.6.1 (2022-02-03)
20
39
 
21
40
  ### Bug Fixes
22
41
 
23
- - New value and typings `notInWar` added for `ClanWarLeagueGroup#state` ([#101](https://github.com/clashperk/clashofclans.js/pull/101))
24
- - Throw error if `Util.formatTag` / `Util.parseTag` is called with invalid argument ([#102](https://github.com/clashperk/clashofclans.js/pull/101))
42
+ - New value and typings `notInWar` added for `ClanWarLeagueGroup#state` ([#101](https://github.com/clashperk/clashofclans.js/pull/101))
43
+ - Throw error if `Util.formatTag` / `Util.parseTag` is called with invalid argument ([#102](https://github.com/clashperk/clashofclans.js/pull/101))
25
44
 
26
45
  ## 2.6.0 (2022-01-29)
27
46
 
28
47
  ## Features
29
48
 
30
- - Replaced Keyv with customizable cache store ([#99](https://github.com/clashperk/clashofclans.js/pull/99))
31
- - Guide for [Internal Caching](https://clashofclans.js.org/guide/internal-caching)
49
+ - Replaced Keyv with customizable cache store ([#99](https://github.com/clashperk/clashofclans.js/pull/99))
50
+ - Guide for [Internal Caching](https://clashofclans.js.org/guide/internal-caching)
32
51
 
33
52
  ## 2.5.2 (2022-01-23)
34
53
 
35
54
  ### Bug Fixes
36
55
 
37
- - Fix `ClanWar#attacksPerMembers` property ([#97](https://github.com/clashperk/clashofclans.js/pull/97))
38
- - Bump `node-fetch` from 2.6.6 to 2.6.7 ([#96](https://github.com/clashperk/clashofclans.js/pull/96))
56
+ - Fix `ClanWar#attacksPerMembers` property ([#97](https://github.com/clashperk/clashofclans.js/pull/97))
57
+ - Bump `node-fetch` from 2.6.6 to 2.6.7 ([#96](https://github.com/clashperk/clashofclans.js/pull/96))
39
58
 
40
59
  ## 2.5.1 (2022-01-11)
41
60
 
42
61
  ### Bug Fixes
43
62
 
44
- - Typings for `ClanWarLeagueGroup#state` property. ([#94](https://github.com/clashperk/clashofclans.js/pull/94))
63
+ - Typings for `ClanWarLeagueGroup#state` property. ([#94](https://github.com/clashperk/clashofclans.js/pull/94))
45
64
 
46
65
  ## 2.5.0 (2021-12-30)
47
66
 
48
67
  ### Bug Fixes
49
68
 
50
- - Fix caching issue with unnecessary/invalid query params. ([#91](https://github.com/clashperk/clashofclans.js/pull/91))
51
- - Added necessary methods to `RESTManager` class. ([#92](https://github.com/clashperk/clashofclans.js/pull/92))
69
+ - Fix caching issue with unnecessary/invalid query params. ([#91](https://github.com/clashperk/clashofclans.js/pull/91))
70
+ - Added necessary methods to `RESTManager` class. ([#92](https://github.com/clashperk/clashofclans.js/pull/92))
52
71
 
53
72
  ## 2.4.0 (2021-12-28)
54
73
 
55
74
  ### Features
56
75
 
57
- - `ClanWar#getClanWarLeagueGroup`, `ClanWar#isCWL` and `ClanWar#isFriendly` are now available. ([#87](https://github.com/clashperk/clashofclans.js/pull/87))
58
- - `RESTOptions#rejectIfNotValid` added to perform `res.ok` operations over `RESTManager` methods. [Know more?](https://clashofclans.js.org/guide/access-raw-data#easy-access) ([#87](https://github.com/clashperk/clashofclans.js/pull/87))
59
- - `Icon#fileName` and `Icon#sizes` are now available in `Icon` class. ([#87](https://github.com/clashperk/clashofclans.js/pull/87))
60
- - `Badge#fileName` and `Badge#sizes` are now available in `Badge` class. ([#87](https://github.com/clashperk/clashofclans.js/pull/87))
76
+ - `ClanWar#getClanWarLeagueGroup`, `ClanWar#isCWL` and `ClanWar#isFriendly` are now available. ([#87](https://github.com/clashperk/clashofclans.js/pull/87))
77
+ - `RESTOptions#rejectIfNotValid` added to perform `res.ok` operations over `RESTManager` methods. [Know more?](https://clashofclans.js.org/guide/access-raw-data#easy-access) ([#87](https://github.com/clashperk/clashofclans.js/pull/87))
78
+ - `Icon#fileName` and `Icon#sizes` are now available in `Icon` class. ([#87](https://github.com/clashperk/clashofclans.js/pull/87))
79
+ - `Badge#fileName` and `Badge#sizes` are now available in `Badge` class. ([#87](https://github.com/clashperk/clashofclans.js/pull/87))
61
80
 
62
81
  ### Deprecations
63
82
 
64
- - `ClanWarMember#previousBestOpponentAttack` has been deprecated. Use `ClanWarAttack#previousBestAttack` instead. ([#87](https://github.com/clashperk/clashofclans.js/pull/87))
83
+ - `ClanWarMember#previousBestOpponentAttack` has been deprecated. Use `ClanWarAttack#previousBestAttack` instead. ([#87](https://github.com/clashperk/clashofclans.js/pull/87))
65
84
 
66
85
  ## 2.3.0 (2021-12-17)
67
86
 
68
87
  ### Features
69
88
 
70
- - BigInt literals issue fixed. ([#84](https://github.com/clashperk/clashofclans.js/pull/84))
71
- - Some Utility methods renamed. ([#84](https://github.com/clashperk/clashofclans.js/pull/84))
72
- - `Util.encodeTag()` to `Util.encodeURI()`
73
- - `Util.encodeTagToId()` to `Util.encodeTag()`
74
- - `Util.decodeIdToTag()` to `Util.decodeTag()`
75
- - Added `dps`, `resourceType`, `trainingTime` and `regenerationTime` to the `Unit` class. ([#85](https://github.com/clashperk/clashofclans.js/pull/85))
89
+ - BigInt literals issue fixed. ([#84](https://github.com/clashperk/clashofclans.js/pull/84))
90
+ - Some Utility methods renamed. ([#84](https://github.com/clashperk/clashofclans.js/pull/84))
91
+ - `Util.encodeTag()` to `Util.encodeURI()`
92
+ - `Util.encodeTagToId()` to `Util.encodeTag()`
93
+ - `Util.decodeIdToTag()` to `Util.decodeTag()`
94
+ - Added `dps`, `resourceType`, `trainingTime` and `regenerationTime` to the `Unit` class. ([#85](https://github.com/clashperk/clashofclans.js/pull/85))
76
95
 
77
96
  ## 2.2.0 (2021-12-16)
78
97
 
79
98
  ### Bug Fixes
80
99
 
81
- - Show units as per in-game orders. ([#82](https://github.com/clashperk/clashofclans.js/pull/82)) ([6e23d2f](https://github.com/clashperk/clashofclans.js/commit/95cf3001059fd3ede9262e249814178631660d5b))
82
- - Season end time utility method. ([#82](https://github.com/clashperk/clashofclans.js/pull/82)) ([6e23d2f](https://github.com/clashperk/clashofclans.js/commit/95cf3001059fd3ede9262e249814178631660d5b))
83
- - Updated raw files for new Troops. ([#82](https://github.com/clashperk/clashofclans.js/pull/82)) ([6e23d2f](https://github.com/clashperk/clashofclans.js/commit/95cf3001059fd3ede9262e249814178631660d5b))
100
+ - Show units as per in-game orders. ([#82](https://github.com/clashperk/clashofclans.js/pull/82)) ([6e23d2f](https://github.com/clashperk/clashofclans.js/commit/95cf3001059fd3ede9262e249814178631660d5b))
101
+ - Season end time utility method. ([#82](https://github.com/clashperk/clashofclans.js/pull/82)) ([6e23d2f](https://github.com/clashperk/clashofclans.js/commit/95cf3001059fd3ede9262e249814178631660d5b))
102
+ - Updated raw files for new Troops. ([#82](https://github.com/clashperk/clashofclans.js/pull/82)) ([6e23d2f](https://github.com/clashperk/clashofclans.js/commit/95cf3001059fd3ede9262e249814178631660d5b))
84
103
 
85
104
  ### Features
86
105
 
87
- - Added `seasonal`, `boostable` and `isLoaded` property to `Unit` class. ([#82](https://github.com/clashperk/clashofclans.js/pull/82)) ([6e23d2f](https://github.com/clashperk/clashofclans.js/commit/95cf3001059fd3ede9262e249814178631660d5b))
106
+ - Added `seasonal`, `boostable` and `isLoaded` property to `Unit` class. ([#82](https://github.com/clashperk/clashofclans.js/pull/82)) ([6e23d2f](https://github.com/clashperk/clashofclans.js/commit/95cf3001059fd3ede9262e249814178631660d5b))
88
107
 
89
108
  ## 2.1.0 (2021-12-06)
90
109
 
91
110
  ### Bug Fixes
92
111
 
93
- - Consistency of `ClanWar.attacksPerMember` property. ([#75](https://github.com/clashperk/clashofclans.js/pull/75)) ([6e23d2f](https://github.com/clashperk/clashofclans.js/commit/6e23d2fe0373f56268ffa55d5ac2807c9a2dc2fc))
112
+ - Consistency of `ClanWar.attacksPerMember` property. ([#75](https://github.com/clashperk/clashofclans.js/pull/75)) ([6e23d2f](https://github.com/clashperk/clashofclans.js/commit/6e23d2fe0373f56268ffa55d5ac2807c9a2dc2fc))
94
113
 
95
114
  ### Features
96
115
 
97
- - More utility methods added to `Util` class. ([#76](https://github.com/clashperk/clashofclans.js/pull/76)) ([ff41115](https://github.com/clashperk/clashofclans.js/commit/ff4111530d6293ef1fc54aa916436130fc30a09c))
116
+ - More utility methods added to `Util` class. ([#76](https://github.com/clashperk/clashofclans.js/pull/76)) ([ff41115](https://github.com/clashperk/clashofclans.js/commit/ff4111530d6293ef1fc54aa916436130fc30a09c))
98
117
 
99
- - `Util.formatTag(tag: string): string`
100
- - `Util.formatDate(date: string): Date`
101
- - `Util.isValidTag(tag: string): boolean`
102
- - `Util.encodeTagToId(tag: string): string` (Removed on 2.3.0)
103
- - `Util.decodeIdToTag(id: string): string` (Removed on 2.3.0)
118
+ - `Util.formatTag(tag: string): string`
119
+ - `Util.formatDate(date: string): Date`
120
+ - `Util.isValidTag(tag: string): boolean`
121
+ - `Util.encodeTagToId(tag: string): string` (Removed on 2.3.0)
122
+ - `Util.decodeIdToTag(id: string): string` (Removed on 2.3.0)
104
123
 
105
- - Support of async/await for custom events ([#79](https://github.com/clashperk/clashofclans.js/pull/79)) ([ff41115](https://github.com/clashperk/clashofclans.js/commit/a23db3786bcca44b8547c70f27773bdb1216f990))
124
+ - Support of async/await for custom events ([#79](https://github.com/clashperk/clashofclans.js/pull/79)) ([ff41115](https://github.com/clashperk/clashofclans.js/commit/a23db3786bcca44b8547c70f27773bdb1216f990))
106
125
 
107
126
  ## 2.0.2 (2021-11-30)
108
127
 
109
128
  ### Bug Fixes
110
129
 
111
- - Return `null` for `RankedPlayer.clan` if they are not in the clan. ([#73](https://github.com/clashperk/clashofclans.js/pull/73)) ([ba82327](https://github.com/clashperk/clashofclans.js/commit/ba8232740f4ca9af2bcc7971aca3574612ef25b6))
112
- - `OverrideOptions` added for `Client#getClans` and `RESTManager#getClans` ([#73](https://github.com/clashperk/clashofclans.js/pull/73)) ([ba82327](https://github.com/clashperk/clashofclans.js/commit/ba8232740f4ca9af2bcc7971aca3574612ef25b6))
113
- - `SeasonRankedPlayer` class for legend league ranking. ([#73](https://github.com/clashperk/clashofclans.js/pull/73)) ([ba82327](https://github.com/clashperk/clashofclans.js/commit/ba8232740f4ca9af2bcc7971aca3574612ef25b6))
130
+ - Return `null` for `RankedPlayer.clan` if they are not in the clan. ([#73](https://github.com/clashperk/clashofclans.js/pull/73)) ([ba82327](https://github.com/clashperk/clashofclans.js/commit/ba8232740f4ca9af2bcc7971aca3574612ef25b6))
131
+ - `OverrideOptions` added for `Client#getClans` and `RESTManager#getClans` ([#73](https://github.com/clashperk/clashofclans.js/pull/73)) ([ba82327](https://github.com/clashperk/clashofclans.js/commit/ba8232740f4ca9af2bcc7971aca3574612ef25b6))
132
+ - `SeasonRankedPlayer` class for legend league ranking. ([#73](https://github.com/clashperk/clashofclans.js/pull/73)) ([ba82327](https://github.com/clashperk/clashofclans.js/commit/ba8232740f4ca9af2bcc7971aca3574612ef25b6))
114
133
 
115
134
  ## 2.0.1 (2021-11-27)
116
135
 
117
136
  ### Bug Fixes
118
137
 
119
- - IP retrieval method and Event Loop ([#70](https://github.com/clashperk/clashofclans.js/issues/70)) ([82b84ba](https://github.com/clashperk/clashofclans.js/commit/82b84ba5d96505c43b75e53aa07f547ef0b77778))
138
+ - IP retrieval method and Event Loop ([#70](https://github.com/clashperk/clashofclans.js/issues/70)) ([82b84ba](https://github.com/clashperk/clashofclans.js/commit/82b84ba5d96505c43b75e53aa07f547ef0b77778))
120
139
 
121
140
  ## 2.0.0 (2021-11-26)
122
141
 
@@ -124,10 +143,10 @@ This new version is a complete TypeScript rewrite to convert everything from pla
124
143
 
125
144
  ### Features
126
145
 
127
- - HTTP Request Request Retries ([#26](https://github.com/clashperk/clashofclans.js/issues/26)) ([94585f3](https://github.com/clashperk/clashofclans.js/commit/94585f3a84a7175b2d07872f9eb9e42372b95e12))
128
- - Event Manager and Custom Events ([#37](https://github.com/clashperk/clashofclans.js/issues/37)) ([5027ae6](https://github.com/clashperk/clashofclans.js/commit/5027ae663a8e07175e17384c7e5706f4a1a7afb4))
129
- - Email Password Login ([#31](https://github.com/clashperk/clashofclans.js/issues/31)) ([4153cd3](https://github.com/clashperk/clashofclans.js/commit/4153cd37ea0e1c71550b9e892105b84d5a407e23))
130
- - Queue Throttler and Batch Throttler ([#34](https://github.com/clashperk/clashofclans.js/issues/34)) ([3a8f051](https://github.com/clashperk/clashofclans.js/commit/3a8f051552e93b98f89bc7d524acdecddf242718))
131
- - Override Request Options ([#36](https://github.com/clashperk/clashofclans.js/issues/36)) ([42d7fdd](https://github.com/clashperk/clashofclans.js/commit/42d7fdd36262cc46f23b731f8cffb9daea19d3b0))
132
- - Internal Caching Options ([#53](https://github.com/clashperk/clashofclans.js/issues/53)) ([984451d](https://github.com/clashperk/clashofclans.js/commit/30ea3240c11866008d0dae514468c0fdbb34ffd0))
133
- - Additional Properties for Player Units ([#65](https://github.com/clashperk/clashofclans.js/pull/65)) ([aa1696](https://github.com/clashperk/clashofclans.js/commit/aa1696243d96d4fed0250b4282c60522a6482343))
146
+ - HTTP Request Request Retries ([#26](https://github.com/clashperk/clashofclans.js/issues/26)) ([94585f3](https://github.com/clashperk/clashofclans.js/commit/94585f3a84a7175b2d07872f9eb9e42372b95e12))
147
+ - Event Manager and Custom Events ([#37](https://github.com/clashperk/clashofclans.js/issues/37)) ([5027ae6](https://github.com/clashperk/clashofclans.js/commit/5027ae663a8e07175e17384c7e5706f4a1a7afb4))
148
+ - Email Password Login ([#31](https://github.com/clashperk/clashofclans.js/issues/31)) ([4153cd3](https://github.com/clashperk/clashofclans.js/commit/4153cd37ea0e1c71550b9e892105b84d5a407e23))
149
+ - Queue Throttler and Batch Throttler ([#34](https://github.com/clashperk/clashofclans.js/issues/34)) ([3a8f051](https://github.com/clashperk/clashofclans.js/commit/3a8f051552e93b98f89bc7d524acdecddf242718))
150
+ - Override Request Options ([#36](https://github.com/clashperk/clashofclans.js/issues/36)) ([42d7fdd](https://github.com/clashperk/clashofclans.js/commit/42d7fdd36262cc46f23b731f8cffb9daea19d3b0))
151
+ - Internal Caching Options ([#53](https://github.com/clashperk/clashofclans.js/issues/53)) ([984451d](https://github.com/clashperk/clashofclans.js/commit/30ea3240c11866008d0dae514468c0fdbb34ffd0))
152
+ - Additional Properties for Player Units ([#65](https://github.com/clashperk/clashofclans.js/pull/65)) ([aa1696](https://github.com/clashperk/clashofclans.js/commit/aa1696243d96d4fed0250b4282c60522a6482343))
package/README.md CHANGED
@@ -25,6 +25,7 @@
25
25
  ```js
26
26
  const { Client } = require('clashofclans.js');
27
27
  const client = new Client();
28
+ // const client = new Client({ keys: [], cache: true, retryLimit: 2, restRequestTimeout: 5000 });
28
29
 
29
30
  (async function () {
30
31
  await client.login({ email: 'developer@email.com', password: '***' });
@@ -34,32 +35,35 @@ const client = new Client();
34
35
  })();
35
36
  ```
36
37
 
37
- ### Custom Event
38
+ ### Custom Polling Event
39
+
40
+ > **Warning** <br />
41
+ > Events are neither real-time nor supported by the API. They are polled frequently and compared with the cached data. If there is a difference, the event is emitted.
38
42
 
39
43
  ```js
40
- const { Client, BatchThrottler } = require('clashofclans.js');
41
- const client = new Client({
44
+ const { PollingClient, BatchThrottler } = require('clashofclans.js');
45
+ const pollingClient = new PollingClient({
42
46
  cache: true,
43
47
  retryLimit: 1,
44
48
  restRequestTimeout: 5000,
45
49
  throttler: new BatchThrottler(20)
46
50
  });
47
51
 
48
- client.events.addClans(['#8QU8J9LP', '#8P2QG08P']);
49
- client.events.setClanEvent({
52
+ pollingClient.addClans(['#8QU8J9LP', '#8P2QG08P']);
53
+ pollingClient.setClanEvent({
50
54
  name: 'clanDescriptionChange',
51
55
  filter: (oldClan, newClan) => {
52
56
  return oldClan.description !== newClan.description;
53
57
  }
54
58
  });
55
59
 
56
- client.on('clanDescriptionChange', (oldClan, newClan) => {
60
+ pollingClient.on('clanDescriptionChange', (oldClan, newClan) => {
57
61
  console.log(oldClan.description, newClan.description);
58
62
  });
59
63
 
60
64
  (async function () {
61
- await client.login({ email: 'developer@email.com', password: '***' });
62
- await client.events.init();
65
+ await pollingClient.login({ email: 'developer@email.com', password: '***' });
66
+ await pollingClient.init();
63
67
  })();
64
68
  ```
65
69
 
@@ -5,6 +5,7 @@ import { CWLRounds, ClientEvents } from '../util/Constants';
5
5
  import { RESTManager } from '../rest/RESTManager';
6
6
  import { Util } from '../util/Util';
7
7
  import { Clan, ClanMember, ClanWar, ClanWarLog, League, Location, Player, WarLeague, RankedClan, RankedPlayer, Label, SeasonRankedPlayer, GoldPassSeason, ClanWarLeagueGroup } from '../struct';
8
+ import { CapitalRaidSeason } from '../struct/CapitalRaidSeason';
8
9
  interface IClientEvents {
9
10
  [ClientEvents.Error]: [error: unknown];
10
11
  [ClientEvents.Debug]: [path: string, status: string, message: string];
@@ -58,6 +59,8 @@ export declare class Client extends EventEmitter {
58
59
  getClan(clanTag: string, options?: OverrideOptions): Promise<Clan>;
59
60
  /** Get list of clan members. */
60
61
  getClanMembers(clanTag: string, options?: SearchOptions): Promise<ClanMember[]>;
62
+ /** Get capital raid seasons. */
63
+ getCapitalRaidSeasons(tag: string, options?: SearchOptions): Promise<CapitalRaidSeason[]>;
61
64
  /** Get clan war log. */
62
65
  getClanWarLog(clanTag: string, options?: SearchOptions): Promise<ClanWarLog[]>;
63
66
  /** Get info about currently running war (normal or friendly) in the clan. */
@@ -109,8 +112,10 @@ export declare class Client extends EventEmitter {
109
112
  getPlayers(playerTags: string[], options?: OverrideOptions): Promise<Player[]>;
110
113
  /** Verify Player API token that can be found from the Game settings. */
111
114
  verifyPlayerToken(playerTag: string, token: string, options?: OverrideOptions): Promise<boolean>;
112
- /** Get list of Leagues. */
115
+ /** Get a list of Leagues. */
113
116
  getLeagues(options?: SearchOptions): Promise<League[]>;
117
+ /** Get a list of Capital Leagues. */
118
+ getCapitalLeagues(options?: SearchOptions): Promise<import("../types").APICapitalLeague[]>;
114
119
  /** Get Legend League season Ids. */
115
120
  getLeagueSeasons(options?: SearchOptions): Promise<string[]>;
116
121
  /** Get Legend League season rankings by season Id. */
@@ -143,6 +148,12 @@ export declare class Client extends EventEmitter {
143
148
  * For global ranking, use `global` as `locationId`.
144
149
  */
145
150
  getVersusPlayerRanks(locationId: number | 'global', options?: SearchOptions): Promise<RankedPlayer[]>;
151
+ /**
152
+ * Get clan capital rankings for a specific location.
153
+ *
154
+ * For global ranking, use `global` as `locationId`.
155
+ */
156
+ getClanCapitalRanks(locationId: number | 'global', options?: SearchOptions): Promise<import("../types").APIClanCapitalRanking[]>;
146
157
  /** Get list of clan labels. */
147
158
  getClanLabels(options?: SearchOptions): Promise<Label[]>;
148
159
  /** Get list of player labels. */
@@ -7,6 +7,7 @@ const HTTPError_1 = require("../rest/HTTPError");
7
7
  const RESTManager_1 = require("../rest/RESTManager");
8
8
  const Util_1 = require("../util/Util");
9
9
  const struct_1 = require("../struct");
10
+ const CapitalRaidSeason_1 = require("../struct/CapitalRaidSeason");
10
11
  /**
11
12
  * Represents Clash of Clans API Client.
12
13
  * ```js
@@ -62,6 +63,11 @@ class Client extends node_events_1.EventEmitter {
62
63
  const { data } = await this.rest.getClanMembers(clanTag, options);
63
64
  return data.items.map((entry) => new struct_1.ClanMember(this, entry));
64
65
  }
66
+ /** Get capital raid seasons. */
67
+ async getCapitalRaidSeasons(tag, options) {
68
+ const { data } = await this.rest.getCapitalRaidSeasons(tag, options);
69
+ return data.items.map((entry) => new CapitalRaidSeason_1.CapitalRaidSeason(this, entry));
70
+ }
65
71
  /** Get clan war log. */
66
72
  async getClanWarLog(clanTag, options) {
67
73
  const { data } = await this.rest.getClanWarLog(clanTag, options);
@@ -69,10 +75,7 @@ class Client extends node_events_1.EventEmitter {
69
75
  }
70
76
  /** Get info about currently running war (normal or friendly) in the clan. */
71
77
  async getClanWar(clanTag, options) {
72
- const { data, maxAge, path, status } = await this.rest.getCurrentWar(clanTag, options);
73
- if (data.state === 'notInWar') {
74
- throw new HTTPError_1.HTTPError(HTTPError_1.NotInWarError, status, path, maxAge);
75
- }
78
+ const { data, maxAge } = await this.rest.getCurrentWar(clanTag, options);
76
79
  return new struct_1.ClanWar(this, data, { clanTag, maxAge });
77
80
  }
78
81
  /**
@@ -153,19 +156,13 @@ class Client extends node_events_1.EventEmitter {
153
156
  }
154
157
  /** Get info about clan war league. */
155
158
  async getClanWarLeagueGroup(clanTag, options) {
156
- const { data, status, path, maxAge } = await this.rest.getClanWarLeagueGroup(clanTag, options);
157
- if (data.state === 'notInWar') {
158
- throw new HTTPError_1.HTTPError(HTTPError_1.NotInWarError, status, path, maxAge);
159
- }
159
+ const { data } = await this.rest.getClanWarLeagueGroup(clanTag, options);
160
160
  return new struct_1.ClanWarLeagueGroup(this, data);
161
161
  }
162
162
  /** Get info about a CWL round by WarTag. */
163
163
  async getClanWarLeagueRound(warTag, options) {
164
164
  const args = typeof warTag === 'string' ? { warTag } : { warTag: warTag.warTag, clanTag: warTag.clanTag };
165
- const { data, maxAge, status, path } = await this.rest.getClanWarLeagueRound(args.warTag, options);
166
- if (data.state === 'notInWar') {
167
- throw new HTTPError_1.HTTPError(HTTPError_1.NotInWarError, status, path, maxAge);
168
- }
165
+ const { data, maxAge } = await this.rest.getClanWarLeagueRound(args.warTag, options);
169
166
  return new struct_1.ClanWar(this, data, { warTag: args.warTag, clanTag: args.clanTag, maxAge });
170
167
  }
171
168
  /** Get info about a player by tag. */
@@ -184,11 +181,16 @@ class Client extends node_events_1.EventEmitter {
184
181
  const { data } = await this.rest.verifyPlayerToken(playerTag, token, options);
185
182
  return data.status === 'ok';
186
183
  }
187
- /** Get list of Leagues. */
184
+ /** Get a list of Leagues. */
188
185
  async getLeagues(options) {
189
186
  const { data } = await this.rest.getLeagues(options);
190
187
  return data.items.map((entry) => new struct_1.League(entry));
191
188
  }
189
+ /** Get a list of Capital Leagues. */
190
+ async getCapitalLeagues(options) {
191
+ const { data } = await this.rest.getCapitalLeagues(options);
192
+ return data.items;
193
+ }
192
194
  /** Get Legend League season Ids. */
193
195
  async getLeagueSeasons(options) {
194
196
  const { data } = await this.rest.getLeagueSeasons(Constants_1.LegendLeagueId, options);
@@ -245,6 +247,15 @@ class Client extends node_events_1.EventEmitter {
245
247
  const { data } = await this.rest.getVersusPlayerRanks(locationId, options);
246
248
  return data.items.map((entry) => new struct_1.RankedPlayer(this, entry));
247
249
  }
250
+ /**
251
+ * Get clan capital rankings for a specific location.
252
+ *
253
+ * For global ranking, use `global` as `locationId`.
254
+ */
255
+ async getClanCapitalRanks(locationId, options) {
256
+ const { data } = await this.rest.getClanCapitalRanks(locationId, options);
257
+ return data.items;
258
+ }
248
259
  /** Get list of clan labels. */
249
260
  async getClanLabels(options) {
250
261
  const { data } = await this.rest.getClanLabels(options);
@@ -3,10 +3,10 @@ import { ClientOptions } from '../types';
3
3
  import { PollingEvents } from '../util/Constants';
4
4
  import { Client } from './Client';
5
5
  /**
6
- * Represents Clash of Clans Polling Event Client.
6
+ * Represents a Polling Event Client.
7
7
  * ```js
8
8
  * const { PollingClient } = require('clashofclans.js');
9
- * const client = new PollingClient({ keys: ['***'] });
9
+ * const pollingClient = new PollingClient({ keys: ['***'] });
10
10
  * ```
11
11
  */
12
12
  export declare class PollingClient extends Client {
@@ -5,10 +5,10 @@ const HTTPError_1 = require("../rest/HTTPError");
5
5
  const Constants_1 = require("../util/Constants");
6
6
  const Client_1 = require("./Client");
7
7
  /**
8
- * Represents Clash of Clans Polling Event Client.
8
+ * Represents a Polling Event Client.
9
9
  * ```js
10
10
  * const { PollingClient } = require('clashofclans.js');
11
- * const client = new PollingClient({ keys: ['***'] });
11
+ * const pollingClient = new PollingClient({ keys: ['***'] });
12
12
  * ```
13
13
  */
14
14
  class PollingClient extends Client_1.Client {
@@ -148,6 +148,8 @@ class PollingClient extends Client_1.Client {
148
148
  }
149
149
  async maintenanceHandler() {
150
150
  setTimeout(this.maintenanceHandler.bind(this), 10000).unref();
151
+ if (!(this.listenerCount(Constants_1.PollingEvents.MaintenanceStart) && this.listenerCount(Constants_1.PollingEvents.MaintenanceEnd)))
152
+ return;
151
153
  try {
152
154
  const res = await this.rest.getClans({ maxMembers: Math.floor(Math.random() * 40) + 10, limit: 1 });
153
155
  if (res.status === 200 && this.inMaintenance) {
package/dist/index.mjs CHANGED
@@ -8,8 +8,11 @@ export const BatchThrottler = mod.BatchThrottler;
8
8
  export const BuilderTroops = mod.BuilderTroops;
9
9
  export const CWLRounds = mod.CWLRounds;
10
10
  export const CacheStore = mod.CacheStore;
11
+ export const CapitalRaidSeason = mod.CapitalRaidSeason;
12
+ export const CapitalRaidSeasonMember = mod.CapitalRaidSeasonMember;
11
13
  export const ChatLanguage = mod.ChatLanguage;
12
14
  export const Clan = mod.Clan;
15
+ export const ClanCapital = mod.ClanCapital;
13
16
  export const ClanMember = mod.ClanMember;
14
17
  export const ClanWar = mod.ClanWar;
15
18
  export const ClanWarAttack = mod.ClanWarAttack;
@@ -40,7 +43,6 @@ export const Leagues = mod.Leagues;
40
43
  export const LegendLeagueId = mod.LegendLeagueId;
41
44
  export const LegendStatistics = mod.LegendStatistics;
42
45
  export const Location = mod.Location;
43
- export const NotInWarError = mod.NotInWarError;
44
46
  export const Player = mod.Player;
45
47
  export const PlayerClan = mod.PlayerClan;
46
48
  export const PollingClient = mod.PollingClient;
@@ -19,10 +19,6 @@ export declare class HTTPError extends Error {
19
19
  maxAge: number;
20
20
  constructor(error: any, status: number, path: string, maxAge: number, method?: string);
21
21
  }
22
- export declare const NotInWarError: {
23
- message: string;
24
- reason: string;
25
- };
26
22
  export declare const PrivateWarLogError: {
27
23
  message: string;
28
24
  reason: string;
@@ -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.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.',
@@ -32,10 +32,6 @@ class HTTPError extends Error {
32
32
  }
33
33
  }
34
34
  exports.HTTPError = HTTPError;
35
- exports.NotInWarError = {
36
- message: 'Clan is not in war at this moment.',
37
- reason: 'notInWar'
38
- };
39
35
  exports.PrivateWarLogError = {
40
36
  message: 'Access denied, clan war log is private.',
41
37
  reason: 'privateWarLog'
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { EventEmitter } from 'node:events';
3
3
  import { Util } from '../util/Util';
4
- import { APIClan, APIClanList, APIClanMemberList, APIClanRankingList, APIClanVersusRankingList, APIClanWar, APIClanWarLeagueGroup, APIClanWarLog, APIGoldPassSeason, APILabelList, APILeague, APILeagueList, APILeagueSeasonList, APILocation, APILocationList, APIPlayer, APIPlayerRankingList, APIPlayerSeasonRankingList, APIPlayerVersusRankingList, APIVerifyToken, APIWarLeague, APIWarLeagueList, SearchOptions, ClanSearchOptions, RESTOptions, OverrideOptions, LoginOptions } from '../types';
4
+ import { APIClan, APIClanList, APIClanMemberList, APICapitalRaidSeasons, APIClanRankingList, APIClanVersusRankingList, APIClanWar, APIClanWarLeagueGroup, APIClanWarLog, APIGoldPassSeason, APILabelList, APILeague, APILeagueList, APILeagueSeasonList, APILocation, APILocationList, APIPlayer, APIPlayerRankingList, APIPlayerSeasonRankingList, APIPlayerVersusRankingList, APIVerifyToken, APIWarLeague, APIWarLeagueList, SearchOptions, ClanSearchOptions, RESTOptions, OverrideOptions, LoginOptions, APICapitalLeagueList, APICapitalLeague, APIClanCapitalRankingList } from '../types';
5
5
  import { RestEvents } from '../util/Constants';
6
6
  import { RequestHandler } from './RequestHandler';
7
7
  export interface IRestEvents {
@@ -66,14 +66,20 @@ export declare class RESTManager extends EventEmitter {
66
66
  getClanWarLeagueGroup(clanTag: string, options?: OverrideOptions): Promise<import("../types").Response<APIClanWarLeagueGroup>>;
67
67
  /** Get info about a CWL round by WarTag. */
68
68
  getClanWarLeagueRound(warTag: string, options?: OverrideOptions): Promise<import("../types").Response<APIClanWar>>;
69
+ /** Retrieve clan's capital raid seasons. */
70
+ getCapitalRaidSeasons(tag: string, options?: OverrideOptions): Promise<import("../types").Response<APICapitalRaidSeasons>>;
69
71
  /** Get info about a player by tag. */
70
72
  getPlayer(playerTag: string, options?: OverrideOptions): Promise<import("../types").Response<APIPlayer>>;
71
73
  /** Verify Player API token that can be found from the Game settings. */
72
74
  verifyPlayerToken(playerTag: string, token: string, options?: OverrideOptions): Promise<import("../types").Response<APIVerifyToken>>;
73
- /** Get list of Leagues. */
75
+ /** Get a list of Leagues. */
74
76
  getLeagues(options?: SearchOptions): Promise<import("../types").Response<APILeagueList>>;
75
77
  /** Get a League info. */
76
78
  getLeague(leagueId: string | number, options?: OverrideOptions): Promise<import("../types").Response<APILeague>>;
79
+ /** Get a list of Capital leagues. */
80
+ getCapitalLeagues(options?: SearchOptions): Promise<import("../types").Response<APICapitalLeagueList>>;
81
+ /** Get a Capital League info. */
82
+ getCapitalLeague(leagueId: string | number, options?: OverrideOptions): Promise<import("../types").Response<APICapitalLeague>>;
77
83
  /** Get Legend League season Ids. */
78
84
  getLeagueSeasons(leagueId: number, options?: SearchOptions): Promise<import("../types").Response<APILeagueSeasonList>>;
79
85
  /** Get Legend League season rankings by season Id. */
@@ -94,6 +100,8 @@ export declare class RESTManager extends EventEmitter {
94
100
  getVersusClanRanks(locationId: number | string, options?: SearchOptions): Promise<import("../types").Response<APIClanVersusRankingList>>;
95
101
  /** Get player versus rankings for a specific location. */
96
102
  getVersusPlayerRanks(locationId: number | string, options?: SearchOptions): Promise<import("../types").Response<APIPlayerVersusRankingList>>;
103
+ /** Get clan capital rankings for a specific location. */
104
+ getClanCapitalRanks(locationId: number | string, options?: SearchOptions): Promise<import("../types").Response<APIClanCapitalRankingList>>;
97
105
  /** Get list of clan labels. */
98
106
  getClanLabels(options?: SearchOptions): Promise<import("../types").Response<APILabelList>>;
99
107
  /** Get list of player labels. */
@@ -64,6 +64,11 @@ class RESTManager extends node_events_1.EventEmitter {
64
64
  getClanWarLeagueRound(warTag, options) {
65
65
  return this.requestHandler.request(`/clanwarleagues/wars/${Util_1.Util.encodeURI(warTag)}`, options);
66
66
  }
67
+ /** Retrieve clan's capital raid seasons. */
68
+ getCapitalRaidSeasons(tag, options) {
69
+ const query = Util_1.Util.queryString(options);
70
+ return this.requestHandler.request(`/clans/${Util_1.Util.encodeURI(tag)}/capitalraidseasons${query}`, options);
71
+ }
67
72
  /** Get info about a player by tag. */
68
73
  getPlayer(playerTag, options) {
69
74
  return this.requestHandler.request(`/players/${Util_1.Util.encodeURI(playerTag)}`, options);
@@ -73,7 +78,7 @@ class RESTManager extends node_events_1.EventEmitter {
73
78
  const opts = { method: 'POST', body: JSON.stringify({ token }), ...options };
74
79
  return this.requestHandler.request(`/players/${Util_1.Util.encodeURI(playerTag)}/verifytoken`, opts);
75
80
  }
76
- /** Get list of Leagues. */
81
+ /** Get a list of Leagues. */
77
82
  getLeagues(options) {
78
83
  const query = Util_1.Util.queryString(options);
79
84
  return this.requestHandler.request(`/leagues${query}`, options);
@@ -82,6 +87,15 @@ class RESTManager extends node_events_1.EventEmitter {
82
87
  getLeague(leagueId, options) {
83
88
  return this.requestHandler.request(`/leagues/${leagueId}`, options);
84
89
  }
90
+ /** Get a list of Capital leagues. */
91
+ getCapitalLeagues(options) {
92
+ const query = Util_1.Util.queryString(options);
93
+ return this.requestHandler.request(`/capitalleagues${query}`, options);
94
+ }
95
+ /** Get a Capital League info. */
96
+ getCapitalLeague(leagueId, options) {
97
+ return this.requestHandler.request(`/capitalleagues/${leagueId}`, options);
98
+ }
85
99
  /** Get Legend League season Ids. */
86
100
  getLeagueSeasons(leagueId, options) {
87
101
  const query = Util_1.Util.queryString(options);
@@ -130,6 +144,11 @@ class RESTManager extends node_events_1.EventEmitter {
130
144
  const query = Util_1.Util.queryString(options);
131
145
  return this.requestHandler.request(`/locations/${locationId}/rankings/players-versus${query}`, options);
132
146
  }
147
+ /** Get clan capital rankings for a specific location. */
148
+ getClanCapitalRanks(locationId, options) {
149
+ const query = Util_1.Util.queryString(options);
150
+ return this.requestHandler.request(`/locations/${locationId}/rankings/capitals${query}`, options);
151
+ }
133
152
  /** Get list of clan labels. */
134
153
  getClanLabels(options) {
135
154
  const query = Util_1.Util.queryString(options);
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
26
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
27
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
@@ -18,7 +41,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
18
41
  exports.RequestHandler = void 0;
19
42
  const node_https_1 = __importDefault(require("node:https"));
20
43
  const node_events_1 = require("node:events");
21
- const node_fetch_1 = __importDefault(require("node-fetch"));
44
+ const node_fetch_1 = __importStar(require("node-fetch"));
22
45
  const Constants_1 = require("../util/Constants");
23
46
  const Store_1 = require("../util/Store");
24
47
  const HTTPError_1 = require("./HTTPError");
@@ -66,39 +89,46 @@ class RequestHandler extends node_events_1.EventEmitter {
66
89
  return this.exec(path, options);
67
90
  }
68
91
  async exec(path, options = {}, retries = 0) {
69
- const res = await (0, node_fetch_1.default)(`${this.baseURL}${path}`, {
70
- agent,
71
- body: options.body,
72
- method: options.method,
73
- timeout: options.restRequestTimeout ?? this.restRequestTimeout,
74
- headers: { 'Authorization': `Bearer ${this._key}`, 'Content-Type': 'application/json' }
75
- }).catch(() => null);
76
- const data = await res?.json().catch(() => null);
77
- if (!res && retries < (options.retryLimit ?? this.retryLimit))
78
- return this.exec(path, options, ++retries);
79
- if (this.creds &&
80
- res?.status === 403 &&
81
- data?.reason === 'accessDenied.invalidIp' &&
82
- retries < (options.retryLimit ?? this.retryLimit)) {
83
- const keys = await this.reValidateKeys().then(() => () => this.login());
84
- if (keys.length)
85
- return this.exec(path, options, ++retries);
86
- }
87
- const maxAge = Number(res?.headers.get('cache-control')?.split('=')?.[1] ?? 0) * 1000;
88
- if (res?.status === 403 && !data?.message && this.rejectIfNotValid) {
89
- throw new HTTPError_1.HTTPError(HTTPError_1.PrivateWarLogError, res.status, path, maxAge);
90
- }
91
- if (!res?.ok && this.rejectIfNotValid) {
92
- throw new HTTPError_1.HTTPError(data, res?.status ?? 504, path, maxAge, options.method);
93
- }
94
- if (res?.status === 429) {
95
- this.emit(Constants_1.RestEvents.RateLimited, path, res.status, options.method);
92
+ try {
93
+ const res = await (0, node_fetch_1.default)(`${this.baseURL}${path}`, {
94
+ agent,
95
+ body: options.body,
96
+ method: options.method,
97
+ timeout: options.restRequestTimeout ?? this.restRequestTimeout,
98
+ headers: { 'Authorization': `Bearer ${this._key}`, 'Content-Type': 'application/json' }
99
+ });
100
+ if (res.status === 504 && retries < (options.retryLimit ?? this.retryLimit)) {
101
+ return await this.exec(path, options, ++retries);
102
+ }
103
+ const data = await res.json();
104
+ if (this.creds &&
105
+ res.status === 403 &&
106
+ data.reason === 'accessDenied.invalidIp' &&
107
+ retries < (options.retryLimit ?? this.retryLimit)) {
108
+ const keys = await this.reValidateKeys().then(() => () => this.login());
109
+ if (keys.length)
110
+ return await this.exec(path, options, ++retries);
111
+ }
112
+ const maxAge = Number(res.headers.get('cache-control')?.split('=')?.[1] ?? 0) * 1000;
113
+ if (res.status === 403 && !data?.message && this.rejectIfNotValid) {
114
+ throw new HTTPError_1.HTTPError(HTTPError_1.PrivateWarLogError, res.status, path, maxAge);
115
+ }
116
+ if (!res.ok && this.rejectIfNotValid) {
117
+ throw new HTTPError_1.HTTPError(data, res.status, path, maxAge, options.method);
118
+ }
119
+ if (this.cached && maxAge > 0 && options.cache !== false && res.ok) {
120
+ await this.cached.set(path, { data, ttl: Date.now() + maxAge, status: res.status }, maxAge);
121
+ }
122
+ return { data, maxAge, status: res.status, path, ok: res.status === 200 };
96
123
  }
97
- this.emit(Constants_1.RestEvents.Debug, path, res?.status ?? 504, options.method);
98
- if (this.cached && maxAge > 0 && options.cache !== false && res?.ok) {
99
- await this.cached.set(path, { data, ttl: Date.now() + maxAge, status: res.status }, maxAge);
124
+ catch (error) {
125
+ if (error instanceof node_fetch_1.FetchError && error.type === 'request-timeout' && retries < (options.retryLimit ?? this.retryLimit)) {
126
+ return this.exec(path, options, ++retries);
127
+ }
128
+ if (this.rejectIfNotValid)
129
+ throw error;
130
+ return { data: { message: error.message }, maxAge: 0, status: 500, path, ok: false };
100
131
  }
101
- return { data, maxAge, status: res?.status ?? 504, path, ok: res?.status === 200 };
102
132
  }
103
133
  async init(options) {
104
134
  if (!(options.email && options.password))
@@ -0,0 +1,49 @@
1
+ import { Client } from '../client/Client';
2
+ import { APICapitalRaidSeason, APICapitalRaidSeasonAttackLog, APICapitalRaidSeasonDefenseLog, APICapitalRaidSeasonMember, OverrideOptions } from '../types';
3
+ import { Player } from './Player';
4
+ export declare class CapitalRaidSeasonMember {
5
+ /** The player's tag. */
6
+ name: string;
7
+ /** The player's name. */
8
+ tag: string;
9
+ /** The number of attacks the player has made. */
10
+ attacks: number;
11
+ /** The number of attacks the player can make. */
12
+ attackLimit: number;
13
+ /** The number of bonus attacks the player can make. */
14
+ bonusAttackLimit: number;
15
+ /** The number of capital resources the player has looted. */
16
+ capitalResourcesLooted: number;
17
+ constructor(data: APICapitalRaidSeasonMember);
18
+ }
19
+ /** Represents a Capital Raid Season. */
20
+ export declare class CapitalRaidSeason {
21
+ private readonly client;
22
+ /** The state of the raid season. */
23
+ state: 'ongoing' | 'ended';
24
+ /** The start time of the raid season. */
25
+ startTime: Date;
26
+ /** The end time of the raid season. */
27
+ endTime: Date;
28
+ /** The total loot collected from the capital. */
29
+ capitalTotalLoot: number;
30
+ /** The number of raids completed. */
31
+ raidsCompleted: number;
32
+ /** The total number of attacks. */
33
+ totalAttacks: number;
34
+ /** The number of enemy districts destroyed. */
35
+ enemyDistrictsDestroyed: number;
36
+ /** The offensive reward. */
37
+ offensiveReward: number;
38
+ /** The defensive reward. */
39
+ defensiveReward: number;
40
+ /** The members of the raid season. */
41
+ members: APICapitalRaidSeasonMember[];
42
+ /** The attack log of the raid season. */
43
+ attackLog: APICapitalRaidSeasonAttackLog[];
44
+ /** The defense log of the raid season. */
45
+ defenseLog: APICapitalRaidSeasonDefenseLog[];
46
+ constructor(client: Client, data: APICapitalRaidSeason);
47
+ /** Get {@link Player} info for every Player in the clan. */
48
+ fetchMembers(options?: OverrideOptions): Promise<Player[]>;
49
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CapitalRaidSeason = exports.CapitalRaidSeasonMember = void 0;
4
+ const Util_1 = require("../util/Util");
5
+ class CapitalRaidSeasonMember {
6
+ constructor(data) {
7
+ this.tag = data.tag;
8
+ this.name = data.name;
9
+ this.attacks = data.attacks;
10
+ this.attackLimit = data.attackLimit;
11
+ this.bonusAttackLimit = data.bonusAttackLimit;
12
+ this.capitalResourcesLooted = data.capitalResourcesLooted;
13
+ }
14
+ }
15
+ exports.CapitalRaidSeasonMember = CapitalRaidSeasonMember;
16
+ /** Represents a Capital Raid Season. */
17
+ class CapitalRaidSeason {
18
+ constructor(client, data) {
19
+ this.client = client;
20
+ this.state = data.state;
21
+ this.startTime = Util_1.Util.formatDate(data.startTime);
22
+ this.endTime = Util_1.Util.formatDate(data.endTime);
23
+ this.capitalTotalLoot = data.capitalTotalLoot;
24
+ this.raidsCompleted = data.raidsCompleted;
25
+ this.totalAttacks = data.totalAttacks;
26
+ this.enemyDistrictsDestroyed = data.enemyDistrictsDestroyed;
27
+ this.offensiveReward = data.offensiveReward;
28
+ this.defensiveReward = data.defensiveReward;
29
+ this.attackLog = data.attackLog;
30
+ this.defenseLog = data.defenseLog;
31
+ this.members = (data.members ?? []).map((member) => new CapitalRaidSeasonMember(member));
32
+ }
33
+ /** Get {@link Player} info for every Player in the clan. */
34
+ async fetchMembers(options) {
35
+ return (await Promise.allSettled(this.members.map((m) => this.client.getPlayer(m.tag, { ...options, ignoreRateLimit: true }))))
36
+ .filter((res) => res.status === 'fulfilled')
37
+ .map((res) => res.value);
38
+ }
39
+ }
40
+ exports.CapitalRaidSeason = CapitalRaidSeason;
@@ -1,4 +1,4 @@
1
- import { APIClan, OverrideOptions } from '../types';
1
+ import { APICapitalLeague, APIClan, OverrideOptions } from '../types';
2
2
  import { Client } from '../client/Client';
3
3
  import { ChatLanguage } from './ChatLanguage';
4
4
  import { ClanMember } from './ClanMember';
@@ -29,6 +29,8 @@ export declare class Clan {
29
29
  level: number;
30
30
  /** The clan's trophy count. */
31
31
  points: number;
32
+ /** The clan's capital points. */
33
+ capitalPoints: number;
32
34
  /** The clan's versus trophy count. */
33
35
  versusPoints: number;
34
36
  /** The minimum trophies required to apply to this clan. */
@@ -57,6 +59,10 @@ export declare class Clan {
57
59
  labels: Label[];
58
60
  /** The clan's Clan Capital information */
59
61
  clanCapital: ClanCapital | null;
62
+ /** The clan's capital league. */
63
+ capitalLeague?: APICapitalLeague;
64
+ /** Whether the clan is family friendly. */
65
+ isFamilyFriendly: boolean;
60
66
  /**
61
67
  * List of clan members.
62
68
  * - This property returns empty array for {@link Client.getClans} method.
@@ -35,6 +35,9 @@ class Clan {
35
35
  this.memberCount = data.members;
36
36
  this.labels = data.labels.map((label) => new Label_1.Label(label));
37
37
  this.clanCapital = Object.keys(data.clanCapital).length > 0 ? new ClanCapital_1.ClanCapital(data.clanCapital) : null;
38
+ this.isFamilyFriendly = data.isFamilyFriendly;
39
+ this.capitalPoints = data.clanCapitalPoints;
40
+ this.capitalLeague = data.capitalLeague;
38
41
  this.members = data.memberList?.map((mem) => new ClanMember_1.ClanMember(this.client, mem)) ?? []; // eslint-disable-line
39
42
  }
40
43
  /** Get {@link Player} info for every Player in the clan. */
@@ -4,7 +4,7 @@ exports.ClanCapital = void 0;
4
4
  class ClanCapital {
5
5
  constructor(data) {
6
6
  this.capitalHallLevel = data.capitalHallLevel ?? null;
7
- this.districts = data.districts ? data.districts : null;
7
+ this.districts = data.districts ?? null;
8
8
  }
9
9
  }
10
10
  exports.ClanCapital = ClanCapital;
@@ -1,4 +1,4 @@
1
- import { APIClanMember, OverrideOptions } from '../types';
1
+ import { APIClanMember, APIPlayerHouse, OverrideOptions } from '../types';
2
2
  import { Client } from '../client/Client';
3
3
  import { League } from './League';
4
4
  export declare class ClanMember {
@@ -25,6 +25,8 @@ export declare class ClanMember {
25
25
  donations: number;
26
26
  /** The member's donation received count for this season. */
27
27
  received: number;
28
+ /** The member's player house details. */
29
+ playerHouse?: APIPlayerHouse | null;
28
30
  constructor(client: Client, data: APIClanMember);
29
31
  /** Whether this clan member is in the clan. */
30
32
  get isMember(): boolean;
@@ -18,6 +18,7 @@ class ClanMember {
18
18
  this.clanRank = data.clanRank;
19
19
  this.previousClanRank = data.previousClanRank;
20
20
  this.donations = data.donations;
21
+ this.playerHouse = data.playerHouse ?? null;
21
22
  this.received = data.donationsReceived;
22
23
  }
23
24
  /** Whether this clan member is in the clan. */
@@ -101,11 +101,21 @@ export declare class WarClan {
101
101
  /** Get clan's formatted link to open clan in-game. */
102
102
  get shareLink(): string;
103
103
  }
104
- /** Represents a Clan War in Clash of Clans. */
104
+ /**
105
+ * Represents a Clan War in Clash of Clans.
106
+ *
107
+ * :::caution
108
+ * It's recommended to see if ClanWar#state is `notInWar` available before performing operations or reading data from it. You can check this with data.ok property.
109
+ * :::
110
+ */
105
111
  export declare class ClanWar {
106
112
  client: Client;
107
- /** The clan's current war state. */
108
- state: 'preparation' | 'inWar' | 'warEnded';
113
+ /**
114
+ * The clan's current war state.
115
+ *
116
+ * :warning: Other properties won't be available if the state is `notInWar`.
117
+ */
118
+ state: 'preparation' | 'inWar' | 'warEnded' | 'notInWar';
109
119
  /** The number of players on each side. */
110
120
  teamSize: number;
111
121
  /** The number of attacks each member has. */
@@ -135,6 +145,8 @@ export declare class ClanWar {
135
145
  getAttack(attackerTag: string, defenderTag: string): ClanWarAttack | null;
136
146
  /** Return a list of {@link ClanWarAttack} for the defenderTag provided. */
137
147
  getDefenses(defenderTag: string): ClanWarAttack[];
148
+ /** Whether the clan is not in war. */
149
+ get isNotInWar(): boolean;
138
150
  /** Whether this is a Battle Day. */
139
151
  get isBattleDay(): boolean;
140
152
  /** Whether this is a Preparation Day. */
@@ -137,26 +137,33 @@ class WarClan {
137
137
  }
138
138
  }
139
139
  exports.WarClan = WarClan;
140
- /** Represents a Clan War in Clash of Clans. */
140
+ /**
141
+ * Represents a Clan War in Clash of Clans.
142
+ *
143
+ * :::caution
144
+ * It's recommended to see if ClanWar#state is `notInWar` available before performing operations or reading data from it. You can check this with data.ok property.
145
+ * :::
146
+ */
141
147
  class ClanWar {
142
148
  constructor(client, data, extra) {
143
149
  Object.defineProperty(this, 'client', { value: client });
144
- // @ts-expect-error
145
150
  this.state = data.state;
146
- this.teamSize = data.teamSize;
147
- this.attacksPerMember = data.attacksPerMember ?? (extra.warTag ? 1 : 2);
148
- this.preparationStartTime = client.util.formatDate(data.preparationStartTime);
149
- this.startTime = client.util.formatDate(data.startTime);
150
- this.endTime = client.util.formatDate(data.endTime);
151
- this.warTag = extra.warTag ?? null;
152
- let [clan, opponent] = [data.clan, data.opponent];
153
- const clanTag = extra.clanTag && client.util.formatTag(extra.clanTag);
154
- if (clanTag && [data.clan.tag, data.opponent.tag].includes(clanTag)) {
155
- clan = data.clan.tag === clanTag ? data.clan : data.opponent;
156
- opponent = data.clan.tag === clan.tag ? data.opponent : data.clan;
151
+ if (this.state !== 'notInWar') {
152
+ this.teamSize = data.teamSize;
153
+ this.attacksPerMember = data.attacksPerMember ?? (extra.warTag ? 1 : 2);
154
+ this.preparationStartTime = client.util.formatDate(data.preparationStartTime);
155
+ this.startTime = client.util.formatDate(data.startTime);
156
+ this.endTime = client.util.formatDate(data.endTime);
157
+ this.warTag = extra.warTag ?? null;
158
+ let [clan, opponent] = [data.clan, data.opponent];
159
+ const clanTag = extra.clanTag && client.util.formatTag(extra.clanTag);
160
+ if (clanTag && [data.clan.tag, data.opponent.tag].includes(clanTag)) {
161
+ clan = data.clan.tag === clanTag ? data.clan : data.opponent;
162
+ opponent = data.clan.tag === clan.tag ? data.opponent : data.clan;
163
+ }
164
+ this.clan = new WarClan(this, clan);
165
+ this.opponent = new WarClan(this, opponent);
157
166
  }
158
- this.clan = new WarClan(this, clan);
159
- this.opponent = new WarClan(this, opponent);
160
167
  this.maxAge = extra.maxAge;
161
168
  }
162
169
  /** Return a {@link ClanWarMember} with the tag provided. */
@@ -178,6 +185,10 @@ class ClanWar {
178
185
  }
179
186
  return this.opponent.attacks.filter((atk) => atk.defenderTag === defenderTag);
180
187
  }
188
+ /** Whether the clan is not in war. */
189
+ get isNotInWar() {
190
+ return this.state === 'notInWar';
191
+ }
181
192
  /** Whether this is a Battle Day. */
182
193
  get isBattleDay() {
183
194
  return this.state === 'inWar';
@@ -1,4 +1,4 @@
1
- import { APIPlayer, OverrideOptions } from '../types';
1
+ import { APIPlayer, APIPlayerHouse, OverrideOptions } from '../types';
2
2
  import { Client } from '../client/Client';
3
3
  import { LegendStatistics } from './LegendStatistics';
4
4
  import { Achievement } from './Achievement';
@@ -63,6 +63,8 @@ export declare class Player {
63
63
  spells: Spell[];
64
64
  /** An array of player's heroes (both home base and build base). */
65
65
  heroes: Hero[];
66
+ /** The player's clan capital house details. */
67
+ playerHouse?: APIPlayerHouse | null;
66
68
  constructor(client: Client, data: APIPlayer);
67
69
  /** Whether this clan member is in the clan. */
68
70
  get inClan(): boolean;
@@ -40,6 +40,7 @@ class Player {
40
40
  this.troops = data.troops.map((unit) => new Unit_1.Troop(data, unit));
41
41
  this.spells = data.spells.map((unit) => new Unit_1.Spell(data, unit));
42
42
  this.heroes = data.heroes.map((unit) => new Unit_1.Hero(data, unit));
43
+ this.playerHouse = data.playerHouse ?? null;
43
44
  }
44
45
  /** Whether this clan member is in the clan. */
45
46
  get inClan() {
@@ -17,3 +17,5 @@ export * from './Ranking';
17
17
  export * from './Season';
18
18
  export * from './Unit';
19
19
  export * from './WarLeague';
20
+ export * from './ClanCapital';
21
+ export * from './CapitalRaidSeason';
@@ -33,3 +33,5 @@ __exportStar(require("./Ranking"), exports);
33
33
  __exportStar(require("./Season"), exports);
34
34
  __exportStar(require("./Unit"), exports);
35
35
  __exportStar(require("./WarLeague"), exports);
36
+ __exportStar(require("./ClanCapital"), exports);
37
+ __exportStar(require("./CapitalRaidSeason"), exports);
@@ -58,6 +58,9 @@ export interface APIClan {
58
58
  labels: APILabel[];
59
59
  memberList: APIClanMember[];
60
60
  clanCapital: APIClanCapital;
61
+ isFamilyFriendly: boolean;
62
+ clanCapitalPoints: number;
63
+ capitalLeague?: APICapitalLeague;
61
64
  }
62
65
  export interface APIClanMember {
63
66
  name: string;
@@ -71,6 +74,13 @@ export interface APIClanMember {
71
74
  previousClanRank: number;
72
75
  donations: number;
73
76
  donationsReceived: number;
77
+ playerHouse?: APIPlayerHouse;
78
+ }
79
+ export interface APIPlayerHouse {
80
+ elements: {
81
+ type: string;
82
+ id: number;
83
+ }[];
74
84
  }
75
85
  export interface APIClanCapital {
76
86
  capitalHallLevel?: number;
@@ -169,6 +179,64 @@ export interface APIClanWarLeagueClanMember {
169
179
  export interface APIClanWarLeagueRound {
170
180
  warTags: string[];
171
181
  }
182
+ export interface APICapitalRaidSeason {
183
+ state: 'ongoing' | 'ended';
184
+ startTime: string;
185
+ endTime: string;
186
+ capitalTotalLoot: number;
187
+ raidsCompleted: number;
188
+ totalAttacks: number;
189
+ enemyDistrictsDestroyed: number;
190
+ offensiveReward: number;
191
+ defensiveReward: number;
192
+ members?: APICapitalRaidSeasonMember[];
193
+ attackLog: APICapitalRaidSeasonAttackLog[];
194
+ defenseLog: APICapitalRaidSeasonDefenseLog[];
195
+ }
196
+ export interface APICapitalRaidSeasonMember {
197
+ tag: string;
198
+ name: string;
199
+ attacks: number;
200
+ attackLimit: number;
201
+ bonusAttackLimit: number;
202
+ capitalResourcesLooted: number;
203
+ }
204
+ export interface APICapitalRaidSeasonClan {
205
+ tag: string;
206
+ name: string;
207
+ level: number;
208
+ badgeUrls: {
209
+ small: string;
210
+ large: string;
211
+ medium: string;
212
+ };
213
+ }
214
+ export interface APICapitalRaidSeasonDistrict {
215
+ id: number;
216
+ name: string;
217
+ districtHallLevel: number;
218
+ destructionPercent: number;
219
+ attackCount: number;
220
+ totalLooted: number;
221
+ }
222
+ export interface APICapitalRaidSeasonAttackLog {
223
+ defender: APICapitalRaidSeasonClan;
224
+ attackCount: number;
225
+ districtCount: number;
226
+ districtsDestroyed: number;
227
+ districts: APICapitalRaidSeasonDistrict[];
228
+ }
229
+ export interface APICapitalRaidSeasonDefenseLog {
230
+ attacker: APICapitalRaidSeasonClan;
231
+ attackCount: number;
232
+ districtCount: number;
233
+ districtsDestroyed: number;
234
+ districts: APICapitalRaidSeasonDistrict[];
235
+ }
236
+ export interface APICapitalRaidSeasons {
237
+ items: APICapitalRaidSeason[];
238
+ paging: APIPaging;
239
+ }
172
240
  /** /players/{playerTag} */
173
241
  export interface APIPlayer {
174
242
  name: string;
@@ -199,6 +267,7 @@ export interface APIPlayer {
199
267
  heroes: APIPlayerItem[];
200
268
  spells: APIPlayerItem[];
201
269
  labels: APILabel[];
270
+ playerHouse?: APIPlayerHouse;
202
271
  }
203
272
  export interface APILegendStatistics {
204
273
  previousSeason?: APISeason;
@@ -313,6 +382,22 @@ export interface APIPlayerVersusRanking {
313
382
  previousRank: number;
314
383
  clan?: APIPlayerClan;
315
384
  }
385
+ export interface APIClanCapitalRanking {
386
+ clanLevel: number;
387
+ clanPoints: number;
388
+ location: APILocation;
389
+ members: number;
390
+ tag: string;
391
+ name: string;
392
+ rank: number;
393
+ previousRank: number;
394
+ badgeUrls: APIBadge;
395
+ clanCapitalPoints: number;
396
+ }
397
+ export interface APIClanCapitalRankingList {
398
+ items: APIClanCapitalRanking[];
399
+ paging: APIPaging;
400
+ }
316
401
  /** /leagues */
317
402
  export interface APILeagueList {
318
403
  items: APILeague[];
@@ -346,6 +431,14 @@ export interface APIWarLeague {
346
431
  id: number;
347
432
  name: string;
348
433
  }
434
+ export interface APICapitalLeague {
435
+ id: number;
436
+ name: string;
437
+ }
438
+ export interface APICapitalLeagueList {
439
+ items: APICapitalLeague[];
440
+ paging: APIPaging;
441
+ }
349
442
  export interface APILabel {
350
443
  id: number;
351
444
  name: string;
@@ -22,11 +22,20 @@ exports.ElixirTroops = [
22
22
  'Miner',
23
23
  'Electro Dragon',
24
24
  'Yeti',
25
- 'Dragon Rider'
25
+ 'Dragon Rider',
26
+ 'Electro Titan'
26
27
  ];
27
28
  exports.DarkElixirTroops = ['Minion', 'Hog Rider', 'Valkyrie', 'Golem', 'Witch', 'Lava Hound', 'Bowler', 'Ice Golem', 'Headhunter'];
28
29
  exports.HomeTroops = [...exports.ElixirTroops, ...exports.DarkElixirTroops];
29
- exports.SiegeMachines = ['Wall Wrecker', 'Battle Blimp', 'Stone Slammer', 'Siege Barracks', 'Log Launcher', 'Flame Flinger'];
30
+ exports.SiegeMachines = [
31
+ 'Wall Wrecker',
32
+ 'Battle Blimp',
33
+ 'Stone Slammer',
34
+ 'Siege Barracks',
35
+ 'Log Launcher',
36
+ 'Flame Flinger',
37
+ 'Battle Drill'
38
+ ];
30
39
  exports.SuperTroops = [
31
40
  'Super Barbarian',
32
41
  'Super Archer',
@@ -50,7 +59,8 @@ exports.ElixirSpells = [
50
59
  'Jump Spell',
51
60
  'Freeze Spell',
52
61
  'Clone Spell',
53
- 'Invisibility Spell'
62
+ 'Invisibility Spell',
63
+ 'Recall Spell'
54
64
  ];
55
65
  exports.DarkElixirSpells = ['Poison Spell', 'Earthquake Spell', 'Haste Spell', 'Skeleton Spell', 'Bat Spell'];
56
66
  exports.Spells = [...exports.ElixirSpells, ...exports.DarkElixirSpells];
@@ -68,7 +78,7 @@ exports.BuilderTroops = [
68
78
  'Hog Glider'
69
79
  ];
70
80
  exports.Heroes = ['Barbarian King', 'Archer Queen', 'Grand Warden', 'Royal Champion', 'Battle Machine'];
71
- exports.HeroPets = ['L.A.S.S.I', 'Electro Owl', 'Mighty Yak', 'Unicorn'];
81
+ exports.HeroPets = ['L.A.S.S.I', 'Electro Owl', 'Mighty Yak', 'Unicorn', 'Poison Lizard', 'Diggy', 'Frosty', 'Phoenix'];
72
82
  exports.UnrankedLeagueData = {
73
83
  id: 29000000,
74
84
  name: 'Unranked',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clashofclans.js",
3
- "version": "3.0.0-dev.ec60c82",
3
+ "version": "3.0.0",
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",