clashofclans.js 2.0.0-dev.ba3ae68 → 2.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.
@@ -11,18 +11,14 @@ export declare class RequestHandler {
11
11
  private keys;
12
12
  private readonly baseURL;
13
13
  private readonly retryLimit;
14
- private readonly cached;
15
14
  private readonly restRequestTimeout;
16
15
  private readonly throttler?;
16
+ private readonly cached;
17
17
  constructor(options?: ClientOptions);
18
18
  private get _keys();
19
19
  private get _key();
20
20
  setKeys(keys: string[]): this;
21
- request<T>(path: string, options?: RequestOptions): Promise<{
22
- data: T;
23
- maxAge: number;
24
- status: number;
25
- }>;
21
+ request<T>(path: string, options?: RequestOptions): Promise<Response<T>>;
26
22
  private exec;
27
23
  init(options: InitOptions): Promise<string[]>;
28
24
  private reValidateKeys;
@@ -32,47 +28,135 @@ export declare class RequestHandler {
32
28
  private createKey;
33
29
  private getIp;
34
30
  }
31
+ /** Options for a client. */
35
32
  export interface ClientOptions {
33
+ /** Keys from Clash of Clans API developer site. */
36
34
  keys?: string[];
35
+ /** Base URL of the Clash of Clans API. */
37
36
  baseURL?: string;
37
+ /**
38
+ * How many times to retry on 5XX errors.
39
+ */
38
40
  retryLimit?: number;
41
+ /**
42
+ * Whether enable or disable internal caching.
43
+ * @example
44
+ * ```ts
45
+ * const client = new Client({ cache: true });
46
+ * ```
47
+ */
39
48
  cache?: boolean | Keyv;
49
+ /** Time to wait before cancelling a REST request, in milliseconds. */
40
50
  restRequestTimeout?: number;
51
+ /**
52
+ * Throttler class which handles rate-limit
53
+ * @example
54
+ * ```ts
55
+ * const client = new Client({ throttler: new QueueThrottler(1000 / 10) });
56
+ * ```
57
+ * @example
58
+ * ```ts
59
+ * const client = new Client({ throttler: new BatchThrottler(30) });
60
+ * ```
61
+ */
41
62
  throttler?: QueueThrottler | BatchThrottler;
42
63
  }
64
+ /** Search options for request. */
43
65
  export interface SearchOptions extends OverrideOptions {
66
+ /** Limit the number of items returned in the response. */
44
67
  limit?: number;
68
+ /**
69
+ * Return only items that occur after this marker.
70
+ * Before marker can be found from the response, inside the 'paging' property.
71
+ * Note that only after or before can be specified for a request, not both.
72
+ */
45
73
  after?: string;
74
+ /**
75
+ * Return only items that occur before this marker.
76
+ * Before marker can be found from the response, inside the 'paging' property.
77
+ * Note that only after or before can be specified for a request, not both.
78
+ */
46
79
  before?: string;
47
80
  }
81
+ /** Override options for a request. */
48
82
  export interface OverrideOptions {
83
+ /** Whether to cache this response. */
49
84
  cache?: boolean;
85
+ /** Whether to skip the cache check and request the API. */
50
86
  force?: boolean;
87
+ /** How many times to retry on 5XX errors. */
51
88
  retryLimit?: string;
89
+ /** Whether to ignore throttlers. */
52
90
  ignoreRateLimit?: boolean;
91
+ /** Time to wait before cancelling a REST request, in milliseconds. */
53
92
  restRequestTimeout?: number;
54
93
  }
55
94
  export interface RequestOptions extends OverrideOptions {
95
+ /** The request body. */
56
96
  body?: string;
97
+ /** The request method. */
57
98
  method?: string;
58
99
  }
100
+ export interface Response<T> {
101
+ /** The response body. */
102
+ data: T;
103
+ /** Path of the request for this response. */
104
+ path: string;
105
+ /** HTTP status code of this response. */
106
+ status: number;
107
+ /** The maxAge of this response. */
108
+ maxAge: number;
109
+ }
110
+ /**
111
+ * Clan search options for a request.
112
+ *
113
+ * ::info
114
+ * If name is used as part of search query, it needs to be at least three characters long.
115
+ * Name search parameter is interpreted as wild card search, so it may appear anywhere in the clan name.
116
+ * :::
117
+ */
59
118
  export interface ClanSearchOptions {
119
+ /** Search clans by name. */
60
120
  name?: string;
121
+ /** Filter by minimum number of clan members. */
61
122
  minMembers?: number;
123
+ /** Filter by maximum number of clan members. */
62
124
  maxMembers?: number;
125
+ /** Filter by minimum amount of clan points. */
63
126
  minClanPoints?: number;
127
+ /** Filter by minimum clan level. */
64
128
  minClanLevel?: number;
129
+ /** Filter by clan war frequency. */
65
130
  warFrequency?: string;
131
+ /** Filter by clan location identifier. For list of available locations, refer to getLocations operation. */
66
132
  locationId?: string;
133
+ /** Comma separated list of label IDs to use for filtering results. */
67
134
  labelIds?: string;
135
+ /** Limit the number of items returned in the response. */
68
136
  limit?: number;
137
+ /**
138
+ * Return only items that occur after this marker.
139
+ * Before marker can be found from the response, inside the 'paging' property.
140
+ * Note that only after or before can be specified for a request, not both.
141
+ */
69
142
  after?: string;
143
+ /**
144
+ * Return only items that occur before this marker.
145
+ * Before marker can be found from the response, inside the 'paging' property.
146
+ * Note that only after or before can be specified for a request, not both.
147
+ */
70
148
  before?: string;
71
149
  }
150
+ /** Login options for a client. */
72
151
  export interface InitOptions {
152
+ /** Developer site email address. */
73
153
  email: string;
154
+ /** Developer site password. */
74
155
  password: string;
156
+ /** Name of API key(s). */
75
157
  keyName?: string;
158
+ /** Number of allowed API keys. */
76
159
  keyCount?: number;
160
+ /** Description of API key(s). */
77
161
  keyDescription?: string;
78
162
  }
@@ -50,8 +50,9 @@ class RequestHandler {
50
50
  }
51
51
  async request(path, options = {}) {
52
52
  const cached = (await this.cached?.get(path)) ?? null;
53
- if (cached && options.force !== true)
54
- return { data: cached, maxAge: 0, status: 200 };
53
+ if (cached && options.force !== true) {
54
+ return { data: cached.data, maxAge: cached.ttl - Date.now(), status: 200, path };
55
+ }
55
56
  if (!this.throttler || options.ignoreRateLimit)
56
57
  return this.exec(path, options);
57
58
  await this.throttler.wait();
@@ -74,15 +75,19 @@ class RequestHandler {
74
75
  if (!res && retries < (options.retryLimit ?? this.retryLimit))
75
76
  return this.exec(path, options, ++retries);
76
77
  if (res?.status === 403 && data?.reason === 'accessDenied.invalidIp' && this.email && this.password) {
77
- await this.login();
78
- return this.exec(path, options, ++retries);
78
+ const keys = await this.reValidateKeys().then(() => this.login());
79
+ if (keys.length)
80
+ return this.exec(path, options, ++retries);
79
81
  }
82
+ const maxAge = Number(res?.headers.get('cache-control')?.split('=')?.[1] ?? 0) * 1000;
83
+ if (res?.status === 403 && !data?.message)
84
+ throw new HTTPError_1.HTTPError(HTTPError_1.PrivateWarLogError, res.status, path, maxAge);
80
85
  if (!res?.ok)
81
- throw new HTTPError_1.HTTPError(data, res?.status ?? 504, path, options.method);
82
- const maxAge = Number(res.headers.get('cache-control')?.split('=')?.[1] ?? 0) * 1000;
83
- if (this.cached && maxAge > 0 && options.cache !== false)
84
- await this.cached.set(path, data, maxAge);
85
- return { data, maxAge, status: res.status };
86
+ throw new HTTPError_1.HTTPError(data, res?.status ?? 504, path, maxAge, options.method);
87
+ if (this.cached && maxAge > 0 && options.cache !== false) {
88
+ await this.cached.set(path, { data, ttl: Date.now() + maxAge }, maxAge);
89
+ }
90
+ return { data, maxAge, status: res.status, path };
86
91
  }
87
92
  async init(options) {
88
93
  if (!(options.email && options.password))
@@ -97,11 +102,12 @@ class RequestHandler {
97
102
  }
98
103
  async reValidateKeys() {
99
104
  for (const key of this.keys) {
100
- const res = await (0, node_fetch_1.default)(`${this.baseURL}/locations`, {
105
+ const res = await (0, node_fetch_1.default)(`${this.baseURL}/locations?limit=1`, {
101
106
  method: 'GET',
107
+ timeout: 10000,
102
108
  headers: { 'Authorization': `Bearer ${key}`, 'Content-Type': 'application/json' }
103
- });
104
- if (res.status === 403) {
109
+ }).catch(() => null);
110
+ if (res?.status === 403) {
105
111
  const index = this.keys.indexOf(key);
106
112
  this.keys.splice(index, 1);
107
113
  console.warn(`[WARN] Pre-defined key #${index + 1} is no longer valid. Removed from the key list.`);
@@ -111,6 +117,7 @@ class RequestHandler {
111
117
  async login() {
112
118
  const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/login`, {
113
119
  method: 'POST',
120
+ timeout: 10000,
114
121
  headers: { 'Content-Type': 'application/json' },
115
122
  body: JSON.stringify({ email: this.email, password: this.password })
116
123
  });
@@ -123,14 +130,14 @@ class RequestHandler {
123
130
  const ip = await this.getIp();
124
131
  const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/apikey/list`, {
125
132
  method: 'POST',
133
+ timeout: 10000,
126
134
  headers: { 'Content-Type': 'application/json', cookie }
127
135
  });
128
136
  const data = await res.json();
129
137
  // Get all available keys from the developer site.
130
138
  const keys = (data.keys ?? []);
131
139
  // Revoke keys for specified key name but not matching current IP address.
132
- const expiredKeys = keys.filter((key) => key.name === this.keyName && !key.cidrRanges.includes(ip));
133
- for (const key of expiredKeys) {
140
+ for (const key of keys.filter((key) => key.name === this.keyName && !key.cidrRanges.includes(ip))) {
134
141
  if (!(await this.revokeKey(key.id, cookie)))
135
142
  continue;
136
143
  const index = keys.findIndex(({ id }) => id === key.id);
@@ -163,6 +170,7 @@ class RequestHandler {
163
170
  async revokeKey(keyId, cookie) {
164
171
  const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/apikey/revoke`, {
165
172
  method: 'POST',
173
+ timeout: 10000,
166
174
  body: JSON.stringify({ id: keyId }),
167
175
  headers: { 'Content-Type': 'application/json', cookie }
168
176
  });
@@ -171,6 +179,7 @@ class RequestHandler {
171
179
  async createKey(cookie, ip) {
172
180
  const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/apikey/create`, {
173
181
  method: 'POST',
182
+ timeout: 10000,
174
183
  headers: { 'Content-Type': 'application/json', cookie },
175
184
  body: JSON.stringify({
176
185
  cidrRanges: [ip],
@@ -182,7 +191,7 @@ class RequestHandler {
182
191
  return data.key;
183
192
  }
184
193
  async getIp() {
185
- return (0, node_fetch_1.default)('https://api.ipify.org/').then((res) => res.text());
194
+ return (0, node_fetch_1.default)('https://api.ipify.org/', { timeout: 10000 }).then((res) => res.text());
186
195
  }
187
196
  }
188
197
  exports.RequestHandler = RequestHandler;
@@ -29,7 +29,3 @@ export declare class BatchThrottler {
29
29
  wait(): Promise<void>;
30
30
  throttle(): Promise<void>;
31
31
  }
32
- export interface DeferredPromise {
33
- resolve(): void;
34
- promise: Promise<void>;
35
- }
@@ -1,3 +1,4 @@
1
+ import { OverrideOptions } from '../rest/RequestHandler';
1
2
  import { ChatLanguage } from './ChatLanguage';
2
3
  import { ClanMember } from './ClanMember';
3
4
  import { Client } from '../client/Client';
@@ -59,5 +60,5 @@ export declare class Clan {
59
60
  members: ClanMember[];
60
61
  constructor(client: Client, data: APIClan);
61
62
  /** Get {@link Player} information for every Player in the clan. */
62
- fetchMembers(): Promise<Player[]>;
63
+ fetchMembers(options?: OverrideOptions): Promise<Player[]>;
63
64
  }
@@ -35,8 +35,8 @@ class Clan {
35
35
  this.members = data.memberList?.map((mem) => new ClanMember_1.ClanMember(this.client, mem)) ?? []; // eslint-disable-line
36
36
  }
37
37
  /** Get {@link Player} information for every Player in the clan. */
38
- async fetchMembers() {
39
- return (await Promise.allSettled(this.members.map((m) => this.client.getPlayer(m.tag, { ignoreRateLimit: true }))))
38
+ async fetchMembers(options) {
39
+ return (await Promise.allSettled(this.members.map((m) => this.client.getPlayer(m.tag, { ...options, ignoreRateLimit: true }))))
40
40
  .filter((res) => res.status === 'fulfilled')
41
41
  .map((res) => res.value);
42
42
  }
@@ -1,3 +1,4 @@
1
+ import { OverrideOptions } from '../rest/RequestHandler';
1
2
  import { Client } from '../client/Client';
2
3
  import { APIClanMember } from '../types';
3
4
  import { League } from './League';
@@ -27,5 +28,5 @@ export declare class ClanMember {
27
28
  received: number;
28
29
  constructor(client: Client, data: APIClanMember);
29
30
  /** Fetch detailed clan info for the member's clan. */
30
- fetch(): Promise<import("./Player").Player>;
31
+ fetch(options?: OverrideOptions): Promise<import("./Player").Player>;
31
32
  }
@@ -21,8 +21,8 @@ class ClanMember {
21
21
  this.received = data.donationsReceived;
22
22
  }
23
23
  /** Fetch detailed clan info for the member's clan. */
24
- async fetch() {
25
- return this.client.getPlayer(this.tag);
24
+ async fetch(options) {
25
+ return this.client.getPlayer(this.tag, options);
26
26
  }
27
27
  }
28
28
  exports.ClanMember = ClanMember;
@@ -116,12 +116,12 @@ export declare class ClanWar {
116
116
  opponent: WarClan;
117
117
  /** The war's unique tag. This is `null` unless this is a CWL. */
118
118
  warTag: string | null;
119
- /** The timestamp when a fresh version of this data will be available again. */
119
+ /** Maximum number of milliseconds the results can be cached. */
120
120
  maxAge: number;
121
121
  constructor(client: Client, data: APIClanWar, extra: {
122
122
  clanTag?: string;
123
123
  warTag?: string;
124
- maxAge?: number;
124
+ maxAge: number;
125
125
  });
126
126
  /** Return a {@link ClanWarMember} with the tag provided. */
127
127
  getMember(tag: string): ClanWarMember | null;
@@ -129,7 +129,9 @@ export declare class ClanWar {
129
129
  getAttack(attackerTag: string, defenderTag: string): ClanWarAttack | null;
130
130
  /** Return a list of {@link ClanWarAttack} for the defenderTag provided. */
131
131
  getDefenses(defenderTag: string): ClanWarAttack[];
132
- /** Returns either `friendly`, `cwl` or `regular`. */
133
- get type(): 'friendly' | 'cwl' | 'regular';
132
+ /** Returns either `friendly`, `cwl` or `normal`. */
133
+ get type(): "friendly" | "cwl" | "normal";
134
134
  private get _isFriendly();
135
+ /** Returns the war status, based off the home clan. */
136
+ get status(): "win" | "lose" | "tie" | "pending";
135
137
  }
@@ -147,7 +147,7 @@ class ClanWar {
147
147
  }
148
148
  this.clan = new WarClan(this, clan);
149
149
  this.opponent = new WarClan(this, opponent);
150
- this.maxAge = Date.now() + (extra.maxAge ?? 0);
150
+ this.maxAge = extra.maxAge;
151
151
  }
152
152
  /** Return a {@link ClanWarMember} with the tag provided. */
153
153
  getMember(tag) {
@@ -168,17 +168,31 @@ class ClanWar {
168
168
  }
169
169
  return this.opponent.attacks.filter((atk) => atk.defenderTag === defenderTag);
170
170
  }
171
- /** Returns either `friendly`, `cwl` or `regular`. */
171
+ /** Returns either `friendly`, `cwl` or `normal`. */
172
172
  get type() {
173
173
  if (this._isFriendly)
174
174
  return 'friendly';
175
175
  if (this.warTag)
176
176
  return 'cwl';
177
- return 'regular';
177
+ return 'normal';
178
178
  }
179
179
  get _isFriendly() {
180
180
  const preparationTime = this.startTime.getTime() - this.preparationStartTime.getTime();
181
181
  return Constants_1.FRIENDLY_WAR_PREPARATION_TIMES.includes(preparationTime);
182
182
  }
183
+ /** Returns the war status, based off the home clan. */
184
+ get status() {
185
+ if (this.state === 'preparation')
186
+ return 'pending';
187
+ if (this.clan.stars > this.opponent.stars)
188
+ return 'win';
189
+ if (this.clan.stars === this.opponent.stars) {
190
+ if (this.clan.destruction > this.opponent.destruction)
191
+ return 'win';
192
+ if (this.clan.destruction === this.opponent.destruction)
193
+ return 'tie';
194
+ }
195
+ return 'lose';
196
+ }
183
197
  }
184
198
  exports.ClanWar = ClanWar;
@@ -1,4 +1,5 @@
1
1
  import { APIClanWarLeagueClan, APIClanWarLeagueClanMember, APIClanWarLeagueGroup, APIClanWarLeagueRound } from '../types';
2
+ import { OverrideOptions } from '../rest/RequestHandler';
2
3
  import { Client } from '../client/Client';
3
4
  import { ClanWar } from './ClanWar';
4
5
  import { Player } from './Player';
@@ -28,7 +29,7 @@ export declare class ClanWarLeagueClan {
28
29
  members: ClanWarLeagueClanMember[];
29
30
  constructor(client: Client, data: APIClanWarLeagueClan);
30
31
  /** Get {@link Player} information for every members that are in the CWL group. */
31
- fetchMembers(): Promise<Player[]>;
32
+ fetchMembers(options?: OverrideOptions): Promise<Player[]>;
32
33
  }
33
34
  /** Represents a Round of CWL Group. */
34
35
  export declare class ClanWarLeagueRound {
@@ -53,9 +54,10 @@ export declare class ClanWarLeagueGroup {
53
54
  /**
54
55
  * This returns an array of {@link ClanWar} which fetches all wars in parallel.
55
56
  * @param clanTag Optional clan tag. If present, this will only return wars which belong to this clan.
57
+ * @param options Override options for the request.
56
58
  */
57
- getWars(clanTag?: string): Promise<ClanWar[]>;
59
+ getWars(clanTag?: string, options?: OverrideOptions): Promise<ClanWar[]>;
58
60
  private _getCurrentWars;
59
- /** Returns # (1-7) of the round for the specified warTag. */
61
+ /** Returns the index of the round for this specified warTag. */
60
62
  getRoundIndex(warTag: string): number | null;
61
63
  }
@@ -22,8 +22,8 @@ class ClanWarLeagueClan {
22
22
  this.members = data.members.map((mem) => new ClanWarLeagueClanMember(mem));
23
23
  }
24
24
  /** Get {@link Player} information for every members that are in the CWL group. */
25
- async fetchMembers() {
26
- return (await Promise.allSettled(this.members.map((m) => this.client.getPlayer(m.tag, { ignoreRateLimit: true }))))
25
+ async fetchMembers(options) {
26
+ return (await Promise.allSettled(this.members.map((m) => this.client.getPlayer(m.tag, { ...options, ignoreRateLimit: true }))))
27
27
  .filter((res) => res.status === 'fulfilled')
28
28
  .map((res) => res.value);
29
29
  }
@@ -49,33 +49,35 @@ class ClanWarLeagueGroup {
49
49
  /**
50
50
  * This returns an array of {@link ClanWar} which fetches all wars in parallel.
51
51
  * @param clanTag Optional clan tag. If present, this will only return wars which belong to this clan.
52
+ * @param options Override options for the request.
52
53
  */
53
- async getWars(clanTag) {
54
+ async getWars(clanTag, options) {
54
55
  const rounds = this.rounds.filter((round) => !round.warTags.includes('#0'));
55
56
  if (!rounds.length)
56
57
  return [];
57
58
  const warTags = rounds.map((round) => round.warTags).flat();
58
- const wars = await Promise.allSettled(warTags.map((warTag) => this.client.getClanWarLeagueRound({ warTag, clanTag }, { ignoreRateLimit: true })));
59
+ const wars = await Promise.allSettled(warTags.map((warTag) => this.client.getClanWarLeagueRound({ warTag, clanTag }, { ...options, ignoreRateLimit: true })));
59
60
  return wars
60
- .filter((res) => res.status === 'fulfilled' && res.value)
61
+ .filter((res) => res.status === 'fulfilled')
61
62
  .map((res) => res.value)
62
63
  .filter((war) => (clanTag ? war.clan.tag === clanTag : true));
63
64
  }
64
- async _getCurrentWars(clanTag) {
65
+ async _getCurrentWars(clanTag, options) {
65
66
  const rounds = this.rounds.filter((round) => !round.warTags.includes('#0'));
66
67
  if (!rounds.length)
67
68
  return [];
68
69
  const warTags = rounds
69
70
  .slice(-2)
70
71
  .map((round) => round.warTags)
71
- .flat();
72
- const wars = await Promise.allSettled(warTags.map((warTag) => this.client.getClanWarLeagueRound({ warTag, clanTag }, { ignoreRateLimit: true })));
72
+ .flat()
73
+ .reverse();
74
+ const wars = await Promise.allSettled(warTags.map((warTag) => this.client.getClanWarLeagueRound({ warTag, clanTag }, { ...options, ignoreRateLimit: true })));
73
75
  return wars
74
- .filter((res) => res.status === 'fulfilled' && res.value)
76
+ .filter((res) => res.status === 'fulfilled')
75
77
  .map((res) => res.value)
76
78
  .filter((war) => war.clan.tag === clanTag);
77
79
  }
78
- /** Returns # (1-7) of the round for the specified warTag. */
80
+ /** Returns the index of the round for this specified warTag. */
79
81
  getRoundIndex(warTag) {
80
82
  return this.rounds.find((round) => round.warTags.includes(warTag))?.round ?? null;
81
83
  }
@@ -49,6 +49,6 @@ export declare class ClanWarLog {
49
49
  /** The opposition clan. */
50
50
  opponent: WarLogClan;
51
51
  constructor(client: Client, data: APIClanWarLogEntry);
52
- /** Returns either `friendly`, `cwl` or `regular`. */
53
- get type(): "friendly" | "cwl" | "regular";
52
+ /** Returns either `friendly`, `cwl` or `normal`. */
53
+ get type(): "friendly" | "cwl" | "normal";
54
54
  }
@@ -34,13 +34,13 @@ class ClanWarLog {
34
34
  this.clan = new WarLogClan(data.clan);
35
35
  this.opponent = new WarLogClan(data.opponent);
36
36
  }
37
- /** Returns either `friendly`, `cwl` or `regular`. */
37
+ /** Returns either `friendly`, `cwl` or `normal`. */
38
38
  get type() {
39
39
  if (!this.clan.expEarned)
40
40
  return 'friendly';
41
41
  if (!this.opponent.tag)
42
42
  return 'cwl';
43
- return 'regular';
43
+ return 'normal';
44
44
  }
45
45
  }
46
46
  exports.ClanWarLog = ClanWarLog;
@@ -1,3 +1,4 @@
1
+ import { OverrideOptions } from '../rest/RequestHandler';
1
2
  import { LegendStatistics } from './LegendStatistics';
2
3
  import { Achievement } from './Achievement';
3
4
  import { Hero, Spell, Troop } from './Unit';
@@ -63,7 +64,7 @@ export declare class Player {
63
64
  heroes: Hero[];
64
65
  constructor(client: Client, data: APIPlayer);
65
66
  /** Fetch detailed clan info for the player's clan. */
66
- fetchClan(): Promise<import("./Clan").Clan | null>;
67
+ fetchClan(options?: OverrideOptions): Promise<import("./Clan").Clan | null>;
67
68
  /** An array of the player's home base troops. */
68
69
  get homeTroops(): Troop[];
69
70
  /** An array of the player's builder base troops. */
@@ -2,12 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Player = void 0;
4
4
  const Constants_1 = require("../util/Constants");
5
+ const raw_json_1 = require("../util/raw.json");
5
6
  const LegendStatistics_1 = require("./LegendStatistics");
6
7
  const Achievement_1 = require("./Achievement");
7
8
  const Unit_1 = require("./Unit");
8
9
  const PlayerClan_1 = require("./PlayerClan");
9
10
  const League_1 = require("./League");
10
11
  const Label_1 = require("./Label");
12
+ const UNIT_NAMES = [...raw_json_1.RAW_UNITS.map((unit) => unit.name), ...raw_json_1.RAW_SUPER_UNITS.map((unit) => unit.name)];
11
13
  /** Represents a Clash of Clans Player. */
12
14
  class Player {
13
15
  constructor(client, data) {
@@ -36,15 +38,15 @@ class Player {
36
38
  this.legendStatistics = data.legendStatistics ? new LegendStatistics_1.LegendStatistics(data.legendStatistics) : null;
37
39
  this.achievements = data.achievements.map((data) => new Achievement_1.Achievement(data));
38
40
  this.labels = data.labels.map((data) => new Label_1.Label(data));
39
- this.troops = data.troops.map((data) => new Unit_1.Troop(data));
40
- this.spells = data.spells.map((data) => new Unit_1.Spell(data));
41
- this.heroes = data.heroes.map((data) => new Unit_1.Hero(data));
41
+ this.troops = data.troops.filter((unit) => UNIT_NAMES.includes(unit.name)).map((unit) => new Unit_1.Troop(data, unit));
42
+ this.spells = data.spells.filter((unit) => UNIT_NAMES.includes(unit.name)).map((unit) => new Unit_1.Spell(data, unit));
43
+ this.heroes = data.heroes.filter((unit) => UNIT_NAMES.includes(unit.name)).map((unit) => new Unit_1.Hero(data, unit));
42
44
  }
43
45
  /** Fetch detailed clan info for the player's clan. */
44
- async fetchClan() {
46
+ async fetchClan(options) {
45
47
  if (!this.clan)
46
48
  return null;
47
- return this.client.getClan(this.clan.tag);
49
+ return this.client.getClan(this.clan.tag, options);
48
50
  }
49
51
  /** An array of the player's home base troops. */
50
52
  get homeTroops() {
@@ -1,3 +1,4 @@
1
+ import { OverrideOptions } from '../rest/RequestHandler';
1
2
  import { Client } from '../client/Client';
2
3
  import { APIPlayerClan } from '../types';
3
4
  import { Badge } from './Badge';
@@ -14,5 +15,5 @@ export declare class PlayerClan {
14
15
  badge: Badge;
15
16
  constructor(_client: Client, data: APIPlayerClan);
16
17
  /** Fetch detailed clan info for the player's clan. */
17
- fetch(): Promise<import("./Clan").Clan>;
18
+ fetch(options?: OverrideOptions): Promise<import("./Clan").Clan>;
18
19
  }
@@ -12,8 +12,8 @@ class PlayerClan {
12
12
  this.badge = new Badge_1.Badge(data.badgeUrls);
13
13
  }
14
14
  /** Fetch detailed clan info for the player's clan. */
15
- fetch() {
16
- return this._client.getClan(this.tag);
15
+ fetch(options) {
16
+ return this._client.getClan(this.tag, options);
17
17
  }
18
18
  }
19
19
  exports.PlayerClan = PlayerClan;
@@ -1,4 +1,4 @@
1
- import { APIPlayerItem } from '../types';
1
+ import { APIPlayerItem, APIPlayer } from '../types';
2
2
  /** Represents a player's unit. */
3
3
  export declare class Unit {
4
4
  /** The name of this unit. */
@@ -9,7 +9,35 @@ export declare class Unit {
9
9
  maxLevel: number;
10
10
  /** The village type of this unit. */
11
11
  village: 'home' | 'builderBase';
12
- constructor(data: APIPlayerItem);
12
+ /** Id of this unit. */
13
+ id: number;
14
+ /** Housing space of this unit. */
15
+ housingSpace: number;
16
+ /** Town/Builder hall's max level of this unit. */
17
+ hallMaxLevel: number;
18
+ /** Unlock Town/Builder Hall level of this unit. */
19
+ unlockHallLevel: number;
20
+ /** Unlock cost of this unit. */
21
+ unlockCost: number;
22
+ /** Unlock time of this unit. */
23
+ unlockTime: number;
24
+ /** Unlock resource of this unit. */
25
+ unlockResource: string;
26
+ /** Unlock building of this unit. */
27
+ unlockBuilding: string;
28
+ /** Unlock building level of this unit. */
29
+ unlockBuildingLevel: number;
30
+ /** Upgrade cost of this unit. */
31
+ upgradeCost: number;
32
+ /** Upgrade resource of this unit. */
33
+ upgradeResource: string;
34
+ /** Upgrade time of this unit. */
35
+ upgradeTime: number;
36
+ /** @internal */
37
+ minOriginalLevel: number | null;
38
+ /** @internal */
39
+ originalName: string | null;
40
+ constructor(data: APIPlayer, unit: APIPlayerItem);
13
41
  /** Whether the unit belongs to the home base. */
14
42
  get isHomeBase(): boolean;
15
43
  /** Whether the unit belongs to the builder base. */
@@ -22,8 +50,13 @@ export declare class Unit {
22
50
  /** Represents a player's troop. */
23
51
  export declare class Troop extends Unit {
24
52
  name: string;
25
- superTroopIsActive: boolean;
26
- constructor(data: APIPlayerItem);
53
+ /** Whether this troop is currently active of boosted. */
54
+ isActive: boolean;
55
+ /** Origin troop's minimum level of this super troop. */
56
+ minOriginalLevel: number | null;
57
+ /** Origin troop's name of this super troop. */
58
+ originalName: string | null;
59
+ constructor(data: APIPlayer, unit: APIPlayerItem);
27
60
  /** Whether this troop is a Super Troop. */
28
61
  get isSuperTroop(): boolean;
29
62
  }