@blizzard-api/client 2.1.3 → 2.2.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/dist/index.d.ts CHANGED
@@ -1,5 +1,19 @@
1
- import { Locales, Origins, Resource, ResourceResponse } from '@blizzard-api/core';
1
+ import { Locales, Origins, Resource, ResourceResponse, getBlizzardApi } from "@blizzard-api/core";
2
+ import { Options } from "ky";
2
3
 
4
+ //#region src/client/types.d.ts
5
+ /**
6
+ * An access token response from the Blizzard API.
7
+ * @see https://develop.battle.net/documentation/guides/using-oauth
8
+ * @see https://develop.battle.net/documentation/guides/using-oauth/client-credentials-flow¨
9
+ * @example
10
+ * const response: AccessToken = {
11
+ * access_token: 'access-token',
12
+ * token_type: 'bearer',
13
+ * expires_in: 86399,
14
+ * sub: 'client-id',
15
+ * };
16
+ */
3
17
  /**
4
18
  * An access token response from the Blizzard API.
5
19
  * @see https://develop.battle.net/documentation/guides/using-oauth
@@ -13,10 +27,10 @@ import { Locales, Origins, Resource, ResourceResponse } from '@blizzard-api/core
13
27
  * };
14
28
  */
15
29
  interface AccessToken {
16
- access_token: string;
17
- expires_in: number;
18
- sub?: string;
19
- token_type: 'bearer';
30
+ access_token: string;
31
+ expires_in: number;
32
+ sub?: string;
33
+ token_type: 'bearer';
20
34
  }
21
35
  /**
22
36
  * An access token request.
@@ -29,23 +43,24 @@ interface AccessToken {
29
43
  * };
30
44
  */
31
45
  interface AccessTokenRequestArguments {
32
- key?: string;
33
- origin?: Origins;
34
- secret?: string;
46
+ key?: string;
47
+ origin?: Origins;
48
+ secret?: string;
35
49
  }
36
50
  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;
51
+ /**
52
+ * @deprecated
53
+ * This property is only here for backward compatibility, it will be removed in the next major version.
54
+ * All data should be accessed directly from the response object instead of through this property.
55
+ */
56
+ data: T;
43
57
  };
44
58
  /**
45
59
  * A client configuration object.
46
60
  * @example
47
61
  * const options: ClientOptions = {
48
62
  * key: 'client',
63
+ * kyOptions: { ... },
49
64
  * secret: 'secret',
50
65
  * origin: 'eu',
51
66
  * locale: 'en_GB',
@@ -53,20 +68,12 @@ type AxiosCompatability<T> = T & {
53
68
  * };
54
69
  */
55
70
  interface ClientOptions {
56
- key: string;
57
- locale?: Locales;
58
- origin: Origins;
59
- secret: string;
60
- token?: string;
61
- }
62
- /**
63
- * A Blizzard API client.
64
- */
65
- interface IBlizzardApiClient {
66
- getAccessToken: (options: AccessTokenRequestArguments) => Promise<AxiosCompatability<AccessToken>>;
67
- refreshAccessToken: (options: AccessTokenRequestArguments) => Promise<AxiosCompatability<AccessToken>>;
68
- setAccessToken: (token: string) => void;
69
- validateAccessToken: (options: ValidateAccessTokenArguments) => Promise<AxiosCompatability<ValidateAccessTokenResponse>>;
71
+ key: string;
72
+ kyOptions?: Options;
73
+ locale?: Locales;
74
+ origin: Origins;
75
+ secret: string;
76
+ token?: string;
70
77
  }
71
78
  /**
72
79
  * Validate an access token.
@@ -78,8 +85,8 @@ interface IBlizzardApiClient {
78
85
  * };
79
86
  */
80
87
  interface ValidateAccessTokenArguments {
81
- origin?: Origins;
82
- token?: string;
88
+ origin?: Origins;
89
+ token?: string;
83
90
  }
84
91
  /**
85
92
  * A response from validating an access token.
@@ -95,14 +102,14 @@ interface ValidateAccessTokenArguments {
95
102
  * };
96
103
  */
97
104
  interface ValidateAccessTokenResponse {
98
- account_authorities: Array<unknown>;
99
- authorities: Array<string>;
100
- client_authorities: Array<unknown>;
101
- client_id: string;
102
- exp: number;
103
- scope: Array<string>;
104
- }
105
-
105
+ account_authorities: Array<unknown>;
106
+ authorities: Array<string>;
107
+ client_authorities: Array<unknown>;
108
+ client_id: string;
109
+ exp: number;
110
+ scope: Array<string>;
111
+ } //#endregion
112
+ //#region src/client/client.d.ts
106
113
  /**
107
114
  * A Blizzard API client.
108
115
  * @classdesc A client to interact with the Blizzard API.
@@ -115,93 +122,95 @@ interface ValidateAccessTokenResponse {
115
122
  * token: 'access'
116
123
  * });
117
124
  */
118
- declare class BlizzardApiClient implements IBlizzardApiClient {
119
- defaults: {
120
- key: string;
121
- locale: Locales;
122
- origin: Origins;
123
- secret: string;
124
- token?: string;
125
+ declare class BlizzardApiClient {
126
+ defaults: {
127
+ key: string;
128
+ locale: Locales;
129
+ origin: Origins;
130
+ secret: string;
131
+ token?: string;
132
+ };
133
+ private ky;
134
+ constructor(options: ClientOptions);
135
+ /**
136
+ * Get an access token.
137
+ * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.
138
+ * @returns The access token. See {@link AccessToken}.
139
+ * @example
140
+ * const response = await client.getAccessToken();
141
+ * const { access_token, token_type, expires_in, sub } = response;
142
+ * console.log(access_token, token_type, expires_in, sub);
143
+ * // => 'access'
144
+ * // => 'bearer'
145
+ * // => 86399
146
+ * // => 'client-id'
147
+ */
148
+ getAccessToken: (options?: AccessTokenRequestArguments) => Promise<AxiosCompatability<AccessToken>>;
149
+ /**
150
+ * Set the access token.
151
+ * @param token The access token.
152
+ */
153
+ setAccessToken: (token: string) => void;
154
+ /**
155
+ * Refresh the access token.
156
+ * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.
157
+ * @returns The access token. See {@link AccessToken}.
158
+ * @example
159
+ * const response = await client.refreshAccessToken();
160
+ * const { access_token, token_type, expires_in, sub } = response;
161
+ * console.log(access_token, token_type, expires_in, sub);
162
+ * // => 'access'
163
+ * // => 'bearer'
164
+ * // => 86399
165
+ * // => 'client-id'
166
+ */
167
+ refreshAccessToken: (options?: AccessTokenRequestArguments) => Promise<AxiosCompatability<AccessToken>>;
168
+ /**
169
+ * Validate an access token.
170
+ * @param options The validate access token arguments. See {@link ValidateAccessTokenArguments}.
171
+ * @returns The response from the Blizzard API. See {@link ValidateAccessTokenResponse}.
172
+ * @example
173
+ * const response = await client.validateAccessToken({ token: 'access' });
174
+ * console.log(response.client_id);
175
+ * // => 'client-id'
176
+ */
177
+ validateAccessToken: (options?: ValidateAccessTokenArguments) => Promise<AxiosCompatability<ValidateAccessTokenResponse>>;
178
+ /**
179
+ * Get the request configuration.
180
+ * @param resource The resource to fetch. See {@link Resource}.
181
+ * @param options Client options. See {@link ClientOptions}.
182
+ * @param headers Additional headers to include in the request. This is deprecated and should be passed into the kyOptions as part of the client options instead.
183
+ * @returns The request configuration.
184
+ */
185
+ getRequestConfig<T, Protected extends boolean = false>(resource: Resource<T, object, Protected>, options?: Partial<ClientOptions>, headers?: Record<string, string>): {
186
+ headers: Record<string, string> & {
187
+ Authorization: `Bearer ${string}`;
188
+ 'Battlenet-Namespace'?: string;
189
+ 'Content-Type': 'application/json';
125
190
  };
126
- private ky;
127
- constructor(options: ClientOptions);
128
- /**
129
- * Get an access token.
130
- * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.
131
- * @returns The access token. See {@link AccessToken}.
132
- * @example
133
- * const response = await client.getAccessToken();
134
- * const { access_token, token_type, expires_in, sub } = response;
135
- * console.log(access_token, token_type, expires_in, sub);
136
- * // => 'access'
137
- * // => 'bearer'
138
- * // => 86399
139
- * // => 'client-id'
140
- */
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;
147
- /**
148
- * Refresh the access token.
149
- * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.
150
- * @returns The access token. See {@link AccessToken}.
151
- * @example
152
- * const response = await client.refreshAccessToken();
153
- * const { access_token, token_type, expires_in, sub } = response;
154
- * console.log(access_token, token_type, expires_in, sub);
155
- * // => 'access'
156
- * // => 'bearer'
157
- * // => 86399
158
- * // => 'client-id'
159
- */
160
- refreshAccessToken: (options?: AccessTokenRequestArguments) => Promise<AxiosCompatability<AccessToken>>;
161
- /**
162
- * Validate an access token.
163
- * @param options The validate access token arguments. See {@link ValidateAccessTokenArguments}.
164
- * @returns The response from the Blizzard API. See {@link ValidateAccessTokenResponse}.
165
- * @example
166
- * const response = await client.validateAccessToken({ token: 'access' });
167
- * console.log(response.client_id);
168
- * // => 'client-id'
169
- */
170
- validateAccessToken: (options?: ValidateAccessTokenArguments) => Promise<AxiosCompatability<ValidateAccessTokenResponse>>;
171
- /**
172
- * Get the request configuration.
173
- * @param resource The resource to fetch. See {@link Resource}.
174
- * @param options Client options. See {@link ClientOptions}.
175
- * @param headers Additional headers to include in the request.
176
- * @returns The request configuration.
177
- */
178
- getRequestConfig<T, Protected extends boolean = false>(resource: Resource<T, object, Protected>, options?: Partial<ClientOptions>, headers?: Record<string, string>): {
179
- headers: {
180
- Authorization: string;
181
- 'Content-Type': string;
182
- 'Battlenet-Namespace'?: string | undefined;
183
- };
184
- searchParams: {
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";
186
- };
191
+ searchParams: Record<string, unknown> & {
192
+ locale: ReturnType<typeof getBlizzardApi>['locale'];
187
193
  };
188
- /**
189
- * Get the request URL.
190
- * @param resource The resource to fetch. See {@link Resource}.
191
- * @param options Client options. See {@link ClientOptions}.
192
- * @returns The request URL.
193
- */
194
- getRequestUrl<T, Protected extends boolean = false>(resource: Resource<T, object, Protected>, options?: Partial<ClientOptions>): string;
195
- /**
196
- * Send a request to the Blizzard API.
197
- * @param resource The resource to fetch. See {@link Resource}.
198
- * @param options Client options. See {@link ClientOptions}.
199
- * @param headers Additional headers to include in the request.
200
- * @returns The response from the Blizzard API. See {@link ResourceResponse}.
201
- */
202
- sendRequest<T, Protected extends boolean = false>(resource: Resource<T, object, Protected>, options?: Partial<ClientOptions>, headers?: Record<string, string>): ResourceResponse<AxiosCompatability<T>>;
194
+ };
195
+ /**
196
+ * Get the request URL.
197
+ * @param resource The resource to fetch. See {@link Resource}.
198
+ * @param options Client options. See {@link ClientOptions}.
199
+ * @returns The request URL.
200
+ */
201
+ getRequestUrl<T, Protected extends boolean = false>(resource: Resource<T, object, Protected>, options?: Partial<ClientOptions>): string;
202
+ /**
203
+ * Send a request to the Blizzard API.
204
+ * @param resource The resource to fetch. See {@link Resource}.
205
+ * @param options Client options. See {@link ClientOptions}.
206
+ * @param headers Additional headers to include in the request. This is deprecated and should be passed into the kyOptions as part of the client options instead.
207
+ * @returns The response from the Blizzard API. See {@link ResourceResponse}.
208
+ */
209
+ sendRequest<T, Protected extends boolean = false>(resource: Resource<T, object, Protected>, options?: Partial<ClientOptions>, headers?: Record<string, string>): ResourceResponse<AxiosCompatability<T>>;
203
210
  }
204
211
 
212
+ //#endregion
213
+ //#region src/client/create-client.d.ts
205
214
  /**
206
215
  * Create a new Blizzard API client.
207
216
  * @param options Client options, see {@link ClientOptions} & https://develop.battle.net/documentation/guides/getting-started
@@ -210,4 +219,6 @@ declare class BlizzardApiClient implements IBlizzardApiClient {
210
219
  */
211
220
  declare const createBlizzardApiClient: (options: ClientOptions, onTokenRefresh?: ((token: AccessToken) => void) | boolean) => Promise<BlizzardApiClient>;
212
221
 
213
- export { type AccessToken, type AccessTokenRequestArguments, type AxiosCompatability, type ClientOptions, type IBlizzardApiClient, type ValidateAccessTokenArguments, type ValidateAccessTokenResponse, createBlizzardApiClient, createBlizzardApiClient as default };
222
+ //#endregion
223
+ export { AccessToken, AccessTokenRequestArguments, AxiosCompatability, ClientOptions, ValidateAccessTokenArguments, ValidateAccessTokenResponse, createBlizzardApiClient, createBlizzardApiClient as default };
224
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,206 +1,293 @@
1
- import { setTimeout } from 'node:timers';
2
- import { stringify } from 'node:querystring';
3
- import { getBlizzardApi } from '@blizzard-api/core';
4
- import ky from 'ky';
1
+ import { setTimeout } from "node:timers";
2
+ import { stringify } from "node:querystring";
3
+ import { getBlizzardApi } from "@blizzard-api/core";
4
+ import ky from "ky";
5
5
 
6
- // src/client/create-client.ts
6
+ //#region src/client/client.ts
7
+ /**
8
+
9
+ * A Blizzard API client.
10
+
11
+ * @classdesc A client to interact with the Blizzard API.
12
+
13
+ * @example
14
+
15
+ * const client = new BlizzardApiClient({
16
+
17
+ * key: 'client',
18
+
19
+ * secret: 'secret',
20
+
21
+ * origin: 'eu',
22
+
23
+ * locale: 'en_GB',
24
+
25
+ * token: 'access'
26
+
27
+ * });
28
+
29
+ */
7
30
  var BlizzardApiClient = class {
8
- defaults;
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
- }
20
- /**
21
- * Get an access token.
22
- * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.
23
- * @returns The access token. See {@link AccessToken}.
24
- * @example
25
- * const response = await client.getAccessToken();
26
- * const { access_token, token_type, expires_in, sub } = response;
27
- * console.log(access_token, token_type, expires_in, sub);
28
- * // => 'access'
29
- * // => 'bearer'
30
- * // => 86399
31
- * // => 'client-id'
32
- */
33
- getAccessToken = async (options) => {
34
- const { key, origin, secret } = { ...this.defaults, ...options };
35
- const basicAuth = Buffer.from(`${key}:${secret}`).toString("base64");
36
- const response = await this.ky.post(`https://${origin}.battle.net/oauth/token`, {
37
- headers: {
38
- Authorization: `Basic ${basicAuth}`,
39
- "Content-Type": "application/json"
40
- },
41
- searchParams: {
42
- grant_type: "client_credentials"
43
- }
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;
56
- };
57
- /**
58
- * Refresh the access token.
59
- * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.
60
- * @returns The access token. See {@link AccessToken}.
61
- * @example
62
- * const response = await client.refreshAccessToken();
63
- * const { access_token, token_type, expires_in, sub } = response;
64
- * console.log(access_token, token_type, expires_in, sub);
65
- * // => 'access'
66
- * // => 'bearer'
67
- * // => 86399
68
- * // => 'client-id'
69
- */
70
- refreshAccessToken = async (options) => {
71
- const response = await this.getAccessToken(options);
72
- this.setAccessToken(response.access_token);
73
- return response;
74
- };
75
- /**
76
- * Validate an access token.
77
- * @param options The validate access token arguments. See {@link ValidateAccessTokenArguments}.
78
- * @returns The response from the Blizzard API. See {@link ValidateAccessTokenResponse}.
79
- * @example
80
- * const response = await client.validateAccessToken({ token: 'access' });
81
- * console.log(response.client_id);
82
- * // => 'client-id'
83
- */
84
- validateAccessToken = async (options) => {
85
- const { origin, token } = { ...this.defaults, ...options };
86
- if (!token) {
87
- throw new Error("No token has been set previously or been passed to the validateAccessToken method.");
88
- }
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"
93
- }
94
- }).json();
95
- return {
96
- data: response,
97
- ...response
98
- };
99
- };
100
- /**
101
- * Get the request configuration.
102
- * @param resource The resource to fetch. See {@link Resource}.
103
- * @param options Client options. See {@link ClientOptions}.
104
- * @param headers Additional headers to include in the request.
105
- * @returns The request configuration.
106
- */
107
- getRequestConfig(resource, options, headers) {
108
- const config = { ...this.defaults, ...options };
109
- const endpoint = getBlizzardApi(config.origin, config.locale);
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
- }
119
- return {
120
- headers: {
121
- ...headers,
122
- ...namespace,
123
- Authorization: `Bearer ${config.token}`,
124
- "Content-Type": "application/json"
125
- },
126
- searchParams: {
127
- locale: endpoint.locale,
128
- ...resource.parameters
129
- }
130
- };
131
- }
132
- /**
133
- * Get the request URL.
134
- * @param resource The resource to fetch. See {@link Resource}.
135
- * @param options Client options. See {@link ClientOptions}.
136
- * @returns The request URL.
137
- */
138
- getRequestUrl(resource, options) {
139
- const config = { ...this.defaults, ...options };
140
- const endpoint = getBlizzardApi(config.origin, config.locale);
141
- const backslashSeparator = resource.path.startsWith("/") ? "" : "/";
142
- return `${endpoint.hostname}${backslashSeparator}${resource.path}`;
143
- }
144
- /**
145
- * Send a request to the Blizzard API.
146
- * @param resource The resource to fetch. See {@link Resource}.
147
- * @param options Client options. See {@link ClientOptions}.
148
- * @param headers Additional headers to include in the request.
149
- * @returns The response from the Blizzard API. See {@link ResourceResponse}.
150
- */
151
- async sendRequest(resource, options, headers) {
152
- const url = this.getRequestUrl(resource, options);
153
- const config = this.getRequestConfig(resource, options, headers);
154
- const response = await this.ky.get(url, config).json();
155
- return {
156
- data: response,
157
- ...response
158
- };
159
- }
31
+ constructor(options) {
32
+ const { locale, origin } = getBlizzardApi(options.origin, options.locale);
33
+ this.defaults = {
34
+ key: options.key,
35
+ locale,
36
+ origin,
37
+ secret: options.secret,
38
+ token: options.token
39
+ };
40
+ this.ky = ky.create(options.kyOptions);
41
+ }
42
+ /**
43
+
44
+ * Get an access token.
45
+
46
+ * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.
47
+
48
+ * @returns The access token. See {@link AccessToken}.
49
+
50
+ * @example
51
+
52
+ * const response = await client.getAccessToken();
53
+
54
+ * const { access_token, token_type, expires_in, sub } = response;
55
+
56
+ * console.log(access_token, token_type, expires_in, sub);
57
+
58
+ * // => 'access'
59
+
60
+ * // => 'bearer'
61
+
62
+ * // => 86399
63
+
64
+ * // => 'client-id'
65
+
66
+ */
67
+ getAccessToken = async (options) => {
68
+ const { key, origin, secret } = {
69
+ ...this.defaults,
70
+ ...options
71
+ };
72
+ const basicAuth = Buffer.from(`${key}:${secret}`).toString("base64");
73
+ const response = await this.ky.post(`https://${origin}.battle.net/oauth/token`, {
74
+ headers: {
75
+ Authorization: `Basic ${basicAuth}`,
76
+ "Content-Type": "application/json"
77
+ },
78
+ searchParams: { grant_type: "client_credentials" }
79
+ }).json();
80
+ return {
81
+ data: response,
82
+ ...response
83
+ };
84
+ };
85
+ /**
86
+
87
+ * Set the access token.
88
+
89
+ * @param token The access token.
90
+
91
+ */
92
+ setAccessToken = (token) => {
93
+ this.defaults.token = token;
94
+ };
95
+ /**
96
+
97
+ * Refresh the access token.
98
+
99
+ * @param options The access token request arguments. See {@link AccessTokenRequestArguments}.
100
+
101
+ * @returns The access token. See {@link AccessToken}.
102
+
103
+ * @example
104
+
105
+ * const response = await client.refreshAccessToken();
106
+
107
+ * const { access_token, token_type, expires_in, sub } = response;
108
+
109
+ * console.log(access_token, token_type, expires_in, sub);
110
+
111
+ * // => 'access'
112
+
113
+ * // => 'bearer'
114
+
115
+ * // => 86399
116
+
117
+ * // => 'client-id'
118
+
119
+ */
120
+ refreshAccessToken = async (options) => {
121
+ const response = await this.getAccessToken(options);
122
+ this.setAccessToken(response.access_token);
123
+ return response;
124
+ };
125
+ /**
126
+
127
+ * Validate an access token.
128
+
129
+ * @param options The validate access token arguments. See {@link ValidateAccessTokenArguments}.
130
+
131
+ * @returns The response from the Blizzard API. See {@link ValidateAccessTokenResponse}.
132
+
133
+ * @example
134
+
135
+ * const response = await client.validateAccessToken({ token: 'access' });
136
+
137
+ * console.log(response.client_id);
138
+
139
+ * // => 'client-id'
140
+
141
+ */
142
+ validateAccessToken = async (options) => {
143
+ const { origin, token } = {
144
+ ...this.defaults,
145
+ ...options
146
+ };
147
+ if (!token) throw new Error("No token has been set previously or been passed to the validateAccessToken method.");
148
+ const response = await this.ky.post(`https://${origin}.battle.net/oauth/check_token`, {
149
+ body: stringify({ token }),
150
+ headers: { "Content-Type": "application/x-www-form-urlencoded" }
151
+ }).json();
152
+ return {
153
+ data: response,
154
+ ...response
155
+ };
156
+ };
157
+ /**
158
+
159
+ * Get the request configuration.
160
+
161
+ * @param resource The resource to fetch. See {@link Resource}.
162
+
163
+ * @param options Client options. See {@link ClientOptions}.
164
+
165
+ * @param headers Additional headers to include in the request. This is deprecated and should be passed into the kyOptions as part of the client options instead.
166
+
167
+ * @returns The request configuration.
168
+
169
+ */
170
+ getRequestConfig(resource, options, headers) {
171
+ const config = {
172
+ ...this.defaults,
173
+ ...options
174
+ };
175
+ const endpoint = getBlizzardApi(config.origin, config.locale);
176
+ const namespace = resource.namespace ? { "Battlenet-Namespace": `${resource.namespace}-${endpoint.origin}` } : void 0;
177
+ const parameters = resource.parameters;
178
+ if (parameters) {
179
+ for (const key of Object.keys(parameters)) if (parameters[key] === void 0) delete parameters[key];
180
+ }
181
+ return {
182
+ headers: {
183
+ ...headers,
184
+ ...namespace,
185
+ Authorization: `Bearer ${config.token}`,
186
+ "Content-Type": "application/json"
187
+ },
188
+ searchParams: {
189
+ ...parameters,
190
+ locale: endpoint.locale
191
+ }
192
+ };
193
+ }
194
+ /**
195
+
196
+ * Get the request URL.
197
+
198
+ * @param resource The resource to fetch. See {@link Resource}.
199
+
200
+ * @param options Client options. See {@link ClientOptions}.
201
+
202
+ * @returns The request URL.
203
+
204
+ */
205
+ getRequestUrl(resource, options) {
206
+ const config = {
207
+ ...this.defaults,
208
+ ...options
209
+ };
210
+ const endpoint = getBlizzardApi(config.origin, config.locale);
211
+ const backslashSeparator = resource.path.startsWith("/") ? "" : "/";
212
+ return `${endpoint.hostname}${backslashSeparator}${resource.path}`;
213
+ }
214
+ /**
215
+
216
+ * Send a request to the Blizzard API.
217
+
218
+ * @param resource The resource to fetch. See {@link Resource}.
219
+
220
+ * @param options Client options. See {@link ClientOptions}.
221
+
222
+ * @param headers Additional headers to include in the request. This is deprecated and should be passed into the kyOptions as part of the client options instead.
223
+
224
+ * @returns The response from the Blizzard API. See {@link ResourceResponse}.
225
+
226
+ */
227
+ async sendRequest(resource, options, headers) {
228
+ const url = this.getRequestUrl(resource, options);
229
+ const config = this.getRequestConfig(resource, options, headers);
230
+ const response = await this.ky.get(url, {
231
+ ...options?.kyOptions,
232
+ headers: {
233
+ ...config.headers,
234
+ ...options?.kyOptions?.headers
235
+ },
236
+ searchParams: {
237
+ ...config.searchParams,
238
+ ...Object.entries(options?.kyOptions?.searchParams ?? {})
239
+ }
240
+ });
241
+ const data = await response.json();
242
+ return {
243
+ data,
244
+ ...data
245
+ };
246
+ }
160
247
  };
161
248
 
162
- // src/client/create-client.ts
163
- var getTokenExpiration = (expiresIn) => expiresIn * 1e3 - 6e4;
164
- var createBlizzardApiClient = async (options, onTokenRefresh = true) => {
165
- const { key, secret, token } = options;
166
- if (!key) {
167
- throw new Error(`Client missing 'key' parameter`);
168
- }
169
- if (!secret) {
170
- throw new Error(`Client missing 'secret' parameter`);
171
- }
172
- const client = new BlizzardApiClient(options);
173
- const refreshToken = async () => {
174
- const response = await client.getAccessToken();
175
- client.setAccessToken(response.access_token);
176
- if (typeof onTokenRefresh === "function") {
177
- onTokenRefresh?.(response);
178
- }
179
- const timeout = setTimeout(() => void refreshToken(), getTokenExpiration(response.expires_in));
180
- timeout.unref();
181
- };
182
- if (!onTokenRefresh) {
183
- return client;
184
- }
185
- if (token) {
186
- try {
187
- const validatedToken = await client.validateAccessToken({ token });
188
- const expiry = getTokenExpiration(validatedToken.exp);
189
- if (expiry - Date.now() < 6e4) {
190
- await refreshToken();
191
- } else {
192
- const timeout = setTimeout(() => void refreshToken(), expiry - Date.now());
193
- timeout.unref();
194
- }
195
- } catch {
196
- await refreshToken();
197
- }
198
- } else {
199
- await refreshToken();
200
- }
201
- return client;
249
+ //#endregion
250
+ //#region src/client/create-client.ts
251
+ const getTokenExpiration = (expiresIn) => expiresIn * 1e3 - 6e4;
252
+ /**
253
+
254
+ * Create a new Blizzard API client.
255
+
256
+ * @param options Client options, see {@link ClientOptions} & https://develop.battle.net/documentation/guides/getting-started
257
+
258
+ * @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.
259
+
260
+ * @returns A new Blizzard API client.
261
+
262
+ */
263
+ const createBlizzardApiClient = async (options, onTokenRefresh = true) => {
264
+ const { key, secret, token } = options;
265
+ if (!key) throw new Error(`Client missing 'key' parameter`);
266
+ if (!secret) throw new Error(`Client missing 'secret' parameter`);
267
+ const client = new BlizzardApiClient(options);
268
+ const refreshToken = async () => {
269
+ const response = await client.getAccessToken();
270
+ client.setAccessToken(response.access_token);
271
+ if (typeof onTokenRefresh === "function") onTokenRefresh?.(response);
272
+ const timeout = setTimeout(() => void refreshToken(), getTokenExpiration(response.expires_in));
273
+ timeout.unref();
274
+ };
275
+ if (!onTokenRefresh) return client;
276
+ if (token) try {
277
+ const validatedToken = await client.validateAccessToken({ token });
278
+ const expiry = getTokenExpiration(validatedToken.exp);
279
+ if (expiry - Date.now() < 6e4) await refreshToken();
280
+ else {
281
+ const timeout = setTimeout(() => void refreshToken(), expiry - Date.now());
282
+ timeout.unref();
283
+ }
284
+ } catch {
285
+ await refreshToken();
286
+ }
287
+ else await refreshToken();
288
+ return client;
202
289
  };
203
290
 
291
+ //#endregion
204
292
  export { createBlizzardApiClient, createBlizzardApiClient as default };
205
- //# sourceMappingURL=index.js.map
206
293
  //# sourceMappingURL=index.js.map
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 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"]}
1
+ {"version":3,"file":"index.js","names":["options: ClientOptions","options?: AccessTokenRequestArguments","token: string","options?: ValidateAccessTokenArguments","resource: Resource<T, object, Protected>","options?: Partial<ClientOptions>","headers?: Record<string, string>","expiresIn: number","options: ClientOptions","onTokenRefresh: ((token: AccessToken) => void) | boolean"],"sources":["../src/client/client.ts","../src/client/create-client.ts"],"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 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 {\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;\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 this.ky = ky.create(options.kyOptions);\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. This is deprecated and should be passed into the kyOptions as part of the client options instead.\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 headers: Record<string, string> & {\r\n Authorization: `Bearer ${string}`;\r\n 'Battlenet-Namespace'?: string;\r\n 'Content-Type': 'application/json';\r\n };\r\n searchParams: Record<string, unknown> & { locale: ReturnType<typeof getBlizzardApi>['locale'] };\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 ...parameters,\r\n locale: endpoint.locale,\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. This is deprecated and should be passed into the kyOptions as part of the client options instead.\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, {\r\n ...options?.kyOptions,\r\n headers: {\r\n ...config.headers,\r\n ...options?.kyOptions?.headers,\r\n },\r\n searchParams: { ...config.searchParams, ...Object.entries(options?.kyOptions?.searchParams ?? {}) },\r\n });\r\n const data = await response.json();\r\n\r\n return {\r\n data,\r\n ...data,\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"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blizzard-api/client",
3
- "version": "2.1.3",
3
+ "version": "2.2.0",
4
4
  "license": "MIT",
5
5
  "author": "Putro",
6
6
  "description": "A node.js client to integrate with the blizzard battle.net api.",
@@ -43,19 +43,19 @@
43
43
  "ky": "1.8.1"
44
44
  },
45
45
  "peerDependencies": {
46
- "@blizzard-api/core": "2.1.0"
46
+ "@blizzard-api/core": "2.1.1"
47
47
  },
48
48
  "devDependencies": {
49
- "@blizzard-api/classic-wow": "2.1.2",
50
- "@blizzard-api/core": "2.1.0",
51
- "@blizzard-api/d3": "1.0.4",
52
- "@blizzard-api/sc2": "1.0.4",
53
- "@blizzard-api/hs": "1.0.4",
54
- "@blizzard-api/wow": "2.0.4"
49
+ "@blizzard-api/classic-wow": "2.1.3",
50
+ "@blizzard-api/core": "2.1.1",
51
+ "@blizzard-api/d3": "1.0.5",
52
+ "@blizzard-api/hs": "1.0.5",
53
+ "@blizzard-api/sc2": "1.0.5",
54
+ "@blizzard-api/wow": "2.0.5"
55
55
  },
56
56
  "scripts": {
57
- "build": "tsup",
58
- "dev": "tsup --watch",
57
+ "build": "tsdown",
58
+ "dev": "tsdown --watch",
59
59
  "test": "vitest run",
60
60
  "test:coverage": "pnpm test -- --coverage",
61
61
  "test:watch": "vitest watch"