@gw2me/client 0.9.3 → 0.9.4
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/base64-p0iUDSbg.js +1 -0
- package/dist/dpop.d.ts +25 -0
- package/dist/dpop.js +1 -0
- package/dist/{index.d.mts → index.d.ts} +68 -16
- package/dist/index.js +1 -0
- package/dist/pkce.d.ts +16 -0
- package/dist/pkce.js +1 -0
- package/dist/{types-cXKOlCJ4.d.mts → types-Bqy6G8sj.d.ts} +7 -4
- package/package.json +18 -14
- package/dist/base64-B0vm543A.mjs +0 -9
- package/dist/dpop.d.mts +0 -14
- package/dist/dpop.mjs +0 -53
- package/dist/index.mjs +0 -289
- package/dist/pkce.d.mts +0 -13
- package/dist/pkce.mjs +0 -21
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e){let t=e instanceof ArrayBuffer?new Uint8Array(e):e;return Uint8Array.prototype.toBase64===void 0?btoa(String.fromCharCode(...t)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``):t.toBase64({alphabet:`base64url`,omitPadding:!0})}export{e as t};
|
package/dist/dpop.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { r as DPoPParams } from "./types-Bqy6G8sj.js";
|
|
2
|
+
|
|
3
|
+
//#region src/dpop.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Generates a new key pair for use with DPoP.
|
|
6
|
+
* @see https://gw2.me/dev/docs/access-tokens#dpop
|
|
7
|
+
*/
|
|
8
|
+
declare function generateDPoPKeyPair(): Promise<CryptoKeyPair>;
|
|
9
|
+
/**
|
|
10
|
+
* Creates a DPoP proof JWT with the given parameters and key pair.
|
|
11
|
+
* @see https://gw2.me/dev/docs/access-tokens#dpop
|
|
12
|
+
*/
|
|
13
|
+
declare function createDPoPJwt({
|
|
14
|
+
htm,
|
|
15
|
+
htu,
|
|
16
|
+
nonce,
|
|
17
|
+
accessToken
|
|
18
|
+
}: DPoPParams, keyPair: CryptoKeyPair): Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Calculates the JWK thumbprint for a given public key.
|
|
21
|
+
* @see https://gw2.me/dev/docs/access-tokens#dpop
|
|
22
|
+
*/
|
|
23
|
+
declare function jwkThumbprint(key: CryptoKey): Promise<string>;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { createDPoPJwt, generateDPoPKeyPair, jwkThumbprint };
|
package/dist/dpop.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./base64-p0iUDSbg.js";function t(){return crypto.subtle.generateKey({name:`ECDSA`,namedCurve:`P-256`},!1,[`sign`])}async function n({htm:t,htu:n,nonce:r,accessToken:o},s){let c=JSON.stringify({alg:`ES256`,typ:`dpop+jwt`,jwk:await a(s.publicKey)}),l=JSON.stringify({iat:Math.floor(Date.now()/1e3),jti:e(crypto.getRandomValues(new Uint8Array(32))),htm:t,htu:n,nonce:r,ath:o?e(await crypto.subtle.digest(`SHA-256`,i(o))):void 0}),u=`${e(i(c))}.${e(i(l))}`;return`${u}.${e(await crypto.subtle.sign({name:`ECDSA`,hash:`SHA-256`},s.privateKey,i(u)))}`}const r=new TextEncoder;function i(e){return r.encode(e)}async function a(e){let{kty:t,e:n,k:r,n:i,x:a,y:o,crv:s}=await crypto.subtle.exportKey(`jwk`,e);return{e:n,k:r,crv:s,kty:t,n:i,x:a,y:o}}async function o(t){let n=JSON.stringify(await a(t));return e(await crypto.subtle.digest(`SHA-256`,i(n)))}export{n as createDPoPJwt,t as generateDPoPKeyPair,o as jwkThumbprint};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as Scope, i as Options, n as DPoPCallback, r as DPoPParams, t as ClientInfo } from "./types-
|
|
1
|
+
import { a as Scope, i as Options, n as DPoPCallback, r as DPoPParams, t as ClientInfo } from "./types-Bqy6G8sj.js";
|
|
2
2
|
|
|
3
3
|
//#region src/api.d.ts
|
|
4
4
|
interface UserResponse {
|
|
@@ -35,9 +35,25 @@ declare class Gw2MeApi {
|
|
|
35
35
|
private access_token;
|
|
36
36
|
private options?;
|
|
37
37
|
constructor(access_token: string, options?: Partial<ApiOptions> | undefined);
|
|
38
|
+
/**
|
|
39
|
+
* Fetches information about the current user. Requires the `identify` scope.
|
|
40
|
+
* @see https://gw2.me/dev/docs/users
|
|
41
|
+
*/
|
|
38
42
|
user(): Promise<UserResponse>;
|
|
43
|
+
/**
|
|
44
|
+
* Stores user-specific settings.
|
|
45
|
+
* @see https://gw2.me/dev/docs/users#settings
|
|
46
|
+
*/
|
|
39
47
|
saveSettings(settings: unknown): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Fetches the Guild Wars 2 accounts linked to the current user. Requires the `accounts` scope.
|
|
50
|
+
* @see https://gw2.me/dev/docs/gw2-api#accounts
|
|
51
|
+
*/
|
|
40
52
|
accounts(): Promise<AccountsResponse>;
|
|
53
|
+
/**
|
|
54
|
+
* Generates a subtoken that can be used to authenticate to the Guild Wars 2 API.
|
|
55
|
+
* @see https://gw2.me/dev/docs/gw2-api#subtoken
|
|
56
|
+
*/
|
|
41
57
|
subtoken(accountId: string, options?: SubtokenOptions): Promise<SubtokenResponse>;
|
|
42
58
|
}
|
|
43
59
|
//#endregion
|
|
@@ -45,17 +61,24 @@ declare class Gw2MeApi {
|
|
|
45
61
|
interface FedCMRequestOptions {
|
|
46
62
|
scopes: Scope[];
|
|
47
63
|
mediation?: CredentialMediationRequirement;
|
|
48
|
-
mode?:
|
|
64
|
+
mode?: "passive" | "active";
|
|
49
65
|
signal?: AbortSignal;
|
|
50
66
|
code_challenge: string;
|
|
51
|
-
code_challenge_method:
|
|
67
|
+
code_challenge_method: "S256";
|
|
52
68
|
/** @default true */
|
|
53
69
|
include_granted_scopes?: boolean;
|
|
54
70
|
}
|
|
55
71
|
declare class Gw2MeFedCM {
|
|
56
72
|
#private;
|
|
57
73
|
constructor(configUrl: URL, clientId: string);
|
|
74
|
+
/**
|
|
75
|
+
* Check if FedCM is supported in the current environment.
|
|
76
|
+
*/
|
|
58
77
|
isSupported(): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Start a FedCM sign-in flow with the given options. Resolves with the credential containing the access token on success, or null if the user cancels the flow.
|
|
80
|
+
* @see https://gw2.me/dev/docs/fed-cm
|
|
81
|
+
*/
|
|
59
82
|
request({
|
|
60
83
|
scopes,
|
|
61
84
|
mediation,
|
|
@@ -76,9 +99,9 @@ interface AuthorizationUrlParams {
|
|
|
76
99
|
scopes: Scope[];
|
|
77
100
|
state?: string;
|
|
78
101
|
code_challenge?: string;
|
|
79
|
-
code_challenge_method?:
|
|
102
|
+
code_challenge_method?: "S256";
|
|
80
103
|
dpop_jkt?: string;
|
|
81
|
-
prompt?:
|
|
104
|
+
prompt?: "none" | "consent";
|
|
82
105
|
include_granted_scopes?: boolean;
|
|
83
106
|
verified_accounts_only?: boolean;
|
|
84
107
|
}
|
|
@@ -88,7 +111,7 @@ interface PushedAuthorizationRequestParams extends AuthorizationUrlParams {
|
|
|
88
111
|
interface AuthorizationUrlRequestUriParams {
|
|
89
112
|
request_uri: string;
|
|
90
113
|
}
|
|
91
|
-
type TokenType =
|
|
114
|
+
type TokenType = "Bearer" | "DPoP";
|
|
92
115
|
interface AuthTokenParams {
|
|
93
116
|
code: string;
|
|
94
117
|
token_type?: TokenType;
|
|
@@ -103,7 +126,7 @@ interface RefreshTokenParams {
|
|
|
103
126
|
}
|
|
104
127
|
interface TokenResponse {
|
|
105
128
|
access_token: string;
|
|
106
|
-
issued_token_type:
|
|
129
|
+
issued_token_type: "urn:ietf:params:oauth:token-type:access_token";
|
|
107
130
|
token_type: TokenType;
|
|
108
131
|
expires_in: number;
|
|
109
132
|
refresh_token?: string;
|
|
@@ -127,10 +150,10 @@ declare namespace IntrospectTokenResponse {
|
|
|
127
150
|
exp?: number;
|
|
128
151
|
}
|
|
129
152
|
interface Bearer extends Common {
|
|
130
|
-
token_type:
|
|
153
|
+
token_type: "Bearer";
|
|
131
154
|
}
|
|
132
155
|
interface DPoP extends Common {
|
|
133
|
-
token_type:
|
|
156
|
+
token_type: "DPoP";
|
|
134
157
|
cnf: {
|
|
135
158
|
jkt: string;
|
|
136
159
|
};
|
|
@@ -147,8 +170,21 @@ declare class Gw2MeClient {
|
|
|
147
170
|
#private;
|
|
148
171
|
private options?;
|
|
149
172
|
constructor(client: ClientInfo, options?: Partial<Options> | undefined);
|
|
173
|
+
/**
|
|
174
|
+
* Generate an authorization URL with the given parameters you can navigate the user to in order to start the authorization code flow.
|
|
175
|
+
* @see https://gw2.me/dev/docs/access-tokens#user-authorization
|
|
176
|
+
*/
|
|
150
177
|
getAuthorizationUrl(params: AuthorizationUrlParams | AuthorizationUrlRequestUriParams): string;
|
|
178
|
+
/**
|
|
179
|
+
* Create a pushed authorization request (PAR) with the given parameters.
|
|
180
|
+
* The returned `request_uri` can the be passed to {@link getAuthorizationUrl} to start the authorization code flow.
|
|
181
|
+
* @see https://gw2.me/dev/docs/access-tokens#par
|
|
182
|
+
*/
|
|
151
183
|
pushAuthorizationRequest(params: PushedAuthorizationRequestParams): Promise<PushedAuthorizationRequestResponse>;
|
|
184
|
+
/**
|
|
185
|
+
* Exchanges an authorization code for an access token.
|
|
186
|
+
* @see https://gw2.me/dev/docs/access-tokens#access-token
|
|
187
|
+
*/
|
|
152
188
|
getAccessToken({
|
|
153
189
|
code,
|
|
154
190
|
token_type,
|
|
@@ -156,28 +192,45 @@ declare class Gw2MeClient {
|
|
|
156
192
|
code_verifier,
|
|
157
193
|
dpop
|
|
158
194
|
}: AuthTokenParams): Promise<TokenResponse>;
|
|
195
|
+
/**
|
|
196
|
+
* Use a refresh token to get a new access token.
|
|
197
|
+
* @see https://gw2.me/dev/docs/refresh-tokens
|
|
198
|
+
*/
|
|
159
199
|
refreshToken({
|
|
160
200
|
refresh_token,
|
|
161
201
|
refresh_token_type,
|
|
162
202
|
dpop
|
|
163
203
|
}: RefreshTokenParams): Promise<TokenResponse>;
|
|
204
|
+
/**
|
|
205
|
+
* Revokes an access or refresh token, making it invalid for further use.
|
|
206
|
+
*/
|
|
164
207
|
revokeToken({
|
|
165
208
|
token
|
|
166
209
|
}: RevokeTokenParams): Promise<void>;
|
|
210
|
+
/**
|
|
211
|
+
* Fetch metadata about an access or refresh token.
|
|
212
|
+
*/
|
|
167
213
|
introspectToken({
|
|
168
214
|
token
|
|
169
215
|
}: IntrospectTokenParams): Promise<IntrospectTokenResponse>;
|
|
170
216
|
/**
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
217
|
+
* Parses the search params received from gw2.me on the redirect url (code and state).
|
|
218
|
+
* If gw2.me returned an error response, this will throw an error.
|
|
219
|
+
*
|
|
220
|
+
* @returns The code and optional state.
|
|
221
|
+
*/
|
|
176
222
|
parseAuthorizationResponseSearchParams(searchParams: URLSearchParams): {
|
|
177
223
|
code: string;
|
|
178
224
|
state: string | undefined;
|
|
179
225
|
};
|
|
226
|
+
/**
|
|
227
|
+
* Access the gw2.me API.
|
|
228
|
+
*/
|
|
180
229
|
api(access_token: string, options?: Partial<Omit<ApiOptions, keyof Options>>): Gw2MeApi;
|
|
230
|
+
/**
|
|
231
|
+
* Use Federated Credential Management (FedCM) to sign in users.
|
|
232
|
+
* @see https://gw2.me/dev/docs/fed-cm
|
|
233
|
+
*/
|
|
181
234
|
get fedCM(): Gw2MeFedCM;
|
|
182
235
|
}
|
|
183
236
|
//#endregion
|
|
@@ -190,5 +243,4 @@ declare class Gw2MeOAuthError extends Gw2MeError {
|
|
|
190
243
|
constructor(error: string, error_description?: string | undefined, error_uri?: string | undefined);
|
|
191
244
|
}
|
|
192
245
|
//#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
|
|
246
|
+
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 };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let e=function(e){return e.Identify=`identify`,e.Email=`email`,e.Accounts=`accounts`,e.Accounts_Verified=`accounts.verified`,e.Accounts_DisplayName=`accounts.displayName`,e.GW2_Account=`gw2:account`,e.GW2_Inventories=`gw2:inventories`,e.GW2_Characters=`gw2:characters`,e.GW2_Tradingpost=`gw2:tradingpost`,e.GW2_Wallet=`gw2:wallet`,e.GW2_Unlocks=`gw2:unlocks`,e.GW2_Pvp=`gw2:pvp`,e.GW2_Wvw=`gw2:wvw`,e.GW2_Builds=`gw2:builds`,e.GW2_Progression=`gw2:progression`,e.GW2_Guilds=`gw2:guilds`,e}({});var t=class extends Error{},n=class extends t{constructor(e,t,n){super(`Received ${e}`+(t?`: ${t}`:``)+(n?` (${n})`:``)),this.error=e,this.error_description=t,this.error_uri=n}};async function r(e){if(await i(e),!a(e))throw new t(`gw2.me did not return a valid JSON response`);return e.json()}async function i(e){if(!e.ok){let n;throw a(e)&&(n=(await e.json()).error_description),new t(`gw2.me returned an error: ${n??`Unknown error`}`)}}function a(e){return e.headers.get(`Content-Type`)?.split(`;`)[0].trim().toLowerCase()===`application/json`}var o=class{constructor(e,t){this.access_token=e,this.options=t}user(){return this.#t(`api/user`).then(e=>fetch(e)).then(r)}saveSettings(e){return this.#t(`api/user/settings`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)}).then(e=>fetch(e)).then(i)}accounts(){return this.#t(`api/accounts`).then(e=>fetch(e)).then(r)}subtoken(e,t){let n=this.#e(`api/accounts/${e}/subtoken`);return t?.permissions&&n.searchParams.set(`permissions`,t.permissions.join(`,`)),this.#t(n).then(e=>fetch(e)).then(r)}#e(e){return new URL(e,this.options?.url||`https://gw2.me/`)}async#t(e,t){let n=e instanceof URL?e:this.#e(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})}},s=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}isSupported(){return typeof window<`u`&&`IdentityCredential`in window}request({scopes:n,mediation:r,signal:i,mode:a,code_challenge:o,code_challenge_method:s,include_granted_scopes:c}){if(!this.isSupported())throw new t(`FedCM is not supported`);return navigator.credentials.get({mediation:r,signal:i,identity:{providers:[{configURL:this.#e,clientId:this.#t,fields:[n.includes(e.Identify)&&`name`,n.includes(e.Email)&&`email`].filter(Boolean),nonce:`${s}:${o}`,params:{scope:n.join(` `),code_challenge:o,code_challenge_method:s,include_granted_scopes:c}}],mode:a}})}},c=class{#e;#t;constructor(e,t){this.options=t,this.#e=e,this.#t=new s(this.#n(`/fed-cm/config.json`),e.client_id)}#n(e){return new URL(e,this.options?.url||`https://gw2.me/`)}#r(){if(!this.#e.client_secret)throw new t(`client_secret is required`);return`Basic ${btoa(`${this.#e.client_id}:${this.#e.client_secret}`)}`}getAuthorizationUrl(e){let t=`request_uri`in e?new URLSearchParams({client_id:this.#e.client_id,response_type:`code`,request_uri:e.request_uri}):l(this.#e.client_id,e);return this.#n(`/oauth2/authorize?${t.toString()}`).toString()}async pushAuthorizationRequest(e){let t=this.#n(`/oauth2/par`),n={"Content-Type":`application/x-www-form-urlencoded`};e.dpop&&(n.DPoP=await e.dpop({htm:`POST`,htu:t.toString()}));let i=l(this.#e.client_id,e);return this.#e.client_secret&&(n.Authorization=this.#r()),await fetch(t,{method:`POST`,headers:n,body:i,cache:`no-store`}).then(r)}async getAccessToken({code:e,token_type:t,redirect_uri:n,code_verifier:i,dpop:a}){let o=new URLSearchParams({grant_type:`authorization_code`,code:e,client_id:this.#e.client_id,redirect_uri:n}),s={"Content-Type":`application/x-www-form-urlencoded`};this.#e.client_secret&&(s.Authorization=this.#r()),i&&o.set(`code_verifier`,i);let c=this.#n(`/api/token`);return a&&(s.DPoP=await a({htm:`POST`,htu:c.toString(),accessToken:t===`DPoP`?e:void 0})),await fetch(c,{method:`POST`,headers:s,body:o,cache:`no-store`}).then(r)}async refreshToken({refresh_token:e,refresh_token_type:t,dpop:n}){let i=new URLSearchParams({grant_type:`refresh_token`,refresh_token:e,client_id:this.#e.client_id}),a={"Content-Type":`application/x-www-form-urlencoded`};this.#e.client_secret&&(a.Authorization=this.#r());let o=this.#n(`/api/token`);return n&&(a.DPoP=await n({htm:`POST`,htu:o.toString(),accessToken:t===`DPoP`?e:void 0})),await fetch(o,{method:`POST`,headers:a,body:i,cache:`no-store`}).then(r)}async revokeToken({token:e}){let t=new URLSearchParams({token:e}),n={"Content-Type":`application/x-www-form-urlencoded`};this.#e.client_secret&&(n.Authorization=this.#r()),await fetch(this.#n(`/api/token/revoke`),{method:`POST`,cache:`no-store`,headers:n,body:t}).then(r)}async introspectToken({token:e}){let t=new URLSearchParams({token:e}),n={"Content-Type":`application/x-www-form-urlencoded`};return this.#e.client_secret&&(n.Authorization=this.#r()),await fetch(this.#n(`/api/token/introspect`),{method:`POST`,cache:`no-store`,headers:n,body:t}).then(r)}parseAuthorizationResponseSearchParams(e){let r=this.#n(`/`).origin,i=e.get(`iss`);if(!i)throw new t("Issuer Identifier verification failed: parameter `iss` is missing");if(i!==r)throw new t(`Issuer Identifier verification failed: expected "${r}", got "${i}"`);let a=e.get(`error`);if(a)throw new n(a,e.get(`error_description`)??void 0,e.get(`error_uri`)??void 0);let o=e.get(`code`);if(!o)throw new t("Parameter `code` is missing");return{code:o,state:e.get(`state`)||void 0}}api(e,t){return new o(e,{...this.options,...t})}get fedCM(){return this.#t}};function l(e,{redirect_uri:t,scopes:n,state:r,code_challenge:i,code_challenge_method:a,dpop_jkt:o,prompt:s,include_granted_scopes:c,verified_accounts_only:l}){let u=new URLSearchParams({client_id:e,response_type:`code`,redirect_uri:t,scope:n.join(` `)});return r&&u.append(`state`,r),i&&a&&(u.append(`code_challenge`,i),u.append(`code_challenge_method`,a)),o&&u.append(`dpop_jkt`,o),s&&u.append(`prompt`,s),c&&u.append(`include_granted_scopes`,`true`),l&&u.append(`verified_accounts_only`,`true`),u}export{o as Gw2MeApi,c as Gw2MeClient,t as Gw2MeError,n as Gw2MeOAuthError,e as Scope};
|
package/dist/pkce.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
/**
|
|
11
|
+
* Generates a PKCE pair containing a random code verifier and a corresponding code challenge.
|
|
12
|
+
* @see https://gw2.me/dev/docs/access-tokens#pkce
|
|
13
|
+
*/
|
|
14
|
+
declare function generatePKCEPair(): Promise<PKCEPair>;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { PKCEChallenge, PKCEPair, generatePKCEPair };
|
package/dist/pkce.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./base64-p0iUDSbg.js";async function t(){let t=new Uint8Array(32);crypto.getRandomValues(t);let n=e(t),r=new TextEncoder,i=await crypto.subtle.digest(`SHA-256`,r.encode(n));return{code_verifier:n,challenge:{code_challenge_method:`S256`,code_challenge:e(new Uint8Array(i))}}}export{t as generatePKCEPair};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
//#region src/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Scopes supported by gw2.me.
|
|
4
|
+
* @see https://gw2.me/dev/docs/scopes
|
|
5
|
+
*/
|
|
2
6
|
declare enum Scope {
|
|
3
7
|
Identify = "identify",
|
|
4
8
|
Email = "email",
|
|
@@ -15,7 +19,7 @@ declare enum Scope {
|
|
|
15
19
|
GW2_Wvw = "gw2:wvw",
|
|
16
20
|
GW2_Builds = "gw2:builds",
|
|
17
21
|
GW2_Progression = "gw2:progression",
|
|
18
|
-
GW2_Guilds = "gw2:guilds"
|
|
22
|
+
GW2_Guilds = "gw2:guilds"
|
|
19
23
|
}
|
|
20
24
|
interface ClientInfo {
|
|
21
25
|
client_id: string;
|
|
@@ -25,12 +29,11 @@ interface Options {
|
|
|
25
29
|
url: string;
|
|
26
30
|
}
|
|
27
31
|
interface DPoPParams {
|
|
28
|
-
htm:
|
|
32
|
+
htm: "POST" | "GET" | (string & {});
|
|
29
33
|
htu: string;
|
|
30
34
|
nonce?: string;
|
|
31
35
|
accessToken?: string;
|
|
32
36
|
}
|
|
33
37
|
type DPoPCallback = (params: DPoPParams) => string | Promise<string>;
|
|
34
38
|
//#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
|
|
39
|
+
export { Scope as a, Options as i, DPoPCallback as n, DPoPParams as r, ClientInfo as t };
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gw2me/client",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.4",
|
|
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.
|
|
10
|
-
"default": "./dist/index.
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
11
|
},
|
|
12
12
|
"./dpop": {
|
|
13
|
-
"types": "./dist/dpop.d.
|
|
14
|
-
"default": "./dist/dpop.
|
|
13
|
+
"types": "./dist/dpop.d.ts",
|
|
14
|
+
"default": "./dist/dpop.js"
|
|
15
15
|
},
|
|
16
16
|
"./pkce": {
|
|
17
|
-
"types": "./dist/pkce.d.
|
|
18
|
-
"default": "./dist/pkce.
|
|
17
|
+
"types": "./dist/pkce.d.ts",
|
|
18
|
+
"default": "./dist/pkce.js"
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"repository": {
|
|
@@ -30,9 +30,10 @@
|
|
|
30
30
|
"oauth2"
|
|
31
31
|
],
|
|
32
32
|
"files": [
|
|
33
|
-
"dist/*.
|
|
34
|
-
"dist/*.d.
|
|
33
|
+
"dist/*.js",
|
|
34
|
+
"dist/*.d.ts"
|
|
35
35
|
],
|
|
36
|
+
"sideEffects": false,
|
|
36
37
|
"author": "darthmaim",
|
|
37
38
|
"license": "MIT",
|
|
38
39
|
"bugs": {
|
|
@@ -40,14 +41,17 @@
|
|
|
40
41
|
},
|
|
41
42
|
"homepage": "https://github.com/gw2treasures/gw2.me#readme",
|
|
42
43
|
"devDependencies": {
|
|
43
|
-
"@
|
|
44
|
+
"@arethetypeswrong/core": "0.18.2",
|
|
45
|
+
"@gw2treasures/eslint-config": "0.2.1",
|
|
44
46
|
"@gw2treasures/publish-package": "0.1.0",
|
|
45
47
|
"@gw2treasures/tsconfig": "0.0.1",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
+
"@types/node": "24.12.0",
|
|
49
|
+
"eslint": "9.39.4",
|
|
50
|
+
"publint": "0.3.18",
|
|
51
|
+
"tsdown": "0.21.4",
|
|
48
52
|
"typescript": "5.9.3",
|
|
49
|
-
"typescript-eslint": "8.
|
|
50
|
-
"undici-types": "7.
|
|
53
|
+
"typescript-eslint": "8.57.1",
|
|
54
|
+
"undici-types": "7.24.4"
|
|
51
55
|
},
|
|
52
56
|
"publishConfig": {
|
|
53
57
|
"access": "public",
|
package/dist/base64-B0vm543A.mjs
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
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
|
package/dist/dpop.d.mts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
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
|
package/dist/index.mjs
DELETED
|
@@ -1,289 +0,0 @@
|
|
|
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
|
package/dist/pkce.d.mts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
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
|