clashofclans.js 2.0.0-dev.30ea324 → 2.0.0-dev.3a1efb5

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