clashofclans.js 1.5.4 → 2.0.0-dev.2c5b083

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.
Files changed (69) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/LICENSE +2 -1
  3. package/README.md +39 -110
  4. package/dist/client/Client.d.ts +177 -0
  5. package/dist/client/Client.js +237 -0
  6. package/dist/client/EventManager.d.ts +86 -0
  7. package/dist/client/EventManager.js +279 -0
  8. package/dist/index.d.ts +9 -0
  9. package/dist/index.js +21 -0
  10. package/dist/rest/HTTPError.d.ts +24 -0
  11. package/dist/rest/HTTPError.js +42 -0
  12. package/dist/rest/RESTManager.d.ts +56 -0
  13. package/dist/rest/RESTManager.js +123 -0
  14. package/dist/rest/RequestHandler.d.ts +162 -0
  15. package/dist/rest/RequestHandler.js +198 -0
  16. package/dist/rest/Throttler.d.ts +31 -0
  17. package/dist/rest/Throttler.js +86 -0
  18. package/dist/struct/Achievement.d.ts +25 -0
  19. package/dist/struct/Achievement.js +28 -0
  20. package/dist/struct/Badge.d.ts +16 -0
  21. package/dist/struct/Badge.js +27 -0
  22. package/dist/struct/ChatLanguage.d.ts +11 -0
  23. package/dist/struct/ChatLanguage.js +12 -0
  24. package/dist/struct/Clan.d.ts +64 -0
  25. package/dist/struct/Clan.js +44 -0
  26. package/dist/struct/ClanMember.d.ts +32 -0
  27. package/dist/struct/ClanMember.js +28 -0
  28. package/dist/struct/ClanWar.d.ts +137 -0
  29. package/dist/struct/ClanWar.js +198 -0
  30. package/dist/struct/ClanWarLeagueGroup.d.ts +63 -0
  31. package/dist/struct/ClanWarLeagueGroup.js +85 -0
  32. package/dist/struct/ClanWarLog.d.ts +54 -0
  33. package/dist/struct/ClanWarLog.js +46 -0
  34. package/dist/struct/Icon.d.ts +16 -0
  35. package/dist/struct/Icon.js +27 -0
  36. package/dist/struct/Label.d.ts +12 -0
  37. package/dist/struct/Label.js +13 -0
  38. package/dist/struct/League.d.ts +14 -0
  39. package/dist/struct/League.js +18 -0
  40. package/dist/struct/LegendStatistics.d.ts +18 -0
  41. package/dist/struct/LegendStatistics.js +17 -0
  42. package/dist/struct/Location.d.ts +15 -0
  43. package/dist/struct/Location.js +14 -0
  44. package/dist/struct/Player.d.ts +78 -0
  45. package/dist/struct/Player.js +72 -0
  46. package/dist/struct/PlayerClan.d.ts +19 -0
  47. package/dist/struct/PlayerClan.js +19 -0
  48. package/dist/struct/Ranking.d.ts +58 -0
  49. package/dist/struct/Ranking.js +50 -0
  50. package/dist/struct/Season.d.ts +19 -0
  51. package/dist/struct/Season.js +21 -0
  52. package/dist/struct/Unit.d.ts +68 -0
  53. package/dist/struct/Unit.js +90 -0
  54. package/dist/struct/WarLeague.d.ts +11 -0
  55. package/dist/struct/WarLeague.js +16 -0
  56. package/dist/struct/index.d.ts +19 -0
  57. package/dist/struct/index.js +31 -0
  58. package/dist/types/index.d.ts +350 -0
  59. package/dist/types/index.js +2 -0
  60. package/dist/util/Constants.d.ts +41 -0
  61. package/dist/util/Constants.js +122 -0
  62. package/dist/util/Util.d.ts +18 -0
  63. package/dist/util/Util.js +53 -0
  64. package/dist/util/raw.json +1 -0
  65. package/package.json +109 -36
  66. package/src/index.d.ts +0 -811
  67. package/src/index.js +0 -5
  68. package/src/struct/Client.js +0 -481
  69. package/src/util/Extension.js +0 -130
@@ -0,0 +1,162 @@
1
+ import { QueueThrottler, BatchThrottler } from './Throttler';
2
+ import Keyv from 'keyv';
3
+ /** Represents a Request Handler. */
4
+ export declare class RequestHandler {
5
+ #private;
6
+ private email;
7
+ private password;
8
+ private keyCount;
9
+ private keyName;
10
+ private keyDescription?;
11
+ private keys;
12
+ private readonly baseURL;
13
+ private readonly retryLimit;
14
+ private readonly restRequestTimeout;
15
+ private readonly throttler?;
16
+ private readonly cached;
17
+ constructor(options?: ClientOptions);
18
+ private get _keys();
19
+ private get _key();
20
+ setKeys(keys: string[]): this;
21
+ request<T>(path: string, options?: RequestOptions): Promise<Response<T>>;
22
+ private exec;
23
+ init(options: InitOptions): Promise<string[]>;
24
+ private reValidateKeys;
25
+ private login;
26
+ private getKeys;
27
+ private revokeKey;
28
+ private createKey;
29
+ private getIp;
30
+ }
31
+ /** Options for a client. */
32
+ export interface ClientOptions {
33
+ /** Keys from Clash of Clans API developer site. */
34
+ keys?: string[];
35
+ /** Base URL of the Clash of Clans API. */
36
+ baseURL?: string;
37
+ /**
38
+ * How many times to retry on 5XX errors.
39
+ */
40
+ retryLimit?: number;
41
+ /**
42
+ * Whether enable or disable internal caching.
43
+ * @example
44
+ * ```ts
45
+ * const client = new Client({ cache: true });
46
+ * ```
47
+ */
48
+ cache?: boolean | Keyv;
49
+ /** Time to wait before cancelling a REST request, in milliseconds. */
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
+ */
62
+ throttler?: QueueThrottler | BatchThrottler;
63
+ }
64
+ /** Search options for request. */
65
+ export interface SearchOptions extends OverrideOptions {
66
+ /** Limit the number of items returned in the response. */
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
+ */
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
+ */
79
+ before?: string;
80
+ }
81
+ /** Override options for a request. */
82
+ export interface OverrideOptions {
83
+ /** Whether to cache this response. */
84
+ cache?: boolean;
85
+ /** Whether to skip the cache check and request the API. */
86
+ force?: boolean;
87
+ /** How many times to retry on 5XX errors. */
88
+ retryLimit?: string;
89
+ /** Whether to ignore throttlers. */
90
+ ignoreRateLimit?: boolean;
91
+ /** Time to wait before cancelling a REST request, in milliseconds. */
92
+ restRequestTimeout?: number;
93
+ }
94
+ export interface RequestOptions extends OverrideOptions {
95
+ /** The request body. */
96
+ body?: string;
97
+ /** The request method. */
98
+ method?: string;
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
+ */
118
+ export interface ClanSearchOptions {
119
+ /** Search clans by name. */
120
+ name?: string;
121
+ /** Filter by minimum number of clan members. */
122
+ minMembers?: number;
123
+ /** Filter by maximum number of clan members. */
124
+ maxMembers?: number;
125
+ /** Filter by minimum amount of clan points. */
126
+ minClanPoints?: number;
127
+ /** Filter by minimum clan level. */
128
+ minClanLevel?: number;
129
+ /** Filter by clan war frequency. */
130
+ warFrequency?: string;
131
+ /** Filter by clan location identifier. For list of available locations, refer to getLocations operation. */
132
+ locationId?: string;
133
+ /** Comma separated list of label IDs to use for filtering results. */
134
+ labelIds?: string;
135
+ /** Limit the number of items returned in the response. */
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
+ */
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
+ */
148
+ before?: string;
149
+ }
150
+ /** Login options for a client. */
151
+ export interface InitOptions {
152
+ /** Developer site email address. */
153
+ email: string;
154
+ /** Developer site password. */
155
+ password: string;
156
+ /** Name of API key(s). */
157
+ keyName?: string;
158
+ /** Number of allowed API keys. */
159
+ keyCount?: number;
160
+ /** Description of API key(s). */
161
+ keyDescription?: string;
162
+ }
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ 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");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
8
+ if (kind === "m") throw new TypeError("Private method is not writable");
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ var _RequestHandler_keyIndex;
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.RequestHandler = void 0;
19
+ const Constants_1 = require("../util/Constants");
20
+ const HTTPError_1 = require("./HTTPError");
21
+ const node_fetch_1 = __importDefault(require("node-fetch"));
22
+ const https_1 = __importDefault(require("https"));
23
+ const keyv_1 = __importDefault(require("keyv"));
24
+ const agent = new https_1.default.Agent({ keepAlive: true });
25
+ /** Represents a Request Handler. */
26
+ class RequestHandler {
27
+ constructor(options) {
28
+ _RequestHandler_keyIndex.set(this, 0); // eslint-disable-line
29
+ this.keys = options?.keys ?? [];
30
+ this.retryLimit = options?.retryLimit ?? 0;
31
+ this.throttler = options?.throttler ?? null;
32
+ this.baseURL = options?.baseURL ?? Constants_1.API_BASE_URL;
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;
38
+ }
39
+ get _keys() {
40
+ return Array.isArray(this.keys) ? this.keys : [this.keys];
41
+ }
42
+ get _key() {
43
+ const key = this._keys[__classPrivateFieldGet(this, _RequestHandler_keyIndex, "f")];
44
+ __classPrivateFieldSet(this, _RequestHandler_keyIndex, __classPrivateFieldGet(this, _RequestHandler_keyIndex, "f") + 1 >= this._keys.length ? 0 : __classPrivateFieldGet(this, _RequestHandler_keyIndex, "f") + 1, "f");
45
+ return key;
46
+ }
47
+ setKeys(keys) {
48
+ this.keys = keys;
49
+ return this;
50
+ }
51
+ async request(path, options = {}) {
52
+ const cached = (await this.cached?.get(path)) ?? null;
53
+ if (cached && options.force !== true) {
54
+ return { data: cached.data, maxAge: cached.ttl - Date.now(), status: 200, path };
55
+ }
56
+ if (!this.throttler || options.ignoreRateLimit)
57
+ return this.exec(path, options);
58
+ await this.throttler.wait();
59
+ try {
60
+ return await this.exec(path, options);
61
+ }
62
+ finally {
63
+ await this.throttler.throttle();
64
+ }
65
+ }
66
+ async exec(path, options = {}, retries = 0) {
67
+ const res = await (0, node_fetch_1.default)(`${this.baseURL}${path}`, {
68
+ agent,
69
+ body: options.body,
70
+ method: options.method,
71
+ timeout: options.restRequestTimeout ?? this.restRequestTimeout,
72
+ headers: { 'Authorization': `Bearer ${this._key}`, 'Content-Type': 'application/json' }
73
+ }).catch(() => null);
74
+ const data = await res?.json().catch(() => null);
75
+ if (!res && retries < (options.retryLimit ?? this.retryLimit))
76
+ return this.exec(path, options, ++retries);
77
+ if (res?.status === 403 && data?.reason === 'accessDenied.invalidIp' && this.email && this.password) {
78
+ const keys = await this.reValidateKeys().then(() => this.login());
79
+ if (keys.length)
80
+ return this.exec(path, options, ++retries);
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);
85
+ if (!res?.ok)
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 };
91
+ }
92
+ async init(options) {
93
+ if (!(options.email && options.password))
94
+ throw ReferenceError('Missing email and password.');
95
+ this.keyDescription = options.keyDescription;
96
+ this.keyName = options.keyName ?? 'clashofclans.js.keys';
97
+ this.keyCount = Math.min(options.keyCount ?? 1, 10);
98
+ this.password = options.password;
99
+ this.email = options.email;
100
+ await this.reValidateKeys();
101
+ return this.login();
102
+ }
103
+ async reValidateKeys() {
104
+ for (const key of this.keys) {
105
+ const res = await (0, node_fetch_1.default)(`${this.baseURL}/locations?limit=1`, {
106
+ method: 'GET',
107
+ timeout: 10000,
108
+ headers: { 'Authorization': `Bearer ${key}`, 'Content-Type': 'application/json' }
109
+ }).catch(() => null);
110
+ if (res?.status === 403) {
111
+ const index = this.keys.indexOf(key);
112
+ this.keys.splice(index, 1);
113
+ console.warn(`[WARN] Pre-defined key #${index + 1} is no longer valid. Removed from the key list.`);
114
+ }
115
+ }
116
+ }
117
+ async login() {
118
+ const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/login`, {
119
+ method: 'POST',
120
+ timeout: 10000,
121
+ headers: { 'Content-Type': 'application/json' },
122
+ body: JSON.stringify({ email: this.email, password: this.password })
123
+ });
124
+ if (res.ok) {
125
+ return this.getKeys(res.headers.get('set-cookie'));
126
+ }
127
+ throw new ReferenceError('Invalid email or password.');
128
+ }
129
+ async getKeys(cookie) {
130
+ const ip = await this.getIp();
131
+ const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/apikey/list`, {
132
+ method: 'POST',
133
+ timeout: 10000,
134
+ headers: { 'Content-Type': 'application/json', cookie }
135
+ });
136
+ const data = await res.json();
137
+ // Get all available keys from the developer site.
138
+ const keys = (data.keys ?? []);
139
+ // Revoke keys for specified key name but not matching current IP address.
140
+ for (const key of keys.filter((key) => key.name === this.keyName && !key.cidrRanges.includes(ip))) {
141
+ if (!(await this.revokeKey(key.id, cookie)))
142
+ continue;
143
+ const index = keys.findIndex(({ id }) => id === key.id);
144
+ keys.splice(index, 1);
145
+ }
146
+ // Filter keys for current IP address and specified key name.
147
+ for (const key of keys.filter((key) => key.name === this.keyName && key.cidrRanges.includes(ip))) {
148
+ if (this.keys.length >= this.keyCount)
149
+ break;
150
+ if (!this.keys.includes(key.key))
151
+ this.keys.push(key.key);
152
+ }
153
+ // Create keys within limits (maximum of 10 keys per account)
154
+ while (this.keys.length < this.keyCount && keys.length < 10) {
155
+ const key = await this.createKey(cookie, ip);
156
+ this.keys.push(key.key);
157
+ keys.push(key);
158
+ }
159
+ if (this.keys.length < this.keyCount && keys.length === 10) {
160
+ console.warn(`[WARN] ${this.keyCount} key(s) were requested but failed to create ${this.keyCount - this.keys.length} more key(s).`);
161
+ }
162
+ if (!this.keys.length) {
163
+ throw new Error([
164
+ `${keys.length} API keys were created but none match a key name of "${this.keyName}" and IP "${ip}".`,
165
+ `Specify a key name or go to "https://developer.clashofclans.com" to delete unused keys.`
166
+ ].join(' '));
167
+ }
168
+ return this.keys;
169
+ }
170
+ async revokeKey(keyId, cookie) {
171
+ const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/apikey/revoke`, {
172
+ method: 'POST',
173
+ timeout: 10000,
174
+ body: JSON.stringify({ id: keyId }),
175
+ headers: { 'Content-Type': 'application/json', cookie }
176
+ });
177
+ return res.ok;
178
+ }
179
+ async createKey(cookie, ip) {
180
+ const res = await (0, node_fetch_1.default)(`${Constants_1.DEV_SITE_API_BASE_URL}/apikey/create`, {
181
+ method: 'POST',
182
+ timeout: 10000,
183
+ headers: { 'Content-Type': 'application/json', cookie },
184
+ body: JSON.stringify({
185
+ cidrRanges: [ip],
186
+ name: this.keyName,
187
+ description: this.keyDescription ?? new Date().toUTCString()
188
+ })
189
+ });
190
+ const data = await res.json();
191
+ return data.key;
192
+ }
193
+ async getIp() {
194
+ return (0, node_fetch_1.default)('https://api.ipify.org/', { timeout: 10000 }).then((res) => res.text());
195
+ }
196
+ }
197
+ exports.RequestHandler = RequestHandler;
198
+ _RequestHandler_keyIndex = new WeakMap();
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Represents a throttler that sleeps for x ms between each request.
3
+ * ```js
4
+ * const throttler = new QueueThrottler(1000 / 10);
5
+ * // 10 requests per second or sleep for 100ms between each request.
6
+ * ```
7
+ */
8
+ export declare class QueueThrottler {
9
+ private lastRun?;
10
+ private readonly sleepTime;
11
+ private readonly promises;
12
+ constructor(sleepTime?: number);
13
+ get remaining(): number;
14
+ throttle(): Promise<void>;
15
+ wait(): Promise<void>;
16
+ private shift;
17
+ }
18
+ /**
19
+ * Represents a throttler that allows x requests per second before sleeping until the next second.
20
+ * ```js
21
+ * const throttler = new BatchThrottler(30);
22
+ * // 30 requests every second.
23
+ * ```
24
+ */
25
+ export declare class BatchThrottler {
26
+ #private;
27
+ private readonly rateLimit;
28
+ constructor(rateLimit?: number);
29
+ wait(): Promise<void>;
30
+ throttle(): Promise<void>;
31
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ 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");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var _BatchThrottler_taskLogs;
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.BatchThrottler = exports.QueueThrottler = void 0;
10
+ const Util_1 = require("../util/Util");
11
+ /**
12
+ * Represents a throttler that sleeps for x ms between each request.
13
+ * ```js
14
+ * const throttler = new QueueThrottler(1000 / 10);
15
+ * // 10 requests per second or sleep for 100ms between each request.
16
+ * ```
17
+ */
18
+ class QueueThrottler {
19
+ constructor(sleepTime = 100) {
20
+ this.promises = [];
21
+ this.sleepTime = sleepTime;
22
+ }
23
+ get remaining() {
24
+ return this.promises.length;
25
+ }
26
+ async throttle() {
27
+ if (this.lastRun) {
28
+ const difference = Date.now() - this.lastRun;
29
+ const needToSleep = this.sleepTime - difference;
30
+ if (needToSleep > 0)
31
+ await Util_1.Util.delay(needToSleep);
32
+ }
33
+ this.lastRun = Date.now();
34
+ return this.shift();
35
+ }
36
+ wait() {
37
+ const next = this.promises.length ? this.promises[this.promises.length - 1].promise : Promise.resolve();
38
+ let resolve;
39
+ const promise = new Promise((res) => {
40
+ resolve = res;
41
+ });
42
+ this.promises.push({ resolve: resolve, promise });
43
+ return next;
44
+ }
45
+ shift() {
46
+ const deferred = this.promises.shift();
47
+ if (typeof deferred !== 'undefined')
48
+ deferred.resolve();
49
+ }
50
+ }
51
+ exports.QueueThrottler = QueueThrottler;
52
+ /**
53
+ * Represents a throttler that allows x requests per second before sleeping until the next second.
54
+ * ```js
55
+ * const throttler = new BatchThrottler(30);
56
+ * // 30 requests every second.
57
+ * ```
58
+ */
59
+ class BatchThrottler {
60
+ constructor(rateLimit = 10) {
61
+ _BatchThrottler_taskLogs.set(this, []); // eslint-disable-line
62
+ this.rateLimit = rateLimit;
63
+ }
64
+ async wait() {
65
+ return Promise.resolve();
66
+ }
67
+ async throttle() {
68
+ while (true) { // eslint-disable-line
69
+ const now = Date.now();
70
+ while (__classPrivateFieldGet(this, _BatchThrottler_taskLogs, "f").length) {
71
+ if (now - __classPrivateFieldGet(this, _BatchThrottler_taskLogs, "f")[0] > 1000) {
72
+ __classPrivateFieldGet(this, _BatchThrottler_taskLogs, "f").shift();
73
+ }
74
+ else {
75
+ break;
76
+ }
77
+ }
78
+ if (__classPrivateFieldGet(this, _BatchThrottler_taskLogs, "f").length < this.rateLimit)
79
+ break;
80
+ await Util_1.Util.delay(1000);
81
+ }
82
+ __classPrivateFieldGet(this, _BatchThrottler_taskLogs, "f").push(Date.now());
83
+ }
84
+ }
85
+ exports.BatchThrottler = BatchThrottler;
86
+ _BatchThrottler_taskLogs = new WeakMap();
@@ -0,0 +1,25 @@
1
+ import { APIPlayerAchievement } from '../types';
2
+ /** Represents a Clash of Clans Achievement. */
3
+ export declare class Achievement {
4
+ /** The name of the achievement. */
5
+ name: string;
6
+ /** The current stars achieved for the achievement. */
7
+ stars: number;
8
+ /** The number of X things attained for this achievement. */
9
+ value: number;
10
+ /** The number of X things required to complete this achievement. */
11
+ target: number;
12
+ /** Information regarding the achievement. */
13
+ info: string;
14
+ /** The village this achievement belongs to. */
15
+ village: 'home' | 'builderBase';
16
+ /** Information regarding completion of the achievement. */
17
+ completionInfo: string | null;
18
+ constructor(data: APIPlayerAchievement);
19
+ /** Whether achievement belongs to the home base. */
20
+ get isHomeBase(): boolean;
21
+ /** Whether the achievement belongs to the builder base. */
22
+ get isBuilderBase(): boolean;
23
+ /** Whether the achievement is completed. */
24
+ get isCompleted(): boolean;
25
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Achievement = void 0;
4
+ /** Represents a Clash of Clans Achievement. */
5
+ class Achievement {
6
+ constructor(data) {
7
+ this.name = data.name;
8
+ this.stars = data.stars;
9
+ this.value = data.value;
10
+ this.target = data.target;
11
+ this.info = data.info;
12
+ this.village = data.village;
13
+ this.completionInfo = data.completionInfo ?? null;
14
+ }
15
+ /** Whether achievement belongs to the home base. */
16
+ get isHomeBase() {
17
+ return this.village === 'home';
18
+ }
19
+ /** Whether the achievement belongs to the builder base. */
20
+ get isBuilderBase() {
21
+ return this.village === 'builderBase';
22
+ }
23
+ /** Whether the achievement is completed. */
24
+ get isCompleted() {
25
+ return this.stars === 3;
26
+ }
27
+ }
28
+ exports.Achievement = Achievement;
@@ -0,0 +1,16 @@
1
+ import { APIBadge } from '../types';
2
+ /** Represents a Clash of Clans Badge. */
3
+ export declare class Badge {
4
+ private readonly _data;
5
+ /** The default badge URL. */
6
+ url: string;
7
+ constructor(data: APIBadge);
8
+ /** The large badge URL. */
9
+ get large(): string;
10
+ /** The medium badge URL. */
11
+ get medium(): string;
12
+ /** The small badge URL. */
13
+ get small(): string;
14
+ /** Get unique hash of this Badge. */
15
+ get hash(): string;
16
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Badge = void 0;
4
+ /** Represents a Clash of Clans Badge. */
5
+ class Badge {
6
+ constructor(data) {
7
+ Object.defineProperty(this, '_data', { value: data });
8
+ this.url = data.large;
9
+ }
10
+ /** The large badge URL. */
11
+ get large() {
12
+ return this._data.large;
13
+ }
14
+ /** The medium badge URL. */
15
+ get medium() {
16
+ return this._data.medium;
17
+ }
18
+ /** The small badge URL. */
19
+ get small() {
20
+ return this._data.small;
21
+ }
22
+ /** Get unique hash of this Badge. */
23
+ get hash() {
24
+ return this.url.split('/').pop();
25
+ }
26
+ }
27
+ exports.Badge = Badge;
@@ -0,0 +1,11 @@
1
+ import { APIChatLanguage } from '../types';
2
+ /** Represents a Clan's Chat Language. */
3
+ export declare class ChatLanguage {
4
+ /** The language's unique Id. */
5
+ id: number;
6
+ /** The language's full name. */
7
+ name: string;
8
+ /** The language's code. */
9
+ code: string;
10
+ constructor(data: APIChatLanguage);
11
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChatLanguage = void 0;
4
+ /** Represents a Clan's Chat Language. */
5
+ class ChatLanguage {
6
+ constructor(data) {
7
+ this.id = data.id;
8
+ this.name = data.name;
9
+ this.code = data.languageCode;
10
+ }
11
+ }
12
+ exports.ChatLanguage = ChatLanguage;
@@ -0,0 +1,64 @@
1
+ import { OverrideOptions } from '../rest/RequestHandler';
2
+ import { ChatLanguage } from './ChatLanguage';
3
+ import { ClanMember } from './ClanMember';
4
+ import { Client } from '../client/Client';
5
+ import { WarLeague } from './WarLeague';
6
+ import type { Player } from './Player';
7
+ import { Location } from './Location';
8
+ import { APIClan } from '../types';
9
+ import { Label } from './Label';
10
+ import { Badge } from './Badge';
11
+ /** Represents a Clan. */
12
+ export declare class Clan {
13
+ client: Client;
14
+ /** Name of the clan. */
15
+ name: string;
16
+ /** Tag of the clan. */
17
+ tag: string;
18
+ /** The clan's type for accepting members. */
19
+ type: 'open' | 'inviteOnly' | 'closed';
20
+ /** The clan's description. */
21
+ description: string;
22
+ /** The location of this clan. */
23
+ location: Location | null;
24
+ /** The clan's trophy count. */
25
+ chatLanguage: ChatLanguage | null;
26
+ /** The clan's Badge. */
27
+ badge: Badge;
28
+ /** The clan's level. */
29
+ level: number;
30
+ /** The clan's trophy count. */
31
+ points: number;
32
+ /** The clan's versus trophy count. */
33
+ versusPoints: number;
34
+ /** The minimum trophies required to apply to this clan. */
35
+ requiredTrophies: number;
36
+ /** The minimum hall level required to apply to this clan. */
37
+ requiredTownHallLevel: number | null;
38
+ /** The frequency for when this clan goes to war. */
39
+ warFrequency: 'always' | 'moreThanOncePerWeek' | 'oncePerWeek' | 'lessThanOncePerWeek' | 'never' | 'unknown';
40
+ /** The clan's current war winning streak. */
41
+ warWinStreak: number;
42
+ /** The number of wars the clan has won. */
43
+ warWins: number;
44
+ /** The number of wars the clan has tied. */
45
+ warTies: number | null;
46
+ /** The number of wars the clan has lost. */
47
+ warLosses: number | null;
48
+ /** Indicates if the clan has a public war log. */
49
+ isWarLogPublic: boolean;
50
+ /** The clan's CWL league. */
51
+ warLeague: WarLeague | null;
52
+ /** The number of members in the clan. */
53
+ memberCount: number;
54
+ /** An array of {@link Label} that the clan has. */
55
+ labels: Label[];
56
+ /**
57
+ * List of clan members.
58
+ * - This property returns empty array for {@link Client.getClans} method.
59
+ */
60
+ members: ClanMember[];
61
+ constructor(client: Client, data: APIClan);
62
+ /** Get {@link Player} information for every Player in the clan. */
63
+ fetchMembers(options?: OverrideOptions): Promise<Player[]>;
64
+ }