@blizzard-api/client 2.0.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -33,8 +33,8 @@ const client = await createBlizzardApiClient({
33
33
  //Response will automatically be typed with the appropriate values
34
34
  const response = await client.sendRequest(wow.commodities());
35
35
 
36
- console.log(response.data);
37
- ^ typeof AuctionHouseCommoditiesResponse
36
+ console.log(response);
37
+ ^ typeof AuctionHouseCommoditiesResponse
38
38
  ```
39
39
 
40
40
  ## Authentication
package/dist/index.d.ts CHANGED
@@ -1,15 +1,9 @@
1
1
  import { Origins, Locales, Resource, ResourceResponse } from '@blizzard-api/core';
2
- import { AxiosResponse } from 'axios';
3
2
 
4
3
  /**
5
4
  * An access token response from the Blizzard API.
6
5
  * @see https://develop.battle.net/documentation/guides/using-oauth
7
6
  * @see https://develop.battle.net/documentation/guides/using-oauth/client-credentials-flow¨
8
- * @interface AccessToken
9
- * @property access_token The access token.
10
- * @property token_type The type of token.
11
- * @property expires_in The time in seconds until the token expires.
12
- * @property sub The subject (unique user identifier) of the token.
13
7
  * @example
14
8
  * const response: AccessToken = {
15
9
  * access_token: 'access-token',
@@ -27,10 +21,6 @@ interface AccessToken {
27
21
  /**
28
22
  * An access token request.
29
23
  * @see https://develop.battle.net/documentation/guides/using-oauth/client-credentials-flow
30
- * @interface AccessTokenRequestArguments
31
- * @property origin The region to request the access token from.
32
- * @property key The client ID.
33
- * @property secret The client secret.
34
24
  * @example
35
25
  * const request: AccessTokenRequestArguments = {
36
26
  * origin: 'eu',
@@ -43,14 +33,16 @@ interface AccessTokenRequestArguments {
43
33
  origin?: Origins;
44
34
  secret?: string;
45
35
  }
36
+ type AxiosCompatability<T> = T & {
37
+ /**
38
+ * @deprecated
39
+ * This property is only here for backward compatibility, it will be removed in the next major version.
40
+ * All data should be accessed directly from the response object instead of through this property.
41
+ */
42
+ data: T;
43
+ };
46
44
  /**
47
45
  * A client configuration object.
48
- * @interface ClientOptions
49
- * @property key The client ID.
50
- * @property secret The client secret.
51
- * @property origin The region of the Blizzard API.
52
- * @property locale The locale of the Blizzard API.
53
- * @property token The access token.
54
46
  * @example
55
47
  * const options: ClientOptions = {
56
48
  * key: 'client',
@@ -69,24 +61,16 @@ interface ClientOptions {
69
61
  }
70
62
  /**
71
63
  * A Blizzard API client.
72
- * @interface IBlizzardApiClient
73
- * @property getAccessToken Get an access token.
74
- * @property setAccessToken Set an access token.
75
- * @property refreshAccessToken Refresh an access token.
76
- * @property validateAccessToken Validate an access token.
77
64
  */
78
65
  interface IBlizzardApiClient {
79
- getAccessToken: (options: AccessTokenRequestArguments) => Promise<AxiosResponse<AccessToken>>;
80
- refreshAccessToken: (options: AccessTokenRequestArguments) => Promise<AxiosResponse<AccessToken>>;
66
+ getAccessToken: (options: AccessTokenRequestArguments) => Promise<AxiosCompatability<AccessToken>>;
67
+ refreshAccessToken: (options: AccessTokenRequestArguments) => Promise<AxiosCompatability<AccessToken>>;
81
68
  setAccessToken: (token: string) => void;
82
- validateAccessToken: (options: ValidateAccessTokenArguments) => Promise<AxiosResponse<ValidateAccessTokenResponse>>;
69
+ validateAccessToken: (options: ValidateAccessTokenArguments) => Promise<AxiosCompatability<ValidateAccessTokenResponse>>;
83
70
  }
84
71
  /**
85
72
  * Validate an access token.
86
73
  * @see https://develop.battle.net/documentation/guides/using-oauth/client-credentials-flow
87
- * @interface ValidateAccessTokenArguments
88
- * @property origin The region to validate the access token from.
89
- * @property token The access token to validate.
90
74
  * @example
91
75
  * const request: ValidateAccessTokenArguments = {
92
76
  * origin: 'eu',
@@ -100,13 +84,6 @@ interface ValidateAccessTokenArguments {
100
84
  /**
101
85
  * A response from validating an access token.
102
86
  * @see https://develop.battle.net/documentation/guides/using-oauth/client-credentials-flow
103
- * @interface ValidateAccessTokenResponse
104
- * @property scope The scope of the token.
105
- * @property account_authorities The account authorities.
106
- * @property exp The expiration time of the token.
107
- * @property client_authorities The client authorities.
108
- * @property authorities The authorities.
109
- * @property client_id The client ID.
110
87
  * @example
111
88
  * const response: ValidateAccessTokenResponse = {
112
89
  * scope: ['wow.profile'],
@@ -128,8 +105,6 @@ interface ValidateAccessTokenResponse {
128
105
 
129
106
  /**
130
107
  * A Blizzard API client.
131
- * @implements IBlizzardApiClient
132
- * @class
133
108
  * @classdesc A client to interact with the Blizzard API.
134
109
  * @example
135
110
  * const client = new BlizzardApiClient({
@@ -148,51 +123,51 @@ declare class BlizzardApiClient implements IBlizzardApiClient {
148
123
  secret: string;
149
124
  token?: string;
150
125
  };
151
- private axios;
126
+ private ky;
127
+ constructor(options: ClientOptions);
152
128
  /**
153
129
  * Get an access token.
154
130
  * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.
155
131
  * @returns The access token. See {@link AccessToken}.
156
132
  * @example
157
133
  * const response = await client.getAccessToken();
158
- * const { access_token, token_type, expires_in, sub } = response.data;
134
+ * const { access_token, token_type, expires_in, sub } = response;
159
135
  * console.log(access_token, token_type, expires_in, sub);
160
136
  * // => 'access'
161
137
  * // => 'bearer'
162
138
  * // => 86399
163
139
  * // => 'client-id'
164
140
  */
165
- getAccessToken: (options?: AccessTokenRequestArguments) => Promise<AxiosResponse<AccessToken>>;
141
+ getAccessToken: (options?: AccessTokenRequestArguments) => Promise<AxiosCompatability<AccessToken>>;
142
+ /**
143
+ * Set the access token.
144
+ * @param token The access token.
145
+ */
146
+ setAccessToken: (token: string) => void;
166
147
  /**
167
148
  * Refresh the access token.
168
149
  * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.
169
150
  * @returns The access token. See {@link AccessToken}.
170
151
  * @example
171
152
  * const response = await client.refreshAccessToken();
172
- * const { access_token, token_type, expires_in, sub } = response.data;
153
+ * const { access_token, token_type, expires_in, sub } = response;
173
154
  * console.log(access_token, token_type, expires_in, sub);
174
155
  * // => 'access'
175
156
  * // => 'bearer'
176
157
  * // => 86399
177
158
  * // => 'client-id'
178
159
  */
179
- refreshAccessToken: (options?: AccessTokenRequestArguments) => Promise<AxiosResponse<AccessToken>>;
180
- /**
181
- * Set the access token.
182
- * @param token The access token.
183
- */
184
- setAccessToken: (token: string) => void;
160
+ refreshAccessToken: (options?: AccessTokenRequestArguments) => Promise<AxiosCompatability<AccessToken>>;
185
161
  /**
186
162
  * Validate an access token.
187
163
  * @param options The validate access token arguments. See {@link ValidateAccessTokenArguments}.
188
164
  * @returns The response from the Blizzard API. See {@link ValidateAccessTokenResponse}.
189
165
  * @example
190
166
  * const response = await client.validateAccessToken({ token: 'access' });
191
- * console.log(response.data.client_id);
167
+ * console.log(response.client_id);
192
168
  * // => 'client-id'
193
169
  */
194
- constructor(options: ClientOptions);
195
- validateAccessToken: (options?: ValidateAccessTokenArguments) => Promise<AxiosResponse<ValidateAccessTokenResponse>>;
170
+ validateAccessToken: (options?: ValidateAccessTokenArguments) => Promise<AxiosCompatability<ValidateAccessTokenResponse>>;
196
171
  /**
197
172
  * Get the request configuration.
198
173
  * @param resource The resource to fetch. See {@link Resource}.
@@ -206,7 +181,7 @@ declare class BlizzardApiClient implements IBlizzardApiClient {
206
181
  'Content-Type': string;
207
182
  'Battlenet-Namespace'?: string | undefined;
208
183
  };
209
- params: {
184
+ searchParams: {
210
185
  locale: "de_DE" | "en_GB" | "en_US" | "es_ES" | "es_MX" | "fr_FR" | "it_IT" | "ko_KR" | "multi" | "pt_BR" | "pt_PT" | "ru_RU" | "zh_CN" | "zh_TW";
211
186
  };
212
187
  };
@@ -224,7 +199,7 @@ declare class BlizzardApiClient implements IBlizzardApiClient {
224
199
  * @param headers Additional headers to include in the request.
225
200
  * @returns The response from the Blizzard API. See {@link ResourceResponse}.
226
201
  */
227
- sendRequest<T, Protected extends boolean = false>(resource: Resource<T, object, Protected>, options?: Partial<ClientOptions>, headers?: Record<string, string>): ResourceResponse<AxiosResponse<T>>;
202
+ sendRequest<T, Protected extends boolean = false>(resource: Resource<T, object, Protected>, options?: Partial<ClientOptions>, headers?: Record<string, string>): ResourceResponse<AxiosCompatability<T>>;
228
203
  }
229
204
 
230
205
  /**
@@ -235,4 +210,4 @@ declare class BlizzardApiClient implements IBlizzardApiClient {
235
210
  */
236
211
  declare const createBlizzardApiClient: (options: ClientOptions, onTokenRefresh?: ((token: AccessToken) => void) | boolean) => Promise<BlizzardApiClient>;
237
212
 
238
- export { type AccessToken, type AccessTokenRequestArguments, type ClientOptions, type IBlizzardApiClient, type ValidateAccessTokenArguments, type ValidateAccessTokenResponse, createBlizzardApiClient, createBlizzardApiClient as default };
213
+ export { type AccessToken, type AccessTokenRequestArguments, type AxiosCompatability, type ClientOptions, type IBlizzardApiClient, type ValidateAccessTokenArguments, type ValidateAccessTokenResponse, createBlizzardApiClient, createBlizzardApiClient as default };
package/dist/index.js CHANGED
@@ -1,19 +1,29 @@
1
1
  import { setTimeout } from 'node:timers';
2
2
  import { stringify } from 'node:querystring';
3
3
  import { getBlizzardApi } from '@blizzard-api/core';
4
- import axios, { isAxiosError, AxiosError } from 'axios';
4
+ import ky from 'ky';
5
5
 
6
6
  // src/client/create-client.ts
7
7
  var BlizzardApiClient = class {
8
8
  defaults;
9
- axios = axios.create();
9
+ ky = ky.create();
10
+ constructor(options) {
11
+ const { locale, origin } = getBlizzardApi(options.origin, options.locale);
12
+ this.defaults = {
13
+ key: options.key,
14
+ locale,
15
+ origin,
16
+ secret: options.secret,
17
+ token: options.token
18
+ };
19
+ }
10
20
  /**
11
21
  * Get an access token.
12
22
  * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.
13
23
  * @returns The access token. See {@link AccessToken}.
14
24
  * @example
15
25
  * const response = await client.getAccessToken();
16
- * const { access_token, token_type, expires_in, sub } = response.data;
26
+ * const { access_token, token_type, expires_in, sub } = response;
17
27
  * console.log(access_token, token_type, expires_in, sub);
18
28
  * // => 'access'
19
29
  * // => 'bearer'
@@ -22,18 +32,27 @@ var BlizzardApiClient = class {
22
32
  */
23
33
  getAccessToken = async (options) => {
24
34
  const { key, origin, secret } = { ...this.defaults, ...options };
25
- return this.axios.post(`https://${origin}.battle.net/oauth/token`, void 0, {
26
- auth: {
27
- password: secret,
28
- username: key
29
- },
35
+ const basicAuth = Buffer.from(`${key}:${secret}`).toString("base64");
36
+ const response = await this.ky.post(`https://${origin}.battle.net/oauth/token`, {
30
37
  headers: {
38
+ Authorization: `Basic ${basicAuth}`,
31
39
  "Content-Type": "application/json"
32
40
  },
33
- params: {
41
+ searchParams: {
34
42
  grant_type: "client_credentials"
35
43
  }
36
- });
44
+ }).json();
45
+ return {
46
+ data: response,
47
+ ...response
48
+ };
49
+ };
50
+ /**
51
+ * Set the access token.
52
+ * @param token The access token.
53
+ */
54
+ setAccessToken = (token) => {
55
+ this.defaults.token = token;
37
56
  };
38
57
  /**
39
58
  * Refresh the access token.
@@ -41,7 +60,7 @@ var BlizzardApiClient = class {
41
60
  * @returns The access token. See {@link AccessToken}.
42
61
  * @example
43
62
  * const response = await client.refreshAccessToken();
44
- * const { access_token, token_type, expires_in, sub } = response.data;
63
+ * const { access_token, token_type, expires_in, sub } = response;
45
64
  * console.log(access_token, token_type, expires_in, sub);
46
65
  * // => 'access'
47
66
  * // => 'bearer'
@@ -50,49 +69,33 @@ var BlizzardApiClient = class {
50
69
  */
51
70
  refreshAccessToken = async (options) => {
52
71
  const response = await this.getAccessToken(options);
53
- this.setAccessToken(response.data.access_token);
72
+ this.setAccessToken(response.access_token);
54
73
  return response;
55
74
  };
56
- /**
57
- * Set the access token.
58
- * @param token The access token.
59
- */
60
- setAccessToken = (token) => {
61
- this.defaults.token = token;
62
- };
63
75
  /**
64
76
  * Validate an access token.
65
77
  * @param options The validate access token arguments. See {@link ValidateAccessTokenArguments}.
66
78
  * @returns The response from the Blizzard API. See {@link ValidateAccessTokenResponse}.
67
79
  * @example
68
80
  * const response = await client.validateAccessToken({ token: 'access' });
69
- * console.log(response.data.client_id);
81
+ * console.log(response.client_id);
70
82
  * // => 'client-id'
71
83
  */
72
- constructor(options) {
73
- const { locale, origin } = getBlizzardApi(options.origin, options.locale);
74
- this.defaults = {
75
- key: options.key,
76
- locale,
77
- origin,
78
- secret: options.secret,
79
- token: options.token
80
- };
81
- }
82
84
  validateAccessToken = async (options) => {
83
85
  const { origin, token } = { ...this.defaults, ...options };
84
86
  if (!token) {
85
87
  throw new Error("No token has been set previously or been passed to the validateAccessToken method.");
86
88
  }
87
- return await this.axios.post(
88
- `https://${origin}.battle.net/oauth/check_token`,
89
- stringify({ token }),
90
- {
91
- headers: {
92
- "Content-Type": "application/x-www-form-urlencoded"
93
- }
89
+ const response = await this.ky.post(`https://${origin}.battle.net/oauth/check_token`, {
90
+ body: stringify({ token }),
91
+ headers: {
92
+ "Content-Type": "application/x-www-form-urlencoded"
94
93
  }
95
- );
94
+ }).json();
95
+ return {
96
+ data: response,
97
+ ...response
98
+ };
96
99
  };
97
100
  /**
98
101
  * Get the request configuration.
@@ -105,6 +108,14 @@ var BlizzardApiClient = class {
105
108
  const config = { ...this.defaults, ...options };
106
109
  const endpoint = getBlizzardApi(config.origin, config.locale);
107
110
  const namespace = resource.namespace ? { "Battlenet-Namespace": `${resource.namespace}-${endpoint.origin}` } : void 0;
111
+ const parameters = resource.parameters;
112
+ if (parameters) {
113
+ for (const key of Object.keys(parameters)) {
114
+ if (parameters[key] === void 0) {
115
+ delete parameters[key];
116
+ }
117
+ }
118
+ }
108
119
  return {
109
120
  headers: {
110
121
  ...headers,
@@ -112,7 +123,7 @@ var BlizzardApiClient = class {
112
123
  Authorization: `Bearer ${config.token}`,
113
124
  "Content-Type": "application/json"
114
125
  },
115
- params: {
126
+ searchParams: {
116
127
  locale: endpoint.locale,
117
128
  ...resource.parameters
118
129
  }
@@ -140,14 +151,11 @@ var BlizzardApiClient = class {
140
151
  async sendRequest(resource, options, headers) {
141
152
  const url = this.getRequestUrl(resource, options);
142
153
  const config = this.getRequestConfig(resource, options, headers);
143
- try {
144
- return await this.axios.get(url, config);
145
- } catch (error) {
146
- if (isAxiosError(error)) {
147
- throw new AxiosError(error.message, error.code);
148
- }
149
- throw error;
150
- }
154
+ const response = await this.ky.get(url, config).json();
155
+ return {
156
+ data: response,
157
+ ...response
158
+ };
151
159
  }
152
160
  };
153
161
 
@@ -164,11 +172,11 @@ var createBlizzardApiClient = async (options, onTokenRefresh = true) => {
164
172
  const client = new BlizzardApiClient(options);
165
173
  const refreshToken = async () => {
166
174
  const response = await client.getAccessToken();
167
- client.setAccessToken(response.data.access_token);
175
+ client.setAccessToken(response.access_token);
168
176
  if (typeof onTokenRefresh === "function") {
169
- onTokenRefresh?.(response.data);
177
+ onTokenRefresh?.(response);
170
178
  }
171
- const timeout = setTimeout(() => void refreshToken(), getTokenExpiration(response.data.expires_in));
179
+ const timeout = setTimeout(() => void refreshToken(), getTokenExpiration(response.expires_in));
172
180
  timeout.unref();
173
181
  };
174
182
  if (!onTokenRefresh) {
@@ -177,7 +185,7 @@ var createBlizzardApiClient = async (options, onTokenRefresh = true) => {
177
185
  if (token) {
178
186
  try {
179
187
  const validatedToken = await client.validateAccessToken({ token });
180
- const expiry = getTokenExpiration(validatedToken.data.exp);
188
+ const expiry = getTokenExpiration(validatedToken.exp);
181
189
  if (expiry - Date.now() < 6e4) {
182
190
  await refreshToken();
183
191
  } else {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client/client.ts","../src/client/create-client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { stringify } from 'node:querystring';\r\nimport { getBlizzardApi } from '@blizzard-api/core';\r\nimport type { Locales, Origins, Resource, ResourceResponse } from '@blizzard-api/core';\r\nimport type { AxiosResponse } from 'axios';\r\nimport axios, { AxiosError, isAxiosError } from 'axios';\r\nimport type {\r\n AccessToken,\r\n AccessTokenRequestArguments,\r\n ClientOptions,\r\n IBlizzardApiClient,\r\n ValidateAccessTokenArguments,\r\n ValidateAccessTokenResponse,\r\n} from './types';\r\n\r\n/**\r\n * A Blizzard API client.\r\n * @implements IBlizzardApiClient\r\n * @class\r\n * @classdesc A client to interact with the Blizzard API.\r\n * @example\r\n * const client = new BlizzardApiClient({\r\n * key: 'client',\r\n * secret: 'secret',\r\n * origin: 'eu',\r\n * locale: 'en_GB',\r\n * token: 'access'\r\n * });\r\n */\r\nexport class BlizzardApiClient implements IBlizzardApiClient {\r\n public defaults: {\r\n key: string;\r\n locale: Locales;\r\n origin: Origins;\r\n secret: string;\r\n token?: string;\r\n };\r\n\r\n private axios = axios.create();\r\n\r\n /**\r\n * Get an access token.\r\n * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.\r\n * @returns The access token. See {@link AccessToken}.\r\n * @example\r\n * const response = await client.getAccessToken();\r\n * const { access_token, token_type, expires_in, sub } = response.data;\r\n * console.log(access_token, token_type, expires_in, sub);\r\n * // => 'access'\r\n * // => 'bearer'\r\n * // => 86399\r\n * // => 'client-id'\r\n */\r\n public getAccessToken = async (options?: AccessTokenRequestArguments): Promise<AxiosResponse<AccessToken>> => {\r\n const { key, origin, secret } = { ...this.defaults, ...options };\r\n return this.axios.post<AccessToken>(`https://${origin}.battle.net/oauth/token`, undefined, {\r\n auth: {\r\n password: secret,\r\n username: key,\r\n },\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n params: {\r\n grant_type: 'client_credentials',\r\n },\r\n });\r\n };\r\n\r\n /**\r\n * Refresh the access token.\r\n * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.\r\n * @returns The access token. See {@link AccessToken}.\r\n * @example\r\n * const response = await client.refreshAccessToken();\r\n * const { access_token, token_type, expires_in, sub } = response.data;\r\n * console.log(access_token, token_type, expires_in, sub);\r\n * // => 'access'\r\n * // => 'bearer'\r\n * // => 86399\r\n * // => 'client-id'\r\n */\r\n public refreshAccessToken = async (options?: AccessTokenRequestArguments): Promise<AxiosResponse<AccessToken>> => {\r\n const response = await this.getAccessToken(options);\r\n this.setAccessToken(response.data.access_token);\r\n return response;\r\n };\r\n\r\n /**\r\n * Set the access token.\r\n * @param token The access token.\r\n */\r\n public setAccessToken = (token: string): void => {\r\n this.defaults.token = token;\r\n };\r\n\r\n /**\r\n * Validate an access token.\r\n * @param options The validate access token arguments. See {@link ValidateAccessTokenArguments}.\r\n * @returns The response from the Blizzard API. See {@link ValidateAccessTokenResponse}.\r\n * @example\r\n * const response = await client.validateAccessToken({ token: 'access' });\r\n * console.log(response.data.client_id);\r\n * // => 'client-id'\r\n */\r\n constructor(options: ClientOptions) {\r\n const { locale, origin } = getBlizzardApi(options.origin, options.locale);\r\n this.defaults = {\r\n key: options.key,\r\n locale: locale,\r\n origin: origin,\r\n secret: options.secret,\r\n token: options.token,\r\n };\r\n }\r\n\r\n public validateAccessToken = async (\r\n options?: ValidateAccessTokenArguments,\r\n ): Promise<AxiosResponse<ValidateAccessTokenResponse>> => {\r\n const { origin, token } = { ...this.defaults, ...options };\r\n\r\n if (!token) {\r\n throw new Error('No token has been set previously or been passed to the validateAccessToken method.');\r\n }\r\n\r\n return await this.axios.post<ValidateAccessTokenResponse>(\r\n `https://${origin}.battle.net/oauth/check_token`,\r\n stringify({ token }),\r\n {\r\n headers: {\r\n 'Content-Type': 'application/x-www-form-urlencoded',\r\n },\r\n },\r\n );\r\n };\r\n\r\n /**\r\n * Get the request configuration.\r\n * @param resource The resource to fetch. See {@link Resource}.\r\n * @param options Client options. See {@link ClientOptions}.\r\n * @param headers Additional headers to include in the request.\r\n * @returns The request configuration.\r\n */\r\n public getRequestConfig<T, Protected extends boolean = false>(\r\n resource: Resource<T, object, Protected>,\r\n options?: Partial<ClientOptions>,\r\n headers?: Record<string, string>,\r\n ) {\r\n const config = { ...this.defaults, ...options };\r\n const endpoint = getBlizzardApi(config.origin, config.locale);\r\n\r\n const namespace = resource.namespace\r\n ? { 'Battlenet-Namespace': `${resource.namespace}-${endpoint.origin}` }\r\n : undefined;\r\n\r\n return {\r\n headers: {\r\n ...headers,\r\n ...namespace,\r\n Authorization: `Bearer ${config.token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n params: {\r\n locale: endpoint.locale,\r\n ...resource.parameters,\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Get the request URL.\r\n * @param resource The resource to fetch. See {@link Resource}.\r\n * @param options Client options. See {@link ClientOptions}.\r\n * @returns The request URL.\r\n */\r\n public getRequestUrl<T, Protected extends boolean = false>(\r\n resource: Resource<T, object, Protected>,\r\n options?: Partial<ClientOptions>,\r\n ) {\r\n const config = { ...this.defaults, ...options };\r\n const endpoint = getBlizzardApi(config.origin, config.locale);\r\n\r\n const backslashSeparator = resource.path.startsWith('/') ? '' : '/';\r\n\r\n return `${endpoint.hostname}${backslashSeparator}${resource.path}`;\r\n }\r\n\r\n /**\r\n * Send a request to the Blizzard API.\r\n * @param resource The resource to fetch. See {@link Resource}.\r\n * @param options Client options. See {@link ClientOptions}.\r\n * @param headers Additional headers to include in the request.\r\n * @returns The response from the Blizzard API. See {@link ResourceResponse}.\r\n */\r\n public async sendRequest<T, Protected extends boolean = false>(\r\n resource: Resource<T, object, Protected>,\r\n options?: Partial<ClientOptions>,\r\n headers?: Record<string, string>,\r\n ): ResourceResponse<AxiosResponse<T>> {\r\n const url = this.getRequestUrl(resource, options);\r\n const config = this.getRequestConfig(resource, options, headers);\r\n\r\n try {\r\n return await this.axios.get<T>(url, config);\r\n } catch (error) {\r\n if (isAxiosError(error)) {\r\n throw new AxiosError(error.message, error.code);\r\n }\r\n throw error;\r\n }\r\n }\r\n}\r\n","//We have to explicitly import setTimeout because of https://github.com/electron/electron/issues/21162#issuecomment-554792447\r\nimport { setTimeout } from 'node:timers';\r\nimport { BlizzardApiClient } from './client';\r\nimport type { AccessToken, ClientOptions } from './types';\r\n\r\nconst getTokenExpiration = (expiresIn: number) => expiresIn * 1000 - 60_000;\r\n\r\n/**\r\n * Create a new Blizzard API client.\r\n * @param options Client options, see {@link ClientOptions} & https://develop.battle.net/documentation/guides/getting-started\r\n * @param onTokenRefresh Callback function to handle token refresh. If set to `true`, the client will automatically refresh the token. If set to `false`, the client will not refresh the token. If set to a function, the function will be called with the new token.\r\n * @returns A new Blizzard API client.\r\n */\r\nexport const createBlizzardApiClient = async (\r\n options: ClientOptions,\r\n onTokenRefresh: ((token: AccessToken) => void) | boolean = true,\r\n): Promise<BlizzardApiClient> => {\r\n const { key, secret, token } = options;\r\n if (!key) {\r\n throw new Error(`Client missing 'key' parameter`);\r\n }\r\n if (!secret) {\r\n throw new Error(`Client missing 'secret' parameter`);\r\n }\r\n\r\n const client = new BlizzardApiClient(options);\r\n\r\n const refreshToken = async () => {\r\n const response = await client.getAccessToken();\r\n\r\n client.setAccessToken(response.data.access_token);\r\n\r\n if (typeof onTokenRefresh === 'function') {\r\n onTokenRefresh?.(response.data);\r\n }\r\n\r\n //Schedule a refresh of the token\r\n const timeout = setTimeout(() => void refreshToken(), getTokenExpiration(response.data.expires_in));\r\n timeout.unref();\r\n };\r\n\r\n //If tokenRefresh is false, return the client without refreshing the token\r\n if (!onTokenRefresh) {\r\n return client;\r\n }\r\n\r\n if (token) {\r\n try {\r\n //If token is set, validate the token\r\n const validatedToken = await client.validateAccessToken({ token });\r\n const expiry = getTokenExpiration(validatedToken.data.exp);\r\n //If token is expiring in less than 60 seconds, refresh the token\r\n if (expiry - Date.now() < 60_000) {\r\n await refreshToken();\r\n } else {\r\n //If token is not expiring, schedule a refresh\r\n const timeout = setTimeout(() => void refreshToken(), expiry - Date.now());\r\n //Unref the timeout so the process can exit\r\n timeout.unref();\r\n }\r\n } catch {\r\n //If token is invalid, refresh the token\r\n await refreshToken();\r\n }\r\n } else {\r\n //If token is not set, refresh the token\r\n await refreshToken();\r\n }\r\n\r\n return client;\r\n};\r\n"]}
1
+ {"version":3,"sources":["../src/client/client.ts","../src/client/create-client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { stringify } from 'node:querystring';\r\nimport { getBlizzardApi } from '@blizzard-api/core';\r\nimport type { Locales, Origins, Resource, ResourceResponse } from '@blizzard-api/core';\r\nimport ky from 'ky';\r\nimport type {\r\n AccessToken,\r\n AccessTokenRequestArguments,\r\n AxiosCompatability,\r\n ClientOptions,\r\n IBlizzardApiClient,\r\n ValidateAccessTokenArguments,\r\n ValidateAccessTokenResponse,\r\n} from './types';\r\n\r\n/**\r\n * A Blizzard API client.\r\n * @classdesc A client to interact with the Blizzard API.\r\n * @example\r\n * const client = new BlizzardApiClient({\r\n * key: 'client',\r\n * secret: 'secret',\r\n * origin: 'eu',\r\n * locale: 'en_GB',\r\n * token: 'access'\r\n * });\r\n */\r\nexport class BlizzardApiClient implements IBlizzardApiClient {\r\n public defaults: {\r\n key: string;\r\n locale: Locales;\r\n origin: Origins;\r\n secret: string;\r\n token?: string;\r\n };\r\n\r\n private ky = ky.create();\r\n\r\n constructor(options: ClientOptions) {\r\n const { locale, origin } = getBlizzardApi(options.origin, options.locale);\r\n this.defaults = {\r\n key: options.key,\r\n locale: locale,\r\n origin: origin,\r\n secret: options.secret,\r\n token: options.token,\r\n };\r\n }\r\n\r\n /**\r\n * Get an access token.\r\n * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.\r\n * @returns The access token. See {@link AccessToken}.\r\n * @example\r\n * const response = await client.getAccessToken();\r\n * const { access_token, token_type, expires_in, sub } = response;\r\n * console.log(access_token, token_type, expires_in, sub);\r\n * // => 'access'\r\n * // => 'bearer'\r\n * // => 86399\r\n * // => 'client-id'\r\n */\r\n public getAccessToken = async (options?: AccessTokenRequestArguments): Promise<AxiosCompatability<AccessToken>> => {\r\n const { key, origin, secret } = { ...this.defaults, ...options };\r\n const basicAuth = Buffer.from(`${key}:${secret}`).toString('base64');\r\n const response = await this.ky\r\n .post<AccessToken>(`https://${origin}.battle.net/oauth/token`, {\r\n headers: {\r\n Authorization: `Basic ${basicAuth}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n searchParams: {\r\n grant_type: 'client_credentials',\r\n },\r\n })\r\n .json();\r\n\r\n return {\r\n data: response,\r\n ...response,\r\n };\r\n };\r\n\r\n /**\r\n * Set the access token.\r\n * @param token The access token.\r\n */\r\n public setAccessToken = (token: string): void => {\r\n this.defaults.token = token;\r\n };\r\n\r\n /**\r\n * Refresh the access token.\r\n * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.\r\n * @returns The access token. See {@link AccessToken}.\r\n * @example\r\n * const response = await client.refreshAccessToken();\r\n * const { access_token, token_type, expires_in, sub } = response;\r\n * console.log(access_token, token_type, expires_in, sub);\r\n * // => 'access'\r\n * // => 'bearer'\r\n * // => 86399\r\n * // => 'client-id'\r\n */\r\n public refreshAccessToken = async (\r\n options?: AccessTokenRequestArguments,\r\n ): Promise<AxiosCompatability<AccessToken>> => {\r\n const response = await this.getAccessToken(options);\r\n this.setAccessToken(response.access_token);\r\n return response;\r\n };\r\n\r\n /**\r\n * Validate an access token.\r\n * @param options The validate access token arguments. See {@link ValidateAccessTokenArguments}.\r\n * @returns The response from the Blizzard API. See {@link ValidateAccessTokenResponse}.\r\n * @example\r\n * const response = await client.validateAccessToken({ token: 'access' });\r\n * console.log(response.client_id);\r\n * // => 'client-id'\r\n */\r\n public validateAccessToken = async (\r\n options?: ValidateAccessTokenArguments,\r\n ): Promise<AxiosCompatability<ValidateAccessTokenResponse>> => {\r\n const { origin, token } = { ...this.defaults, ...options };\r\n\r\n if (!token) {\r\n throw new Error('No token has been set previously or been passed to the validateAccessToken method.');\r\n }\r\n\r\n const response = await this.ky\r\n .post<ValidateAccessTokenResponse>(`https://${origin}.battle.net/oauth/check_token`, {\r\n body: stringify({ token }),\r\n headers: {\r\n 'Content-Type': 'application/x-www-form-urlencoded',\r\n },\r\n })\r\n .json();\r\n\r\n return {\r\n data: response,\r\n ...response,\r\n };\r\n };\r\n\r\n /**\r\n * Get the request configuration.\r\n * @param resource The resource to fetch. See {@link Resource}.\r\n * @param options Client options. See {@link ClientOptions}.\r\n * @param headers Additional headers to include in the request.\r\n * @returns The request configuration.\r\n */\r\n public getRequestConfig<T, Protected extends boolean = false>(\r\n resource: Resource<T, object, Protected>,\r\n options?: Partial<ClientOptions>,\r\n headers?: Record<string, string>,\r\n ) {\r\n const config = { ...this.defaults, ...options };\r\n const endpoint = getBlizzardApi(config.origin, config.locale);\r\n\r\n const namespace = resource.namespace\r\n ? { 'Battlenet-Namespace': `${resource.namespace}-${endpoint.origin}` }\r\n : undefined;\r\n\r\n const parameters = resource.parameters as Record<string, unknown>;\r\n if (parameters) {\r\n for (const key of Object.keys(parameters)) {\r\n if (parameters[key] === undefined) {\r\n delete parameters[key];\r\n }\r\n }\r\n }\r\n\r\n return {\r\n headers: {\r\n ...headers,\r\n ...namespace,\r\n Authorization: `Bearer ${config.token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n searchParams: {\r\n locale: endpoint.locale,\r\n ...resource.parameters,\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Get the request URL.\r\n * @param resource The resource to fetch. See {@link Resource}.\r\n * @param options Client options. See {@link ClientOptions}.\r\n * @returns The request URL.\r\n */\r\n public getRequestUrl<T, Protected extends boolean = false>(\r\n resource: Resource<T, object, Protected>,\r\n options?: Partial<ClientOptions>,\r\n ) {\r\n const config = { ...this.defaults, ...options };\r\n const endpoint = getBlizzardApi(config.origin, config.locale);\r\n\r\n const backslashSeparator = resource.path.startsWith('/') ? '' : '/';\r\n\r\n return `${endpoint.hostname}${backslashSeparator}${resource.path}`;\r\n }\r\n\r\n /**\r\n * Send a request to the Blizzard API.\r\n * @param resource The resource to fetch. See {@link Resource}.\r\n * @param options Client options. See {@link ClientOptions}.\r\n * @param headers Additional headers to include in the request.\r\n * @returns The response from the Blizzard API. See {@link ResourceResponse}.\r\n */\r\n public async sendRequest<T, Protected extends boolean = false>(\r\n resource: Resource<T, object, Protected>,\r\n options?: Partial<ClientOptions>,\r\n headers?: Record<string, string>,\r\n ): ResourceResponse<AxiosCompatability<T>> {\r\n const url = this.getRequestUrl(resource, options);\r\n const config = this.getRequestConfig(resource, options, headers);\r\n\r\n const response = await this.ky.get<T>(url, config).json();\r\n return {\r\n data: response,\r\n ...response,\r\n };\r\n }\r\n}\r\n","//We have to explicitly import setTimeout because of https://github.com/electron/electron/issues/21162#issuecomment-554792447\r\nimport { setTimeout } from 'node:timers';\r\nimport { BlizzardApiClient } from './client';\r\nimport type { AccessToken, ClientOptions } from './types';\r\n\r\nconst getTokenExpiration = (expiresIn: number) => expiresIn * 1000 - 60_000;\r\n\r\n/**\r\n * Create a new Blizzard API client.\r\n * @param options Client options, see {@link ClientOptions} & https://develop.battle.net/documentation/guides/getting-started\r\n * @param onTokenRefresh Callback function to handle token refresh. If set to `true`, the client will automatically refresh the token. If set to `false`, the client will not refresh the token. If set to a function, the function will be called with the new token.\r\n * @returns A new Blizzard API client.\r\n */\r\nexport const createBlizzardApiClient = async (\r\n options: ClientOptions,\r\n onTokenRefresh: ((token: AccessToken) => void) | boolean = true,\r\n): Promise<BlizzardApiClient> => {\r\n const { key, secret, token } = options;\r\n if (!key) {\r\n throw new Error(`Client missing 'key' parameter`);\r\n }\r\n if (!secret) {\r\n throw new Error(`Client missing 'secret' parameter`);\r\n }\r\n\r\n const client = new BlizzardApiClient(options);\r\n\r\n const refreshToken = async () => {\r\n const response = await client.getAccessToken();\r\n\r\n client.setAccessToken(response.access_token);\r\n\r\n if (typeof onTokenRefresh === 'function') {\r\n onTokenRefresh?.(response);\r\n }\r\n\r\n //Schedule a refresh of the token\r\n const timeout = setTimeout(() => void refreshToken(), getTokenExpiration(response.expires_in));\r\n timeout.unref();\r\n };\r\n\r\n //If tokenRefresh is false, return the client without refreshing the token\r\n if (!onTokenRefresh) {\r\n return client;\r\n }\r\n\r\n if (token) {\r\n try {\r\n //If token is set, validate the token\r\n const validatedToken = await client.validateAccessToken({ token });\r\n const expiry = getTokenExpiration(validatedToken.exp);\r\n //If token is expiring in less than 60 seconds, refresh the token\r\n if (expiry - Date.now() < 60_000) {\r\n await refreshToken();\r\n } else {\r\n //If token is not expiring, schedule a refresh\r\n const timeout = setTimeout(() => void refreshToken(), expiry - Date.now());\r\n //Unref the timeout so the process can exit\r\n timeout.unref();\r\n }\r\n } catch {\r\n //If token is invalid, refresh the token\r\n await refreshToken();\r\n }\r\n } else {\r\n //If token is not set, refresh the token\r\n await refreshToken();\r\n }\r\n\r\n return client;\r\n};\r\n"]}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@blizzard-api/client",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "license": "MIT",
5
5
  "author": "Putro",
6
- "description": "A node.js axios client to integrate with the blizzard battle.net api.",
6
+ "description": "A node.js client to integrate with the blizzard battle.net api.",
7
7
  "repository": "https://github.com/Pewtro/blizzard-api/tree/main/packages/client",
8
8
  "type": "module",
9
9
  "engines": {
@@ -40,18 +40,18 @@
40
40
  "hearthstone"
41
41
  ],
42
42
  "dependencies": {
43
- "axios": "1.7.9"
43
+ "ky": "1.7.5"
44
44
  },
45
45
  "peerDependencies": {
46
- "@blizzard-api/core": "2.0.1"
46
+ "@blizzard-api/core": "2.0.2"
47
47
  },
48
48
  "devDependencies": {
49
- "@blizzard-api/classic-wow": "2.0.1",
50
- "@blizzard-api/core": "2.0.1",
51
- "@blizzard-api/hs": "1.0.1",
52
- "@blizzard-api/d3": "1.0.1",
53
- "@blizzard-api/sc2": "1.0.1",
54
- "@blizzard-api/wow": "2.0.1"
49
+ "@blizzard-api/classic-wow": "2.0.3",
50
+ "@blizzard-api/core": "2.0.2",
51
+ "@blizzard-api/d3": "1.0.3",
52
+ "@blizzard-api/hs": "1.0.3",
53
+ "@blizzard-api/sc2": "1.0.3",
54
+ "@blizzard-api/wow": "2.0.3"
55
55
  },
56
56
  "scripts": {
57
57
  "build": "tsup",