@gw2me/client 0.9.2 → 0.9.3

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.
@@ -0,0 +1,9 @@
1
+ //#region src/base64.ts
2
+ function base64urlEncode(input) {
3
+ const data = input instanceof ArrayBuffer ? new Uint8Array(input) : input;
4
+ return btoa(String.fromCharCode(...data)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
5
+ }
6
+
7
+ //#endregion
8
+ export { base64urlEncode as t };
9
+ //# sourceMappingURL=base64-B0vm543A.mjs.map
@@ -0,0 +1,14 @@
1
+ import { r as DPoPParams } from "./types-cXKOlCJ4.mjs";
2
+
3
+ //#region src/dpop.d.ts
4
+ declare function generateDPoPKeyPair(): Promise<CryptoKeyPair>;
5
+ declare function createDPoPJwt({
6
+ htm,
7
+ htu,
8
+ nonce,
9
+ accessToken
10
+ }: DPoPParams, keyPair: CryptoKeyPair): Promise<string>;
11
+ declare function jwkThumbprint(key: CryptoKey): Promise<string>;
12
+ //#endregion
13
+ export { createDPoPJwt, generateDPoPKeyPair, jwkThumbprint };
14
+ //# sourceMappingURL=dpop.d.mts.map
package/dist/dpop.mjs ADDED
@@ -0,0 +1,53 @@
1
+ import { t as base64urlEncode } from "./base64-B0vm543A.mjs";
2
+
3
+ //#region src/dpop.ts
4
+ function generateDPoPKeyPair() {
5
+ return crypto.subtle.generateKey({
6
+ name: "ECDSA",
7
+ namedCurve: "P-256"
8
+ }, false, ["sign"]);
9
+ }
10
+ async function createDPoPJwt({ htm, htu, nonce, accessToken }, keyPair) {
11
+ const header = JSON.stringify({
12
+ alg: "ES256",
13
+ typ: "dpop+jwt",
14
+ jwk: await jwk(keyPair.publicKey)
15
+ });
16
+ const body = JSON.stringify({
17
+ iat: Math.floor(Date.now() / 1e3),
18
+ jti: base64urlEncode(crypto.getRandomValues(new Uint8Array(32))),
19
+ htm,
20
+ htu,
21
+ nonce,
22
+ ath: accessToken ? base64urlEncode(await crypto.subtle.digest("SHA-256", stringToBuffer(accessToken))) : void 0
23
+ });
24
+ const input = `${base64urlEncode(stringToBuffer(header))}.${base64urlEncode(stringToBuffer(body))}`;
25
+ return `${input}.${base64urlEncode(await crypto.subtle.sign({
26
+ name: "ECDSA",
27
+ hash: "SHA-256"
28
+ }, keyPair.privateKey, stringToBuffer(input)))}`;
29
+ }
30
+ const encoder = new TextEncoder();
31
+ function stringToBuffer(value) {
32
+ return encoder.encode(value);
33
+ }
34
+ async function jwk(key) {
35
+ const { kty, e, k, n, x, y, crv } = await crypto.subtle.exportKey("jwk", key);
36
+ return {
37
+ e,
38
+ k,
39
+ crv,
40
+ kty,
41
+ n,
42
+ x,
43
+ y
44
+ };
45
+ }
46
+ async function jwkThumbprint(key) {
47
+ const jwkJson = JSON.stringify(await jwk(key));
48
+ return base64urlEncode(await crypto.subtle.digest("SHA-256", stringToBuffer(jwkJson)));
49
+ }
50
+
51
+ //#endregion
52
+ export { createDPoPJwt, generateDPoPKeyPair, jwkThumbprint };
53
+ //# sourceMappingURL=dpop.mjs.map
@@ -0,0 +1,194 @@
1
+ import { a as Scope, i as Options, n as DPoPCallback, r as DPoPParams, t as ClientInfo } from "./types-cXKOlCJ4.mjs";
2
+
3
+ //#region src/api.d.ts
4
+ interface UserResponse {
5
+ sub: string;
6
+ user: {
7
+ id: string;
8
+ name: string;
9
+ email?: string;
10
+ emailVerified?: boolean;
11
+ };
12
+ settings?: unknown;
13
+ }
14
+ interface AccountsResponse {
15
+ accounts: {
16
+ id: string;
17
+ name: string;
18
+ shared: boolean;
19
+ verified?: boolean;
20
+ displayName?: string | null;
21
+ }[];
22
+ }
23
+ interface SubtokenOptions {
24
+ permissions?: string[];
25
+ }
26
+ interface SubtokenResponse {
27
+ subtoken: string;
28
+ expiresAt: string;
29
+ }
30
+ interface ApiOptions extends Options {
31
+ dpop?: DPoPCallback;
32
+ }
33
+ declare class Gw2MeApi {
34
+ #private;
35
+ private access_token;
36
+ private options?;
37
+ constructor(access_token: string, options?: Partial<ApiOptions> | undefined);
38
+ user(): Promise<UserResponse>;
39
+ saveSettings(settings: unknown): Promise<void>;
40
+ accounts(): Promise<AccountsResponse>;
41
+ subtoken(accountId: string, options?: SubtokenOptions): Promise<SubtokenResponse>;
42
+ }
43
+ //#endregion
44
+ //#region src/fed-cm.d.ts
45
+ interface FedCMRequestOptions {
46
+ scopes: Scope[];
47
+ mediation?: CredentialMediationRequirement;
48
+ mode?: 'passive' | 'active';
49
+ signal?: AbortSignal;
50
+ code_challenge: string;
51
+ code_challenge_method: 'S256';
52
+ /** @default true */
53
+ include_granted_scopes?: boolean;
54
+ }
55
+ declare class Gw2MeFedCM {
56
+ #private;
57
+ constructor(configUrl: URL, clientId: string);
58
+ isSupported(): boolean;
59
+ request({
60
+ scopes,
61
+ mediation,
62
+ signal,
63
+ mode,
64
+ code_challenge,
65
+ code_challenge_method,
66
+ include_granted_scopes
67
+ }: FedCMRequestOptions): Promise<null | {
68
+ token: string;
69
+ type: "identity";
70
+ }>;
71
+ }
72
+ //#endregion
73
+ //#region src/client.d.ts
74
+ interface AuthorizationUrlParams {
75
+ redirect_uri: string;
76
+ scopes: Scope[];
77
+ state?: string;
78
+ code_challenge?: string;
79
+ code_challenge_method?: 'S256';
80
+ dpop_jkt?: string;
81
+ prompt?: 'none' | 'consent';
82
+ include_granted_scopes?: boolean;
83
+ verified_accounts_only?: boolean;
84
+ }
85
+ interface PushedAuthorizationRequestParams extends AuthorizationUrlParams {
86
+ dpop?: DPoPCallback;
87
+ }
88
+ interface AuthorizationUrlRequestUriParams {
89
+ request_uri: string;
90
+ }
91
+ type TokenType = 'Bearer' | 'DPoP';
92
+ interface AuthTokenParams {
93
+ code: string;
94
+ token_type?: TokenType;
95
+ redirect_uri: string;
96
+ code_verifier?: string;
97
+ dpop?: DPoPCallback;
98
+ }
99
+ interface RefreshTokenParams {
100
+ refresh_token: string;
101
+ refresh_token_type?: TokenType;
102
+ dpop?: DPoPCallback;
103
+ }
104
+ interface TokenResponse {
105
+ access_token: string;
106
+ issued_token_type: 'urn:ietf:params:oauth:token-type:access_token';
107
+ token_type: TokenType;
108
+ expires_in: number;
109
+ refresh_token?: string;
110
+ scope: string;
111
+ }
112
+ interface RevokeTokenParams {
113
+ token: string;
114
+ }
115
+ interface IntrospectTokenParams {
116
+ token: string;
117
+ }
118
+ declare namespace IntrospectTokenResponse {
119
+ interface Inactive {
120
+ active: false;
121
+ }
122
+ namespace Active {
123
+ interface Common {
124
+ active: true;
125
+ scope: string;
126
+ client_id: string;
127
+ exp?: number;
128
+ }
129
+ interface Bearer extends Common {
130
+ token_type: 'Bearer';
131
+ }
132
+ interface DPoP extends Common {
133
+ token_type: 'DPoP';
134
+ cnf: {
135
+ jkt: string;
136
+ };
137
+ }
138
+ }
139
+ type Active = Active.Bearer | Active.DPoP;
140
+ }
141
+ type IntrospectTokenResponse = IntrospectTokenResponse.Inactive | IntrospectTokenResponse.Active;
142
+ interface PushedAuthorizationRequestResponse {
143
+ request_uri: string;
144
+ expires_in: number;
145
+ }
146
+ declare class Gw2MeClient {
147
+ #private;
148
+ private options?;
149
+ constructor(client: ClientInfo, options?: Partial<Options> | undefined);
150
+ getAuthorizationUrl(params: AuthorizationUrlParams | AuthorizationUrlRequestUriParams): string;
151
+ pushAuthorizationRequest(params: PushedAuthorizationRequestParams): Promise<PushedAuthorizationRequestResponse>;
152
+ getAccessToken({
153
+ code,
154
+ token_type,
155
+ redirect_uri,
156
+ code_verifier,
157
+ dpop
158
+ }: AuthTokenParams): Promise<TokenResponse>;
159
+ refreshToken({
160
+ refresh_token,
161
+ refresh_token_type,
162
+ dpop
163
+ }: RefreshTokenParams): Promise<TokenResponse>;
164
+ revokeToken({
165
+ token
166
+ }: RevokeTokenParams): Promise<void>;
167
+ introspectToken({
168
+ token
169
+ }: IntrospectTokenParams): Promise<IntrospectTokenResponse>;
170
+ /**
171
+ * Parses the search params received from gw2.me on the redirect url (code and state).
172
+ * If gw2.me returned an error response, this will throw an error.
173
+ *
174
+ * @returns The code and optional state.
175
+ */
176
+ parseAuthorizationResponseSearchParams(searchParams: URLSearchParams): {
177
+ code: string;
178
+ state: string | undefined;
179
+ };
180
+ api(access_token: string, options?: Partial<Omit<ApiOptions, keyof Options>>): Gw2MeApi;
181
+ get fedCM(): Gw2MeFedCM;
182
+ }
183
+ //#endregion
184
+ //#region src/error.d.ts
185
+ declare class Gw2MeError extends Error {}
186
+ declare class Gw2MeOAuthError extends Gw2MeError {
187
+ error: string;
188
+ error_description?: string | undefined;
189
+ error_uri?: string | undefined;
190
+ constructor(error: string, error_description?: string | undefined, error_uri?: string | undefined);
191
+ }
192
+ //#endregion
193
+ export { AccountsResponse, ApiOptions, AuthTokenParams, AuthorizationUrlParams, AuthorizationUrlRequestUriParams, ClientInfo, DPoPCallback, DPoPParams, FedCMRequestOptions, Gw2MeApi, Gw2MeClient, Gw2MeError, Gw2MeFedCM, Gw2MeOAuthError, IntrospectTokenParams, IntrospectTokenResponse, Options, PushedAuthorizationRequestParams, PushedAuthorizationRequestResponse, RefreshTokenParams, RevokeTokenParams, Scope, SubtokenOptions, SubtokenResponse, TokenResponse, TokenType, UserResponse };
194
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,289 @@
1
+ //#region src/types.ts
2
+ let Scope = /* @__PURE__ */ function(Scope$1) {
3
+ Scope$1["Identify"] = "identify";
4
+ Scope$1["Email"] = "email";
5
+ Scope$1["Accounts"] = "accounts";
6
+ Scope$1["Accounts_Verified"] = "accounts.verified";
7
+ Scope$1["Accounts_DisplayName"] = "accounts.displayName";
8
+ Scope$1["GW2_Account"] = "gw2:account";
9
+ Scope$1["GW2_Inventories"] = "gw2:inventories";
10
+ Scope$1["GW2_Characters"] = "gw2:characters";
11
+ Scope$1["GW2_Tradingpost"] = "gw2:tradingpost";
12
+ Scope$1["GW2_Wallet"] = "gw2:wallet";
13
+ Scope$1["GW2_Unlocks"] = "gw2:unlocks";
14
+ Scope$1["GW2_Pvp"] = "gw2:pvp";
15
+ Scope$1["GW2_Wvw"] = "gw2:wvw";
16
+ Scope$1["GW2_Builds"] = "gw2:builds";
17
+ Scope$1["GW2_Progression"] = "gw2:progression";
18
+ Scope$1["GW2_Guilds"] = "gw2:guilds";
19
+ return Scope$1;
20
+ }({});
21
+
22
+ //#endregion
23
+ //#region src/error.ts
24
+ var Gw2MeError = class extends Error {};
25
+ var Gw2MeOAuthError = class extends Gw2MeError {
26
+ constructor(error, error_description, error_uri) {
27
+ super(`Received ${error}` + (error_description ? `: ${error_description}` : "") + (error_uri ? ` (${error_uri})` : ""));
28
+ this.error = error;
29
+ this.error_description = error_description;
30
+ this.error_uri = error_uri;
31
+ }
32
+ };
33
+
34
+ //#endregion
35
+ //#region src/util.ts
36
+ async function jsonOrError(response) {
37
+ await okOrError(response);
38
+ if (!(response.headers.get("Content-Type") === "application/json")) throw new Gw2MeError("gw2.me did not return a valid JSON response");
39
+ return response.json();
40
+ }
41
+ async function okOrError(response) {
42
+ if (!response.ok) {
43
+ let errorMessage;
44
+ if (response.headers.get("Content-Type") === "application/json") errorMessage = (await response.json()).error_description;
45
+ throw new Gw2MeError(`gw2.me returned an error: ${errorMessage ?? "Unknown error"}`);
46
+ }
47
+ }
48
+
49
+ //#endregion
50
+ //#region src/api.ts
51
+ var Gw2MeApi = class {
52
+ constructor(access_token, options) {
53
+ this.access_token = access_token;
54
+ this.options = options;
55
+ }
56
+ user() {
57
+ return this.#requestWithDpop("api/user").then((request) => fetch(request)).then(jsonOrError);
58
+ }
59
+ saveSettings(settings) {
60
+ return this.#requestWithDpop("api/user/settings", {
61
+ method: "POST",
62
+ headers: { "Content-Type": "application/json" },
63
+ body: JSON.stringify(settings)
64
+ }).then((request) => fetch(request)).then(okOrError);
65
+ }
66
+ accounts() {
67
+ return this.#requestWithDpop("api/accounts").then((request) => fetch(request)).then(jsonOrError);
68
+ }
69
+ subtoken(accountId, options) {
70
+ const url = this.#getUrl(`api/accounts/${accountId}/subtoken`);
71
+ if (options?.permissions) url.searchParams.set("permissions", options.permissions.join(","));
72
+ return this.#requestWithDpop(url).then((request) => fetch(request)).then(jsonOrError);
73
+ }
74
+ #getUrl(url) {
75
+ return new URL(url, this.options?.url || "https://gw2.me/");
76
+ }
77
+ async #requestWithDpop(endpoint, init) {
78
+ const url = endpoint instanceof URL ? endpoint : this.#getUrl(endpoint);
79
+ const dpop = this.options?.dpop;
80
+ const headers = new Headers(init?.headers);
81
+ headers.set("Authorization", `${dpop ? "DPoP" : "Bearer"} ${this.access_token}`);
82
+ if (dpop) headers.set("DPoP", await dpop({
83
+ htm: init?.method ?? "GET",
84
+ htu: url.toString(),
85
+ accessToken: this.access_token
86
+ }));
87
+ return new Request(url, {
88
+ cache: "no-cache",
89
+ ...init,
90
+ headers
91
+ });
92
+ }
93
+ };
94
+
95
+ //#endregion
96
+ //#region src/fed-cm.ts
97
+ var Gw2MeFedCM = class {
98
+ #configUrl;
99
+ #clientId;
100
+ constructor(configUrl, clientId) {
101
+ this.#configUrl = configUrl;
102
+ this.#clientId = clientId;
103
+ }
104
+ isSupported() {
105
+ return typeof window !== "undefined" && "IdentityCredential" in window;
106
+ }
107
+ request({ scopes, mediation, signal, mode, code_challenge, code_challenge_method, include_granted_scopes }) {
108
+ if (!this.isSupported()) throw new Gw2MeError("FedCM is not supported");
109
+ return navigator.credentials.get({
110
+ mediation,
111
+ signal,
112
+ identity: {
113
+ providers: [{
114
+ configURL: this.#configUrl,
115
+ clientId: this.#clientId,
116
+ fields: [scopes.includes(Scope.Identify) && "name", scopes.includes(Scope.Email) && "email"].filter(Boolean),
117
+ nonce: `${code_challenge_method}:${code_challenge}`,
118
+ params: {
119
+ scope: scopes.join(" "),
120
+ code_challenge,
121
+ code_challenge_method,
122
+ include_granted_scopes
123
+ }
124
+ }],
125
+ mode
126
+ }
127
+ });
128
+ }
129
+ };
130
+
131
+ //#endregion
132
+ //#region src/client.ts
133
+ var Gw2MeClient = class {
134
+ #client;
135
+ #fedCM;
136
+ constructor(client, options) {
137
+ this.options = options;
138
+ this.#client = client;
139
+ this.#fedCM = new Gw2MeFedCM(this.#getUrl("/fed-cm/config.json"), client.client_id);
140
+ }
141
+ #getUrl(url) {
142
+ return new URL(url, this.options?.url || "https://gw2.me/");
143
+ }
144
+ #getAuthorizationHeader() {
145
+ if (!this.#client.client_secret) throw new Gw2MeError("client_secret is required");
146
+ return `Basic ${btoa(`${this.#client.client_id}:${this.#client.client_secret}`)}`;
147
+ }
148
+ getAuthorizationUrl(params) {
149
+ const urlParams = "request_uri" in params ? new URLSearchParams({
150
+ client_id: this.#client.client_id,
151
+ response_type: "code",
152
+ request_uri: params.request_uri
153
+ }) : constructAuthorizationParams(this.#client.client_id, params);
154
+ return this.#getUrl(`/oauth2/authorize?${urlParams.toString()}`).toString();
155
+ }
156
+ async pushAuthorizationRequest(params) {
157
+ const url = this.#getUrl("/oauth2/par");
158
+ const headers = { "Content-Type": "application/x-www-form-urlencoded" };
159
+ if (params.dpop) headers.DPoP = await params.dpop({
160
+ htm: "POST",
161
+ htu: url.toString()
162
+ });
163
+ const urlParams = constructAuthorizationParams(this.#client.client_id, params);
164
+ if (this.#client.client_secret) headers.Authorization = this.#getAuthorizationHeader();
165
+ return await fetch(url, {
166
+ method: "POST",
167
+ headers,
168
+ body: urlParams,
169
+ cache: "no-store"
170
+ }).then(jsonOrError);
171
+ }
172
+ async getAccessToken({ code, token_type, redirect_uri, code_verifier, dpop }) {
173
+ const data = new URLSearchParams({
174
+ grant_type: "authorization_code",
175
+ code,
176
+ client_id: this.#client.client_id,
177
+ redirect_uri
178
+ });
179
+ const headers = { "Content-Type": "application/x-www-form-urlencoded" };
180
+ if (this.#client.client_secret) headers.Authorization = this.#getAuthorizationHeader();
181
+ if (code_verifier) data.set("code_verifier", code_verifier);
182
+ const url = this.#getUrl("/api/token");
183
+ if (dpop) headers.DPoP = await dpop({
184
+ htm: "POST",
185
+ htu: url.toString(),
186
+ accessToken: token_type === "DPoP" ? code : void 0
187
+ });
188
+ return await fetch(url, {
189
+ method: "POST",
190
+ headers,
191
+ body: data,
192
+ cache: "no-store"
193
+ }).then(jsonOrError);
194
+ }
195
+ async refreshToken({ refresh_token, refresh_token_type, dpop }) {
196
+ const data = new URLSearchParams({
197
+ grant_type: "refresh_token",
198
+ refresh_token,
199
+ client_id: this.#client.client_id
200
+ });
201
+ const headers = { "Content-Type": "application/x-www-form-urlencoded" };
202
+ if (this.#client.client_secret) headers["Authorization"] = this.#getAuthorizationHeader();
203
+ const url = this.#getUrl("/api/token");
204
+ if (dpop) headers.DPoP = await dpop({
205
+ htm: "POST",
206
+ htu: url.toString(),
207
+ accessToken: refresh_token_type === "DPoP" ? refresh_token : void 0
208
+ });
209
+ return await fetch(url, {
210
+ method: "POST",
211
+ headers,
212
+ body: data,
213
+ cache: "no-store"
214
+ }).then(jsonOrError);
215
+ }
216
+ async revokeToken({ token }) {
217
+ const body = new URLSearchParams({ token });
218
+ const headers = { "Content-Type": "application/x-www-form-urlencoded" };
219
+ if (this.#client.client_secret) headers.Authorization = this.#getAuthorizationHeader();
220
+ await fetch(this.#getUrl("/api/token/revoke"), {
221
+ method: "POST",
222
+ cache: "no-store",
223
+ headers,
224
+ body
225
+ }).then(jsonOrError);
226
+ }
227
+ async introspectToken({ token }) {
228
+ const body = new URLSearchParams({ token });
229
+ const headers = { "Content-Type": "application/x-www-form-urlencoded" };
230
+ if (this.#client.client_secret) headers.Authorization = this.#getAuthorizationHeader();
231
+ return await fetch(this.#getUrl("/api/token/introspect"), {
232
+ method: "POST",
233
+ cache: "no-store",
234
+ headers,
235
+ body
236
+ }).then(jsonOrError);
237
+ }
238
+ /**
239
+ * Parses the search params received from gw2.me on the redirect url (code and state).
240
+ * If gw2.me returned an error response, this will throw an error.
241
+ *
242
+ * @returns The code and optional state.
243
+ */
244
+ parseAuthorizationResponseSearchParams(searchParams) {
245
+ const expectedIssuer = this.#getUrl("/").origin;
246
+ const receivedIssuer = searchParams.get("iss");
247
+ if (!receivedIssuer) throw new Gw2MeError("Issuer Identifier verification failed: parameter `iss` is missing");
248
+ if (receivedIssuer !== expectedIssuer) throw new Gw2MeError(`Issuer Identifier verification failed: expected "${expectedIssuer}", got "${receivedIssuer}"`);
249
+ const error = searchParams.get("error");
250
+ if (error) throw new Gw2MeOAuthError(error, searchParams.get("error_description") ?? void 0, searchParams.get("error_uri") ?? void 0);
251
+ const code = searchParams.get("code");
252
+ if (!code) throw new Gw2MeError("Parameter `code` is missing");
253
+ return {
254
+ code,
255
+ state: searchParams.get("state") || void 0
256
+ };
257
+ }
258
+ api(access_token, options) {
259
+ return new Gw2MeApi(access_token, {
260
+ ...this.options,
261
+ ...options
262
+ });
263
+ }
264
+ get fedCM() {
265
+ return this.#fedCM;
266
+ }
267
+ };
268
+ function constructAuthorizationParams(client_id, { redirect_uri, scopes, state, code_challenge, code_challenge_method, dpop_jkt, prompt, include_granted_scopes, verified_accounts_only }) {
269
+ const params = new URLSearchParams({
270
+ client_id,
271
+ response_type: "code",
272
+ redirect_uri,
273
+ scope: scopes.join(" ")
274
+ });
275
+ if (state) params.append("state", state);
276
+ if (code_challenge && code_challenge_method) {
277
+ params.append("code_challenge", code_challenge);
278
+ params.append("code_challenge_method", code_challenge_method);
279
+ }
280
+ if (dpop_jkt) params.append("dpop_jkt", dpop_jkt);
281
+ if (prompt) params.append("prompt", prompt);
282
+ if (include_granted_scopes) params.append("include_granted_scopes", "true");
283
+ if (verified_accounts_only) params.append("verified_accounts_only", "true");
284
+ return params;
285
+ }
286
+
287
+ //#endregion
288
+ export { Gw2MeApi, Gw2MeClient, Gw2MeError, Gw2MeOAuthError, Scope };
289
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,13 @@
1
+ //#region src/pkce.d.ts
2
+ interface PKCEChallenge {
3
+ code_challenge: string;
4
+ code_challenge_method: 'S256';
5
+ }
6
+ interface PKCEPair {
7
+ challenge: PKCEChallenge;
8
+ code_verifier: string;
9
+ }
10
+ declare function generatePKCEPair(): Promise<PKCEPair>;
11
+ //#endregion
12
+ export { PKCEChallenge, PKCEPair, generatePKCEPair };
13
+ //# sourceMappingURL=pkce.d.mts.map
package/dist/pkce.mjs ADDED
@@ -0,0 +1,21 @@
1
+ import { t as base64urlEncode } from "./base64-B0vm543A.mjs";
2
+
3
+ //#region src/pkce.ts
4
+ async function generatePKCEPair() {
5
+ const verifierBuffer = new Uint8Array(32);
6
+ crypto.getRandomValues(verifierBuffer);
7
+ const code_verifier = base64urlEncode(verifierBuffer);
8
+ const encoder = new TextEncoder();
9
+ const challenge = await crypto.subtle.digest("SHA-256", encoder.encode(code_verifier));
10
+ return {
11
+ code_verifier,
12
+ challenge: {
13
+ code_challenge_method: "S256",
14
+ code_challenge: base64urlEncode(new Uint8Array(challenge))
15
+ }
16
+ };
17
+ }
18
+
19
+ //#endregion
20
+ export { generatePKCEPair };
21
+ //# sourceMappingURL=pkce.mjs.map
@@ -0,0 +1,36 @@
1
+ //#region src/types.d.ts
2
+ declare enum Scope {
3
+ Identify = "identify",
4
+ Email = "email",
5
+ Accounts = "accounts",
6
+ Accounts_Verified = "accounts.verified",
7
+ Accounts_DisplayName = "accounts.displayName",
8
+ GW2_Account = "gw2:account",
9
+ GW2_Inventories = "gw2:inventories",
10
+ GW2_Characters = "gw2:characters",
11
+ GW2_Tradingpost = "gw2:tradingpost",
12
+ GW2_Wallet = "gw2:wallet",
13
+ GW2_Unlocks = "gw2:unlocks",
14
+ GW2_Pvp = "gw2:pvp",
15
+ GW2_Wvw = "gw2:wvw",
16
+ GW2_Builds = "gw2:builds",
17
+ GW2_Progression = "gw2:progression",
18
+ GW2_Guilds = "gw2:guilds",
19
+ }
20
+ interface ClientInfo {
21
+ client_id: string;
22
+ client_secret?: string;
23
+ }
24
+ interface Options {
25
+ url: string;
26
+ }
27
+ interface DPoPParams {
28
+ htm: 'POST' | 'GET' | (string & {});
29
+ htu: string;
30
+ nonce?: string;
31
+ accessToken?: string;
32
+ }
33
+ type DPoPCallback = (params: DPoPParams) => string | Promise<string>;
34
+ //#endregion
35
+ export { Scope as a, Options as i, DPoPCallback as n, DPoPParams as r, ClientInfo as t };
36
+ //# sourceMappingURL=types-cXKOlCJ4.d.mts.map
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@gw2me/client",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
4
4
  "description": "gw2.me client library",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  "./package.json": "./package.json",
8
8
  ".": {
9
- "types": "./dist/index.d.ts",
10
- "default": "./dist/index.js"
9
+ "types": "./dist/index.d.mts",
10
+ "default": "./dist/index.mjs"
11
11
  },
12
12
  "./dpop": {
13
- "types": "./dist/dpop.d.ts",
14
- "default": "./dist/dpop.js"
13
+ "types": "./dist/dpop.d.mts",
14
+ "default": "./dist/dpop.mjs"
15
15
  },
16
16
  "./pkce": {
17
- "types": "./dist/pkce.d.ts",
18
- "default": "./dist/pkce.js"
17
+ "types": "./dist/pkce.d.mts",
18
+ "default": "./dist/pkce.mjs"
19
19
  }
20
20
  },
21
21
  "repository": {
@@ -30,7 +30,8 @@
30
30
  "oauth2"
31
31
  ],
32
32
  "files": [
33
- "dist/"
33
+ "dist/*.mjs",
34
+ "dist/*.d.mts"
34
35
  ],
35
36
  "author": "darthmaim",
36
37
  "license": "MIT",
@@ -43,20 +44,17 @@
43
44
  "@gw2treasures/publish-package": "0.1.0",
44
45
  "@gw2treasures/tsconfig": "0.0.1",
45
46
  "eslint": "9.39.2",
46
- "tsup": "8.5.1",
47
+ "tsdown": "0.19.0",
47
48
  "typescript": "5.9.3",
48
- "typescript-eslint": "8.51.0",
49
- "undici-types": "7.16.0"
49
+ "typescript-eslint": "8.53.0",
50
+ "undici-types": "7.18.2"
50
51
  },
51
52
  "publishConfig": {
52
53
  "access": "public",
53
54
  "provenance": true
54
55
  },
55
56
  "scripts": {
56
- "build": "pnpm run clean && if test $CI; then pnpm run build:ci; else pnpm run build:local; fi",
57
- "build:local": "tsup src/index.ts src/dpop.ts src/pkce.ts --format esm && tsc --emitDeclarationOnly --declaration --declarationMap",
58
- "build:ci": "tsup src/index.ts src/dpop.ts src/pkce.ts --format esm --minify --dts",
59
- "clean": "rm -rf dist/",
57
+ "build": "tsdown src/index.ts src/dpop.ts src/pkce.ts",
60
58
  "lint": "eslint .",
61
59
  "publish-package": "gw2treasures-publish-package"
62
60
  }
@@ -1 +0,0 @@
1
- function a(r){let e=r instanceof ArrayBuffer?new Uint8Array(r):r;return btoa(String.fromCharCode(...e)).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}export{a};
@@ -1 +0,0 @@
1
- var f=a=>{throw TypeError(a)};var d=(a,b,c)=>b.has(a)||f("Cannot "+c);var g=(a,b,c)=>(d(a,b,"read from private field"),c?c.call(a):b.get(a)),h=(a,b,c)=>b.has(a)?f("Cannot add the same private member more than once"):b instanceof WeakSet?b.add(a):b.set(a,c),i=(a,b,c,e)=>(d(a,b,"write to private field"),e?e.call(a,c):b.set(a,c),c),j=(a,b,c)=>(d(a,b,"access private method"),c);export{g as a,h as b,i as c,j as d};
package/dist/dpop.d.ts DELETED
@@ -1,7 +0,0 @@
1
- import { D as DPoPParams } from './types-yBP8cksw.js';
2
-
3
- declare function generateDPoPKeyPair(): Promise<CryptoKeyPair>;
4
- declare function createDPoPJwt({ htm, htu, nonce, accessToken }: DPoPParams, keyPair: CryptoKeyPair): Promise<string>;
5
- declare function jwkThumbprint(key: CryptoKey): Promise<string>;
6
-
7
- export { createDPoPJwt, generateDPoPKeyPair, jwkThumbprint };
package/dist/dpop.js DELETED
@@ -1 +0,0 @@
1
- import{a as e}from"./chunk-EXOYQILJ.js";import"./chunk-OSZ7DOEH.js";function d(){return crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign"])}async function m({htm:t,htu:n,nonce:r,accessToken:a},s){let c=JSON.stringify({alg:"ES256",typ:"dpop+jwt",jwk:await u(s.publicKey)}),y=JSON.stringify({iat:Math.floor(Date.now()/1e3),jti:e(crypto.getRandomValues(new Uint8Array(32))),htm:t,htu:n,nonce:r,ath:a?e(await crypto.subtle.digest("SHA-256",o(a))):void 0}),i=`${e(o(c))}.${e(o(y))}`,p={name:"ECDSA",hash:"SHA-256"},g=e(await crypto.subtle.sign(p,s.privateKey,o(i)));return`${i}.${g}`}var w=new TextEncoder;function o(t){return w.encode(t)}async function u(t){let{kty:n,e:r,k:a,n:s,x:c,y,crv:i}=await crypto.subtle.exportKey("jwk",t);return{e:r,k:a,crv:i,kty:n,n:s,x:c,y}}async function P(t){let n=JSON.stringify(await u(t)),r=await crypto.subtle.digest("SHA-256",o(n));return e(r)}export{m as createDPoPJwt,d as generateDPoPKeyPair,P as jwkThumbprint};
package/dist/index.d.ts DELETED
@@ -1,169 +0,0 @@
1
- import { O as Options, a as DPoPCallback, S as Scope, C as ClientInfo } from './types-yBP8cksw.js';
2
- export { D as DPoPParams } from './types-yBP8cksw.js';
3
-
4
- interface UserResponse {
5
- sub: string;
6
- user: {
7
- id: string;
8
- name: string;
9
- email?: string;
10
- emailVerified?: boolean;
11
- };
12
- settings?: unknown;
13
- }
14
- interface AccountsResponse {
15
- accounts: {
16
- id: string;
17
- name: string;
18
- shared: boolean;
19
- verified?: boolean;
20
- displayName?: string | null;
21
- }[];
22
- }
23
- interface SubtokenOptions {
24
- permissions?: string[];
25
- }
26
- interface SubtokenResponse {
27
- subtoken: string;
28
- expiresAt: string;
29
- }
30
- interface ApiOptions extends Options {
31
- dpop?: DPoPCallback;
32
- }
33
- declare class Gw2MeApi {
34
- #private;
35
- private access_token;
36
- private options?;
37
- constructor(access_token: string, options?: Partial<ApiOptions> | undefined);
38
- user(): Promise<UserResponse>;
39
- saveSettings(settings: unknown): Promise<void>;
40
- accounts(): Promise<AccountsResponse>;
41
- subtoken(accountId: string, options?: SubtokenOptions): Promise<SubtokenResponse>;
42
- }
43
-
44
- interface FedCMRequestOptions {
45
- scopes: Scope[];
46
- mediation?: CredentialMediationRequirement;
47
- mode?: 'passive' | 'active';
48
- signal?: AbortSignal;
49
- code_challenge: string;
50
- code_challenge_method: 'S256';
51
- /** @default true */
52
- include_granted_scopes?: boolean;
53
- }
54
- declare class Gw2MeFedCM {
55
- #private;
56
- constructor(configUrl: URL, clientId: string);
57
- isSupported(): boolean;
58
- request({ scopes, mediation, signal, mode, code_challenge, code_challenge_method, include_granted_scopes }: FedCMRequestOptions): Promise<null | {
59
- token: string;
60
- type: "identity";
61
- }>;
62
- }
63
-
64
- interface AuthorizationUrlParams {
65
- redirect_uri: string;
66
- scopes: Scope[];
67
- state?: string;
68
- code_challenge?: string;
69
- code_challenge_method?: 'S256';
70
- dpop_jkt?: string;
71
- prompt?: 'none' | 'consent';
72
- include_granted_scopes?: boolean;
73
- verified_accounts_only?: boolean;
74
- }
75
- interface PushedAuthorizationRequestParams extends AuthorizationUrlParams {
76
- dpop?: DPoPCallback;
77
- }
78
- interface AuthorizationUrlRequestUriParams {
79
- request_uri: string;
80
- }
81
- type TokenType = 'Bearer' | 'DPoP';
82
- interface AuthTokenParams {
83
- code: string;
84
- token_type?: TokenType;
85
- redirect_uri: string;
86
- code_verifier?: string;
87
- dpop?: DPoPCallback;
88
- }
89
- interface RefreshTokenParams {
90
- refresh_token: string;
91
- refresh_token_type?: TokenType;
92
- dpop?: DPoPCallback;
93
- }
94
- interface TokenResponse {
95
- access_token: string;
96
- issued_token_type: 'urn:ietf:params:oauth:token-type:access_token';
97
- token_type: TokenType;
98
- expires_in: number;
99
- refresh_token?: string;
100
- scope: string;
101
- }
102
- interface RevokeTokenParams {
103
- token: string;
104
- }
105
- interface IntrospectTokenParams {
106
- token: string;
107
- }
108
- declare namespace IntrospectTokenResponse {
109
- interface Inactive {
110
- active: false;
111
- }
112
- namespace Active {
113
- interface Common {
114
- active: true;
115
- scope: string;
116
- client_id: string;
117
- exp?: number;
118
- }
119
- interface Bearer extends Common {
120
- token_type: 'Bearer';
121
- }
122
- interface DPoP extends Common {
123
- token_type: 'DPoP';
124
- cnf: {
125
- jkt: string;
126
- };
127
- }
128
- }
129
- type Active = Active.Bearer | Active.DPoP;
130
- }
131
- type IntrospectTokenResponse = IntrospectTokenResponse.Inactive | IntrospectTokenResponse.Active;
132
- interface PushedAuthorizationRequestResponse {
133
- request_uri: string;
134
- expires_in: number;
135
- }
136
- declare class Gw2MeClient {
137
- #private;
138
- private options?;
139
- constructor(client: ClientInfo, options?: Partial<Options> | undefined);
140
- getAuthorizationUrl(params: AuthorizationUrlParams | AuthorizationUrlRequestUriParams): string;
141
- pushAuthorizationRequest(params: PushedAuthorizationRequestParams): Promise<PushedAuthorizationRequestResponse>;
142
- getAccessToken({ code, token_type, redirect_uri, code_verifier, dpop }: AuthTokenParams): Promise<TokenResponse>;
143
- refreshToken({ refresh_token, refresh_token_type, dpop }: RefreshTokenParams): Promise<TokenResponse>;
144
- revokeToken({ token }: RevokeTokenParams): Promise<void>;
145
- introspectToken({ token }: IntrospectTokenParams): Promise<IntrospectTokenResponse>;
146
- /**
147
- * Parses the search params received from gw2.me on the redirect url (code and state).
148
- * If gw2.me returned an error response, this will throw an error.
149
- *
150
- * @returns The code and optional state.
151
- */
152
- parseAuthorizationResponseSearchParams(searchParams: URLSearchParams): {
153
- code: string;
154
- state: string | undefined;
155
- };
156
- api(access_token: string, options?: Partial<Omit<ApiOptions, keyof Options>>): Gw2MeApi;
157
- get fedCM(): Gw2MeFedCM;
158
- }
159
-
160
- declare class Gw2MeError extends Error {
161
- }
162
- declare class Gw2MeOAuthError extends Gw2MeError {
163
- error: string;
164
- error_description?: string | undefined;
165
- error_uri?: string | undefined;
166
- constructor(error: string, error_description?: string | undefined, error_uri?: string | undefined);
167
- }
168
-
169
- export { type AccountsResponse, type ApiOptions, type AuthTokenParams, type AuthorizationUrlParams, type AuthorizationUrlRequestUriParams, ClientInfo, DPoPCallback, type FedCMRequestOptions, Gw2MeApi, Gw2MeClient, Gw2MeError, Gw2MeFedCM, Gw2MeOAuthError, type IntrospectTokenParams, IntrospectTokenResponse, Options, type PushedAuthorizationRequestParams, type PushedAuthorizationRequestResponse, type RefreshTokenParams, type RevokeTokenParams, Scope, type SubtokenOptions, type SubtokenResponse, type TokenResponse, type TokenType, type UserResponse };
package/dist/index.js DELETED
@@ -1 +0,0 @@
1
- import{a as s,b as m,c as _,d as o}from"./chunk-OSZ7DOEH.js";var z=(p=>(p.Identify="identify",p.Email="email",p.Accounts="accounts",p.Accounts_Verified="accounts.verified",p.Accounts_DisplayName="accounts.displayName",p.GW2_Account="gw2:account",p.GW2_Inventories="gw2:inventories",p.GW2_Characters="gw2:characters",p.GW2_Tradingpost="gw2:tradingpost",p.GW2_Wallet="gw2:wallet",p.GW2_Unlocks="gw2:unlocks",p.GW2_Pvp="gw2:pvp",p.GW2_Wvw="gw2:wvw",p.GW2_Builds="gw2:builds",p.GW2_Progression="gw2:progression",p.GW2_Guilds="gw2:guilds",p))(z||{});var h=class extends Error{},b=class extends h{constructor(t,n,r){super(`Received ${t}`+(n?`: ${n}`:"")+(r?` (${r})`:""));this.error=t;this.error_description=n;this.error_uri=r}};async function f(u){if(await C(u),!(u.headers.get("Content-Type")==="application/json"))throw new h("gw2.me did not return a valid JSON response");return u.json()}async function C(u){if(!u.ok){let e;throw u.headers.get("Content-Type")==="application/json"&&(e=(await u.json()).error_description),new h(`gw2.me returned an error: ${e??"Unknown error"}`)}}var g,U,x,v=class{constructor(e,t){this.access_token=e;this.options=t;m(this,g)}user(){return o(this,g,x).call(this,"api/user").then(e=>fetch(e)).then(f)}saveSettings(e){return o(this,g,x).call(this,"api/user/settings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}).then(t=>fetch(t)).then(C)}accounts(){return o(this,g,x).call(this,"api/accounts").then(e=>fetch(e)).then(f)}subtoken(e,t){let n=o(this,g,U).call(this,`api/accounts/${e}/subtoken`);return t?.permissions&&n.searchParams.set("permissions",t.permissions.join(",")),o(this,g,x).call(this,n).then(r=>fetch(r)).then(f)}};g=new WeakSet,U=function(e){return new URL(e,this.options?.url||"https://gw2.me/")},x=async function(e,t){let n=e instanceof URL?e:o(this,g,U).call(this,e),r=this.options?.dpop,i=new Headers(t?.headers);return i.set("Authorization",`${r?"DPoP":"Bearer"} ${this.access_token}`),r&&i.set("DPoP",await r({htm:t?.method??"GET",htu:n.toString(),accessToken:this.access_token})),new Request(n,{cache:"no-cache",...t,headers:i})};var R,T,O=class{constructor(e,t){m(this,R);m(this,T);_(this,R,e),_(this,T,t)}isSupported(){return typeof window<"u"&&"IdentityCredential"in window}request({scopes:e,mediation:t,signal:n,mode:r,code_challenge:i,code_challenge_method:d,include_granted_scopes:l}){if(!this.isSupported())throw new h("FedCM is not supported");return navigator.credentials.get({mediation:t,signal:n,identity:{providers:[{configURL:s(this,R),clientId:s(this,T),fields:[e.includes("identify")&&"name",e.includes("email")&&"email"].filter(Boolean),nonce:`${d}:${i}`,params:{scope:e.join(" "),code_challenge:i,code_challenge_method:d,include_granted_scopes:l}}],mode:r}})}};R=new WeakMap,T=new WeakMap;var a,A,c,P,y,S=class{constructor(e,t){this.options=t;m(this,c);m(this,a);m(this,A);_(this,a,e),_(this,A,new O(o(this,c,P).call(this,"/fed-cm/config.json"),e.client_id))}getAuthorizationUrl(e){let t="request_uri"in e?new URLSearchParams({client_id:s(this,a).client_id,response_type:"code",request_uri:e.request_uri}):q(s(this,a).client_id,e);return o(this,c,P).call(this,`/oauth2/authorize?${t.toString()}`).toString()}async pushAuthorizationRequest(e){let t=o(this,c,P).call(this,"/oauth2/par"),n={"Content-Type":"application/x-www-form-urlencoded"};e.dpop&&(n.DPoP=await e.dpop({htm:"POST",htu:t.toString()}));let r=q(s(this,a).client_id,e);return s(this,a).client_secret&&(n.Authorization=o(this,c,y).call(this)),await fetch(t,{method:"POST",headers:n,body:r,cache:"no-store"}).then(f)}async getAccessToken({code:e,token_type:t,redirect_uri:n,code_verifier:r,dpop:i}){let d=new URLSearchParams({grant_type:"authorization_code",code:e,client_id:s(this,a).client_id,redirect_uri:n}),l={"Content-Type":"application/x-www-form-urlencoded"};s(this,a).client_secret&&(l.Authorization=o(this,c,y).call(this)),r&&d.set("code_verifier",r);let w=o(this,c,P).call(this,"/api/token");return i&&(l.DPoP=await i({htm:"POST",htu:w.toString(),accessToken:t==="DPoP"?e:void 0})),await fetch(w,{method:"POST",headers:l,body:d,cache:"no-store"}).then(f)}async refreshToken({refresh_token:e,refresh_token_type:t,dpop:n}){let r=new URLSearchParams({grant_type:"refresh_token",refresh_token:e,client_id:s(this,a).client_id}),i={"Content-Type":"application/x-www-form-urlencoded"};s(this,a).client_secret&&(i.Authorization=o(this,c,y).call(this));let d=o(this,c,P).call(this,"/api/token");return n&&(i.DPoP=await n({htm:"POST",htu:d.toString(),accessToken:t==="DPoP"?e:void 0})),await fetch(d,{method:"POST",headers:i,body:r,cache:"no-store"}).then(f)}async revokeToken({token:e}){let t=new URLSearchParams({token:e}),n={"Content-Type":"application/x-www-form-urlencoded"};s(this,a).client_secret&&(n.Authorization=o(this,c,y).call(this)),await fetch(o(this,c,P).call(this,"/api/token/revoke"),{method:"POST",cache:"no-store",headers:n,body:t}).then(f)}async introspectToken({token:e}){let t=new URLSearchParams({token:e}),n={"Content-Type":"application/x-www-form-urlencoded"};return s(this,a).client_secret&&(n.Authorization=o(this,c,y).call(this)),await fetch(o(this,c,P).call(this,"/api/token/introspect"),{method:"POST",cache:"no-store",headers:n,body:t}).then(f)}parseAuthorizationResponseSearchParams(e){let t=o(this,c,P).call(this,"/").origin,n=e.get("iss");if(!n)throw new h("Issuer Identifier verification failed: parameter `iss` is missing");if(n!==t)throw new h(`Issuer Identifier verification failed: expected "${t}", got "${n}"`);let r=e.get("error");if(r){let l=e.get("error_description")??void 0,w=e.get("error_uri")??void 0;throw new b(r,l,w)}let i=e.get("code");if(!i)throw new h("Parameter `code` is missing");let d=e.get("state")||void 0;return{code:i,state:d}}api(e,t){return new v(e,{...this.options,...t})}get fedCM(){return s(this,A)}};a=new WeakMap,A=new WeakMap,c=new WeakSet,P=function(e){return new URL(e,this.options?.url||"https://gw2.me/")},y=function(){if(!s(this,a).client_secret)throw new h("client_secret is required");return`Basic ${btoa(`${s(this,a).client_id}:${s(this,a).client_secret}`)}`};function q(u,{redirect_uri:e,scopes:t,state:n,code_challenge:r,code_challenge_method:i,dpop_jkt:d,prompt:l,include_granted_scopes:w,verified_accounts_only:I}){let k=new URLSearchParams({client_id:u,response_type:"code",redirect_uri:e,scope:t.join(" ")});return n&&k.append("state",n),r&&i&&(k.append("code_challenge",r),k.append("code_challenge_method",i)),d&&k.append("dpop_jkt",d),l&&k.append("prompt",l),w&&k.append("include_granted_scopes","true"),I&&k.append("verified_accounts_only","true"),k}export{v as Gw2MeApi,S as Gw2MeClient,h as Gw2MeError,b as Gw2MeOAuthError,z as Scope};
package/dist/pkce.d.ts DELETED
@@ -1,11 +0,0 @@
1
- interface PKCEChallenge {
2
- code_challenge: string;
3
- code_challenge_method: 'S256';
4
- }
5
- interface PKCEPair {
6
- challenge: PKCEChallenge;
7
- code_verifier: string;
8
- }
9
- declare function generatePKCEPair(): Promise<PKCEPair>;
10
-
11
- export { type PKCEChallenge, type PKCEPair, generatePKCEPair };
package/dist/pkce.js DELETED
@@ -1 +0,0 @@
1
- import{a as e}from"./chunk-EXOYQILJ.js";import"./chunk-OSZ7DOEH.js";async function a(){let n=new Uint8Array(32);crypto.getRandomValues(n);let r=e(n),c=new TextEncoder,o=await crypto.subtle.digest("SHA-256",c.encode(r));return{code_verifier:r,challenge:{code_challenge_method:"S256",code_challenge:e(new Uint8Array(o))}}}export{a as generatePKCEPair};
@@ -1,34 +0,0 @@
1
- declare enum Scope {
2
- Identify = "identify",
3
- Email = "email",
4
- Accounts = "accounts",
5
- Accounts_Verified = "accounts.verified",
6
- Accounts_DisplayName = "accounts.displayName",
7
- GW2_Account = "gw2:account",
8
- GW2_Inventories = "gw2:inventories",
9
- GW2_Characters = "gw2:characters",
10
- GW2_Tradingpost = "gw2:tradingpost",
11
- GW2_Wallet = "gw2:wallet",
12
- GW2_Unlocks = "gw2:unlocks",
13
- GW2_Pvp = "gw2:pvp",
14
- GW2_Wvw = "gw2:wvw",
15
- GW2_Builds = "gw2:builds",
16
- GW2_Progression = "gw2:progression",
17
- GW2_Guilds = "gw2:guilds"
18
- }
19
- interface ClientInfo {
20
- client_id: string;
21
- client_secret?: string;
22
- }
23
- interface Options {
24
- url: string;
25
- }
26
- interface DPoPParams {
27
- htm: 'POST' | 'GET' | (string & {});
28
- htu: string;
29
- nonce?: string;
30
- accessToken?: string;
31
- }
32
- type DPoPCallback = (params: DPoPParams) => string | Promise<string>;
33
-
34
- export { type ClientInfo as C, type DPoPParams as D, type Options as O, Scope as S, type DPoPCallback as a };