guildwars2-ts 1.1.0 → 1.1.2

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/LICENSE CHANGED
@@ -1,16 +1,16 @@
1
- ISC License
2
-
3
- Copyright (c) 2023 Ivan Sosnov
4
- Copyright (c) 2021 Julio Sansossio (parts of request base code)
5
-
6
- Permission to use, copy, modify, and/or distribute this software for any
7
- purpose with or without fee is hereby granted, provided that the above
8
- copyright notice and this permission notice appear in all copies.
9
-
10
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
11
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
13
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
15
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16
- PERFORMANCE OF THIS SOFTWARE.
1
+ ISC License
2
+
3
+ Copyright (c) 2023 Ivan Sosnov
4
+ Copyright (c) 2021 Julio Sansossio (parts of request base code)
5
+
6
+ Permission to use, copy, modify, and/or distribute this software for any
7
+ purpose with or without fee is hereby granted, provided that the above
8
+ copyright notice and this permission notice appear in all copies.
9
+
10
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
11
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
13
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
15
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16
+ PERFORMANCE OF THIS SOFTWARE.
package/dist/index.d.mts CHANGED
@@ -50,8 +50,6 @@ declare class ApiBase {
50
50
  constructor(apiParams?: ApiParams);
51
51
  /**
52
52
  * Parameters for the api response, at top level
53
- *
54
- * @returns Api parameters
55
53
  */
56
54
  protected getParams(): ApiParams;
57
55
  /**
@@ -60,26 +58,25 @@ declare class ApiBase {
60
58
  * @param endpoint - API Endpoint
61
59
  * @param apiParams - Query string
62
60
  * @param responseType - Type of the response
61
+ * @param attempts - Previously failed retry count
63
62
  */
64
- protected buildRequest<T extends z.ZodType>(endpoint: Endpoint, apiParams: UrlParams, responseType: T): Promise<z.infer<T>>;
63
+ protected buildRequest<T extends z.ZodType>(endpoint: Endpoint, apiParams: UrlParams, responseType: T, attempts?: number): Promise<z.infer<T>>;
65
64
  /**
66
65
  * Retries failed requests
67
- * TODO: Fix logic. Rate-limits are almost impossible hit, but other generic requests will fail and loop forever
68
66
  *
69
67
  * @param endpoint - Endpoint to which a request was originally made
70
68
  * @param prevOptions - Axios request options
71
69
  * @param responseType - Originally requested schema
72
70
  * @param apiParams - Query string
71
+ * @param rateLimitAttempt - Current rate-limit retry counter
73
72
  * @param prevError - Error that caused a retry
74
- * @returns Successful request, or error
75
73
  */
76
- protected retryRequest<T extends z.ZodType>(endpoint: Endpoint, prevOptions: RawAxiosRequestConfig, responseType: T, apiParams: UrlParams, prevError?: unknown): Promise<T>;
74
+ protected retryRequest<T extends z.ZodType>(endpoint: Endpoint, prevOptions: RawAxiosRequestConfig, responseType: T, apiParams: UrlParams, rateLimitAttempt: number, prevError?: unknown): Promise<T>;
77
75
  /**
78
76
  * Builds final Api url from the endpoint and provided parameters
79
77
  *
80
78
  * @param endpoint - Api endpoint
81
79
  * @param urlParams - Parameters
82
- * @returns Finalized endpoint Url
83
80
  */
84
81
  private _getApiUrl;
85
82
  }
@@ -1803,8 +1800,9 @@ declare const ColorsDTO: z.ZodArray<z.ZodObject<{
1803
1800
  /** ID of the dye item. */
1804
1801
  item: z.ZodOptional<z.ZodNumber>;
1805
1802
  /** Color categories. */
1806
- categories: z.ZodOptional<z.ZodTuple<[z.ZodEnum<["Gray", "Brown", "Red", "Orange", "Yellow", "Green", "Blue", "Purple"]>, z.ZodEnum<["Vibrant", "Leather", "Metal"]>, z.ZodEnum<["Starter", "Common", "Uncommon", "Rare", "Exclusive"]>], null>>;
1803
+ categories: z.ZodUnion<[z.ZodTuple<[z.ZodEnum<["Gray", "Brown", "Red", "Orange", "Yellow", "Green", "Blue", "Purple"]>, z.ZodEnum<["Vibrant", "Leather", "Metal"]>, z.ZodEnum<["Starter", "Common", "Uncommon", "Rare", "Exclusive"]>], null>, z.ZodArray<z.ZodUndefined, "many">]>;
1807
1804
  }, "strip", z.ZodTypeAny, {
1805
+ categories: (undefined[] | ["Gray" | "Brown" | "Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple", "Vibrant" | "Leather" | "Metal", "Starter" | "Common" | "Uncommon" | "Rare" | "Exclusive"]) & (undefined[] | ["Gray" | "Brown" | "Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple", "Vibrant" | "Leather" | "Metal", "Starter" | "Common" | "Uncommon" | "Rare" | "Exclusive"] | undefined);
1808
1806
  id: number;
1809
1807
  name: string;
1810
1808
  base_rgb: number[];
@@ -1841,8 +1839,8 @@ declare const ColorsDTO: z.ZodArray<z.ZodObject<{
1841
1839
  rgb: number[];
1842
1840
  } | undefined;
1843
1841
  item?: number | undefined;
1844
- categories?: ["Gray" | "Brown" | "Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple", "Vibrant" | "Leather" | "Metal", "Starter" | "Common" | "Uncommon" | "Rare" | "Exclusive"] | undefined;
1845
1842
  }, {
1843
+ categories: (undefined[] | ["Gray" | "Brown" | "Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple", "Vibrant" | "Leather" | "Metal", "Starter" | "Common" | "Uncommon" | "Rare" | "Exclusive"]) & (undefined[] | ["Gray" | "Brown" | "Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple", "Vibrant" | "Leather" | "Metal", "Starter" | "Common" | "Uncommon" | "Rare" | "Exclusive"] | undefined);
1846
1844
  id: number;
1847
1845
  name: string;
1848
1846
  base_rgb: number[];
@@ -1879,7 +1877,6 @@ declare const ColorsDTO: z.ZodArray<z.ZodObject<{
1879
1877
  rgb: number[];
1880
1878
  } | undefined;
1881
1879
  item?: number | undefined;
1882
- categories?: ["Gray" | "Brown" | "Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple", "Vibrant" | "Leather" | "Metal", "Starter" | "Common" | "Uncommon" | "Rare" | "Exclusive"] | undefined;
1883
1880
  }>, "many">;
1884
1881
 
1885
1882
  /**
@@ -11098,12 +11095,6 @@ declare class GuildApi extends ApiBase {
11098
11095
  name: string;
11099
11096
  role: "Member" | "Captain";
11100
11097
  }[];
11101
- seasons: {
11102
- id: string;
11103
- rating: number;
11104
- wins: number;
11105
- losses: number;
11106
- }[];
11107
11098
  id: number;
11108
11099
  name: string;
11109
11100
  aggregate: {
@@ -11114,20 +11105,20 @@ declare class GuildApi extends ApiBase {
11114
11105
  forfeits: number;
11115
11106
  };
11116
11107
  ladders: {
11117
- ranked: {
11108
+ ranked?: {
11118
11109
  wins: number;
11119
11110
  losses: number;
11120
11111
  desertions: number;
11121
11112
  byes: number;
11122
11113
  forfeits: number;
11123
- };
11124
- unranked: {
11114
+ } | undefined;
11115
+ unranked?: {
11125
11116
  wins: number;
11126
11117
  losses: number;
11127
11118
  desertions: number;
11128
11119
  byes: number;
11129
11120
  forfeits: number;
11130
- };
11121
+ } | undefined;
11131
11122
  };
11132
11123
  games: {
11133
11124
  id: string;
@@ -11143,6 +11134,12 @@ declare class GuildApi extends ApiBase {
11143
11134
  rating_change: number;
11144
11135
  season?: string | undefined;
11145
11136
  }[];
11137
+ seasons?: {
11138
+ id: string;
11139
+ rating: number;
11140
+ wins: number;
11141
+ losses: number;
11142
+ }[] | undefined;
11146
11143
  }[]>;
11147
11144
  /**
11148
11145
  * Returns information about the items in a guild's treasury.
package/dist/index.d.ts CHANGED
@@ -50,8 +50,6 @@ declare class ApiBase {
50
50
  constructor(apiParams?: ApiParams);
51
51
  /**
52
52
  * Parameters for the api response, at top level
53
- *
54
- * @returns Api parameters
55
53
  */
56
54
  protected getParams(): ApiParams;
57
55
  /**
@@ -60,26 +58,25 @@ declare class ApiBase {
60
58
  * @param endpoint - API Endpoint
61
59
  * @param apiParams - Query string
62
60
  * @param responseType - Type of the response
61
+ * @param attempts - Previously failed retry count
63
62
  */
64
- protected buildRequest<T extends z.ZodType>(endpoint: Endpoint, apiParams: UrlParams, responseType: T): Promise<z.infer<T>>;
63
+ protected buildRequest<T extends z.ZodType>(endpoint: Endpoint, apiParams: UrlParams, responseType: T, attempts?: number): Promise<z.infer<T>>;
65
64
  /**
66
65
  * Retries failed requests
67
- * TODO: Fix logic. Rate-limits are almost impossible hit, but other generic requests will fail and loop forever
68
66
  *
69
67
  * @param endpoint - Endpoint to which a request was originally made
70
68
  * @param prevOptions - Axios request options
71
69
  * @param responseType - Originally requested schema
72
70
  * @param apiParams - Query string
71
+ * @param rateLimitAttempt - Current rate-limit retry counter
73
72
  * @param prevError - Error that caused a retry
74
- * @returns Successful request, or error
75
73
  */
76
- protected retryRequest<T extends z.ZodType>(endpoint: Endpoint, prevOptions: RawAxiosRequestConfig, responseType: T, apiParams: UrlParams, prevError?: unknown): Promise<T>;
74
+ protected retryRequest<T extends z.ZodType>(endpoint: Endpoint, prevOptions: RawAxiosRequestConfig, responseType: T, apiParams: UrlParams, rateLimitAttempt: number, prevError?: unknown): Promise<T>;
77
75
  /**
78
76
  * Builds final Api url from the endpoint and provided parameters
79
77
  *
80
78
  * @param endpoint - Api endpoint
81
79
  * @param urlParams - Parameters
82
- * @returns Finalized endpoint Url
83
80
  */
84
81
  private _getApiUrl;
85
82
  }
@@ -1803,8 +1800,9 @@ declare const ColorsDTO: z.ZodArray<z.ZodObject<{
1803
1800
  /** ID of the dye item. */
1804
1801
  item: z.ZodOptional<z.ZodNumber>;
1805
1802
  /** Color categories. */
1806
- categories: z.ZodOptional<z.ZodTuple<[z.ZodEnum<["Gray", "Brown", "Red", "Orange", "Yellow", "Green", "Blue", "Purple"]>, z.ZodEnum<["Vibrant", "Leather", "Metal"]>, z.ZodEnum<["Starter", "Common", "Uncommon", "Rare", "Exclusive"]>], null>>;
1803
+ categories: z.ZodUnion<[z.ZodTuple<[z.ZodEnum<["Gray", "Brown", "Red", "Orange", "Yellow", "Green", "Blue", "Purple"]>, z.ZodEnum<["Vibrant", "Leather", "Metal"]>, z.ZodEnum<["Starter", "Common", "Uncommon", "Rare", "Exclusive"]>], null>, z.ZodArray<z.ZodUndefined, "many">]>;
1807
1804
  }, "strip", z.ZodTypeAny, {
1805
+ categories: (undefined[] | ["Gray" | "Brown" | "Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple", "Vibrant" | "Leather" | "Metal", "Starter" | "Common" | "Uncommon" | "Rare" | "Exclusive"]) & (undefined[] | ["Gray" | "Brown" | "Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple", "Vibrant" | "Leather" | "Metal", "Starter" | "Common" | "Uncommon" | "Rare" | "Exclusive"] | undefined);
1808
1806
  id: number;
1809
1807
  name: string;
1810
1808
  base_rgb: number[];
@@ -1841,8 +1839,8 @@ declare const ColorsDTO: z.ZodArray<z.ZodObject<{
1841
1839
  rgb: number[];
1842
1840
  } | undefined;
1843
1841
  item?: number | undefined;
1844
- categories?: ["Gray" | "Brown" | "Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple", "Vibrant" | "Leather" | "Metal", "Starter" | "Common" | "Uncommon" | "Rare" | "Exclusive"] | undefined;
1845
1842
  }, {
1843
+ categories: (undefined[] | ["Gray" | "Brown" | "Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple", "Vibrant" | "Leather" | "Metal", "Starter" | "Common" | "Uncommon" | "Rare" | "Exclusive"]) & (undefined[] | ["Gray" | "Brown" | "Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple", "Vibrant" | "Leather" | "Metal", "Starter" | "Common" | "Uncommon" | "Rare" | "Exclusive"] | undefined);
1846
1844
  id: number;
1847
1845
  name: string;
1848
1846
  base_rgb: number[];
@@ -1879,7 +1877,6 @@ declare const ColorsDTO: z.ZodArray<z.ZodObject<{
1879
1877
  rgb: number[];
1880
1878
  } | undefined;
1881
1879
  item?: number | undefined;
1882
- categories?: ["Gray" | "Brown" | "Red" | "Orange" | "Yellow" | "Green" | "Blue" | "Purple", "Vibrant" | "Leather" | "Metal", "Starter" | "Common" | "Uncommon" | "Rare" | "Exclusive"] | undefined;
1883
1880
  }>, "many">;
1884
1881
 
1885
1882
  /**
@@ -11098,12 +11095,6 @@ declare class GuildApi extends ApiBase {
11098
11095
  name: string;
11099
11096
  role: "Member" | "Captain";
11100
11097
  }[];
11101
- seasons: {
11102
- id: string;
11103
- rating: number;
11104
- wins: number;
11105
- losses: number;
11106
- }[];
11107
11098
  id: number;
11108
11099
  name: string;
11109
11100
  aggregate: {
@@ -11114,20 +11105,20 @@ declare class GuildApi extends ApiBase {
11114
11105
  forfeits: number;
11115
11106
  };
11116
11107
  ladders: {
11117
- ranked: {
11108
+ ranked?: {
11118
11109
  wins: number;
11119
11110
  losses: number;
11120
11111
  desertions: number;
11121
11112
  byes: number;
11122
11113
  forfeits: number;
11123
- };
11124
- unranked: {
11114
+ } | undefined;
11115
+ unranked?: {
11125
11116
  wins: number;
11126
11117
  losses: number;
11127
11118
  desertions: number;
11128
11119
  byes: number;
11129
11120
  forfeits: number;
11130
- };
11121
+ } | undefined;
11131
11122
  };
11132
11123
  games: {
11133
11124
  id: string;
@@ -11143,6 +11134,12 @@ declare class GuildApi extends ApiBase {
11143
11134
  rating_change: number;
11144
11135
  season?: string | undefined;
11145
11136
  }[];
11137
+ seasons?: {
11138
+ id: string;
11139
+ rating: number;
11140
+ wins: number;
11141
+ losses: number;
11142
+ }[] | undefined;
11146
11143
  }[]>;
11147
11144
  /**
11148
11145
  * Returns information about the items in a guild's treasury.
package/dist/index.js CHANGED
@@ -114,8 +114,6 @@ var ApiBase = class {
114
114
  }
115
115
  /**
116
116
  * Parameters for the api response, at top level
117
- *
118
- * @returns Api parameters
119
117
  */
120
118
  getParams() {
121
119
  return {
@@ -133,8 +131,9 @@ var ApiBase = class {
133
131
  * @param endpoint - API Endpoint
134
132
  * @param apiParams - Query string
135
133
  * @param responseType - Type of the response
134
+ * @param attempts - Previously failed retry count
136
135
  */
137
- async buildRequest(endpoint, apiParams, responseType) {
136
+ async buildRequest(endpoint, apiParams, responseType, attempts) {
138
137
  const { tokenRequired } = endpoint;
139
138
  const url = this._getApiUrl(endpoint, apiParams);
140
139
  const headers = new axios.AxiosHeaders();
@@ -163,46 +162,61 @@ var ApiBase = class {
163
162
  }
164
163
  return data;
165
164
  } catch (error) {
166
- return await this.retryRequest(endpoint, options, responseType, apiParams, error);
165
+ return await this.retryRequest(endpoint, options, responseType, apiParams, attempts ?? 0, error);
167
166
  }
168
167
  }
169
168
  /**
170
169
  * Retries failed requests
171
- * TODO: Fix logic. Rate-limits are almost impossible hit, but other generic requests will fail and loop forever
172
170
  *
173
171
  * @param endpoint - Endpoint to which a request was originally made
174
172
  * @param prevOptions - Axios request options
175
173
  * @param responseType - Originally requested schema
176
174
  * @param apiParams - Query string
175
+ * @param rateLimitAttempt - Current rate-limit retry counter
177
176
  * @param prevError - Error that caused a retry
178
- * @returns Successful request, or error
179
177
  */
180
- async retryRequest(endpoint, prevOptions, responseType, apiParams, prevError) {
181
- if (prevError instanceof axios.AxiosError) {
182
- if (prevError.response) {
183
- const { status } = prevError.response;
184
- if (status === 401) {
178
+ async retryRequest(endpoint, prevOptions, responseType, apiParams, rateLimitAttempt, prevError) {
179
+ if (prevError instanceof axios.AxiosError && prevError.response) {
180
+ const { status } = prevError.response;
181
+ switch (true) {
182
+ case status === 401: {
185
183
  logger.warn(`Request to ${prevOptions.url} failed.`);
186
184
  throw new ApiTokenError();
187
185
  }
188
- if (status === 403) {
186
+ case status === 403: {
189
187
  const requiredScope = prevError.response.data.text.slice(0, 1).toUpperCase() + prevError.response.data.text.slice(1);
190
188
  logger.warn(`Request to ${prevOptions.url} failed. ${requiredScope}.`);
191
189
  throw new ApiPermissionsError(requiredScope);
192
190
  }
193
- if (status === 404) {
191
+ case status === 404: {
194
192
  logger.warn(`Request to ${prevOptions.url} returned no data.`);
195
193
  throw new ApiNotFoundError();
196
194
  }
197
- if (status === 504) {
195
+ case status === 429: {
196
+ if (!this._rateLimitRetry) {
197
+ logger.warn("Rate-limit has been reached, but retries were turned off. Stopping here.");
198
+ throw new ApiRetryFailedError();
199
+ }
200
+ if (rateLimitAttempt < 3) {
201
+ logger.warn(
202
+ // biome-ignore lint/style/noNonNullAssertion: <This will always be present>
203
+ `Rate-limit has been reached. Request to ${prevOptions.url} will be repeated in 30 seconds.`
204
+ );
205
+ await new Promise((resolve) => setTimeout(() => resolve(), 3e4));
206
+ return await this.buildRequest(endpoint, apiParams, responseType, ++rateLimitAttempt);
207
+ } else {
208
+ logger.error(`Rate-limit retries failed. Aborting request to ${prevOptions.url}`);
209
+ throw new ApiRetryFailedError();
210
+ }
211
+ }
212
+ case status === 504: {
198
213
  logger.warn(`Request to ${prevOptions.url} timed out.`);
199
214
  throw new ApiTimeoutError();
200
215
  }
216
+ default:
217
+ logger.warn(`Request to ${prevOptions.url} failed. ${prevError.message}`);
218
+ throw new ApiGenericError();
201
219
  }
202
- logger.warn(`Request to ${prevOptions.url} failed. ${prevError.message}`);
203
- } else if (this._rateLimitRetry) {
204
- logger.info(`Rate-limit retries failed. Aborting request to ${prevOptions.url}`);
205
- throw new ApiRetryFailedError();
206
220
  }
207
221
  throw new ApiGenericError();
208
222
  }
@@ -211,7 +225,6 @@ var ApiBase = class {
211
225
  *
212
226
  * @param endpoint - Api endpoint
213
227
  * @param urlParams - Parameters
214
- * @returns Finalized endpoint Url
215
228
  */
216
229
  _getApiUrl(endpoint, urlParams) {
217
230
  const { path } = endpoint;
@@ -1550,9 +1563,9 @@ var GuildTeamsDTO = zod.z.array(
1550
1563
  /** Team ladder statistics aggregates. */
1551
1564
  ladders: zod.z.object({
1552
1565
  /** Ranked arena stats. */
1553
- ranked: PvPAggregate,
1566
+ ranked: PvPAggregate.optional(),
1554
1567
  /** Unranked arena stats. */
1555
- unranked: PvPAggregate
1568
+ unranked: PvPAggregate.optional()
1556
1569
  }),
1557
1570
  /** Team games. */
1558
1571
  games: zod.z.array(PvPGame),
@@ -1568,7 +1581,7 @@ var GuildTeamsDTO = zod.z.array(
1568
1581
  /** Seasonal rating. */
1569
1582
  rating: zod.z.number()
1570
1583
  })
1571
- )
1584
+ ).optional()
1572
1585
  })
1573
1586
  );
1574
1587
  var GuildTreasuryDTO = zod.z.array(
@@ -1770,7 +1783,7 @@ var ColorsDTO = zod.z.array(
1770
1783
  /** ID of the dye item. */
1771
1784
  item: zod.z.number().optional(),
1772
1785
  /** Color categories. */
1773
- categories: zod.z.tuple([Hue, Material, Rarity]).optional()
1786
+ categories: zod.z.tuple([Hue, Material, Rarity]).or(zod.z.array(zod.z.undefined()).length(0))
1774
1787
  })
1775
1788
  );
1776
1789
  var EmblemDTO = zod.z.array(
@@ -6280,5 +6293,3 @@ exports.GW2Api = GW2Api;
6280
6293
  exports.LogLevel = LogLevel;
6281
6294
  exports.setLogLevel = setLogLevel;
6282
6295
  exports.setPathLogging = setPathLogging;
6283
- //# sourceMappingURL=out.js.map
6284
- //# sourceMappingURL=index.js.map
package/dist/index.mjs CHANGED
@@ -107,8 +107,6 @@ var ApiBase = class {
107
107
  }
108
108
  /**
109
109
  * Parameters for the api response, at top level
110
- *
111
- * @returns Api parameters
112
110
  */
113
111
  getParams() {
114
112
  return {
@@ -126,8 +124,9 @@ var ApiBase = class {
126
124
  * @param endpoint - API Endpoint
127
125
  * @param apiParams - Query string
128
126
  * @param responseType - Type of the response
127
+ * @param attempts - Previously failed retry count
129
128
  */
130
- async buildRequest(endpoint, apiParams, responseType) {
129
+ async buildRequest(endpoint, apiParams, responseType, attempts) {
131
130
  const { tokenRequired } = endpoint;
132
131
  const url = this._getApiUrl(endpoint, apiParams);
133
132
  const headers = new AxiosHeaders();
@@ -156,46 +155,61 @@ var ApiBase = class {
156
155
  }
157
156
  return data;
158
157
  } catch (error) {
159
- return await this.retryRequest(endpoint, options, responseType, apiParams, error);
158
+ return await this.retryRequest(endpoint, options, responseType, apiParams, attempts ?? 0, error);
160
159
  }
161
160
  }
162
161
  /**
163
162
  * Retries failed requests
164
- * TODO: Fix logic. Rate-limits are almost impossible hit, but other generic requests will fail and loop forever
165
163
  *
166
164
  * @param endpoint - Endpoint to which a request was originally made
167
165
  * @param prevOptions - Axios request options
168
166
  * @param responseType - Originally requested schema
169
167
  * @param apiParams - Query string
168
+ * @param rateLimitAttempt - Current rate-limit retry counter
170
169
  * @param prevError - Error that caused a retry
171
- * @returns Successful request, or error
172
170
  */
173
- async retryRequest(endpoint, prevOptions, responseType, apiParams, prevError) {
174
- if (prevError instanceof AxiosError) {
175
- if (prevError.response) {
176
- const { status } = prevError.response;
177
- if (status === 401) {
171
+ async retryRequest(endpoint, prevOptions, responseType, apiParams, rateLimitAttempt, prevError) {
172
+ if (prevError instanceof AxiosError && prevError.response) {
173
+ const { status } = prevError.response;
174
+ switch (true) {
175
+ case status === 401: {
178
176
  logger.warn(`Request to ${prevOptions.url} failed.`);
179
177
  throw new ApiTokenError();
180
178
  }
181
- if (status === 403) {
179
+ case status === 403: {
182
180
  const requiredScope = prevError.response.data.text.slice(0, 1).toUpperCase() + prevError.response.data.text.slice(1);
183
181
  logger.warn(`Request to ${prevOptions.url} failed. ${requiredScope}.`);
184
182
  throw new ApiPermissionsError(requiredScope);
185
183
  }
186
- if (status === 404) {
184
+ case status === 404: {
187
185
  logger.warn(`Request to ${prevOptions.url} returned no data.`);
188
186
  throw new ApiNotFoundError();
189
187
  }
190
- if (status === 504) {
188
+ case status === 429: {
189
+ if (!this._rateLimitRetry) {
190
+ logger.warn("Rate-limit has been reached, but retries were turned off. Stopping here.");
191
+ throw new ApiRetryFailedError();
192
+ }
193
+ if (rateLimitAttempt < 3) {
194
+ logger.warn(
195
+ // biome-ignore lint/style/noNonNullAssertion: <This will always be present>
196
+ `Rate-limit has been reached. Request to ${prevOptions.url} will be repeated in 30 seconds.`
197
+ );
198
+ await new Promise((resolve) => setTimeout(() => resolve(), 3e4));
199
+ return await this.buildRequest(endpoint, apiParams, responseType, ++rateLimitAttempt);
200
+ } else {
201
+ logger.error(`Rate-limit retries failed. Aborting request to ${prevOptions.url}`);
202
+ throw new ApiRetryFailedError();
203
+ }
204
+ }
205
+ case status === 504: {
191
206
  logger.warn(`Request to ${prevOptions.url} timed out.`);
192
207
  throw new ApiTimeoutError();
193
208
  }
209
+ default:
210
+ logger.warn(`Request to ${prevOptions.url} failed. ${prevError.message}`);
211
+ throw new ApiGenericError();
194
212
  }
195
- logger.warn(`Request to ${prevOptions.url} failed. ${prevError.message}`);
196
- } else if (this._rateLimitRetry) {
197
- logger.info(`Rate-limit retries failed. Aborting request to ${prevOptions.url}`);
198
- throw new ApiRetryFailedError();
199
213
  }
200
214
  throw new ApiGenericError();
201
215
  }
@@ -204,7 +218,6 @@ var ApiBase = class {
204
218
  *
205
219
  * @param endpoint - Api endpoint
206
220
  * @param urlParams - Parameters
207
- * @returns Finalized endpoint Url
208
221
  */
209
222
  _getApiUrl(endpoint, urlParams) {
210
223
  const { path } = endpoint;
@@ -1543,9 +1556,9 @@ var GuildTeamsDTO = z.array(
1543
1556
  /** Team ladder statistics aggregates. */
1544
1557
  ladders: z.object({
1545
1558
  /** Ranked arena stats. */
1546
- ranked: PvPAggregate,
1559
+ ranked: PvPAggregate.optional(),
1547
1560
  /** Unranked arena stats. */
1548
- unranked: PvPAggregate
1561
+ unranked: PvPAggregate.optional()
1549
1562
  }),
1550
1563
  /** Team games. */
1551
1564
  games: z.array(PvPGame),
@@ -1561,7 +1574,7 @@ var GuildTeamsDTO = z.array(
1561
1574
  /** Seasonal rating. */
1562
1575
  rating: z.number()
1563
1576
  })
1564
- )
1577
+ ).optional()
1565
1578
  })
1566
1579
  );
1567
1580
  var GuildTreasuryDTO = z.array(
@@ -1763,7 +1776,7 @@ var ColorsDTO = z.array(
1763
1776
  /** ID of the dye item. */
1764
1777
  item: z.number().optional(),
1765
1778
  /** Color categories. */
1766
- categories: z.tuple([Hue, Material, Rarity]).optional()
1779
+ categories: z.tuple([Hue, Material, Rarity]).or(z.array(z.undefined()).length(0))
1767
1780
  })
1768
1781
  );
1769
1782
  var EmblemDTO = z.array(
@@ -6269,5 +6282,3 @@ var GW2Api = class extends ApiBase {
6269
6282
  };
6270
6283
 
6271
6284
  export { ApiLanguage, GW2Api, LogLevel, setLogLevel, setPathLogging };
6272
- //# sourceMappingURL=out.js.map
6273
- //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guildwars2-ts",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "GuildWars 2 API Wrapper in Typescript",
5
5
  "homepage": "https://gitlab.com/dinckelman/guildwars2-ts",
6
6
  "main": "dist/index.js",
@@ -12,10 +12,6 @@
12
12
  "README.md",
13
13
  "package.json"
14
14
  ],
15
- "author": {
16
- "name": "Ivan Sosnov",
17
- "email": "dinckel@dinckelman.xyz"
18
- },
19
15
  "license": "ISC",
20
16
  "keywords": [
21
17
  "guildwars",