@logto/client 1.1.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/errors.cjs +17 -0
- package/lib/errors.d.ts +3 -6
- package/lib/errors.js +4 -22
- package/lib/{index.mjs → index.cjs} +71 -36
- package/lib/index.d.ts +10 -17
- package/lib/index.js +40 -71
- package/lib/mock.d.ts +3 -3
- package/lib/types/{index.mjs → index.cjs} +8 -5
- package/lib/types/index.js +5 -8
- package/lib/utils/index.cjs +9 -0
- package/lib/utils/index.d.ts +1 -1
- package/lib/utils/index.js +3 -6
- package/lib/utils/once.cjs +20 -0
- package/lib/utils/once.d.ts +3 -0
- package/lib/utils/once.js +18 -0
- package/lib/utils/{requester.mjs → requester.cjs} +7 -5
- package/lib/utils/requester.js +5 -7
- package/package.json +24 -29
- package/lib/errors.mjs +0 -27
- package/lib/utils/index.mjs +0 -6
package/lib/errors.cjs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const logtoClientErrorCodes = Object.freeze({
|
|
4
|
+
'sign_in_session.invalid': 'Invalid sign-in session.',
|
|
5
|
+
'sign_in_session.not_found': 'Sign-in session not found.',
|
|
6
|
+
not_authenticated: 'Not authenticated.',
|
|
7
|
+
fetch_user_info_failed: 'Unable to fetch user info. The access token may be invalid.',
|
|
8
|
+
});
|
|
9
|
+
class LogtoClientError extends Error {
|
|
10
|
+
constructor(code, data) {
|
|
11
|
+
super(logtoClientErrorCodes[code]);
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.data = data;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
exports.LogtoClientError = LogtoClientError;
|
package/lib/errors.d.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import type { NormalizeKeyPaths } from '@silverhand/essentials';
|
|
2
1
|
declare const logtoClientErrorCodes: Readonly<{
|
|
3
|
-
sign_in_session:
|
|
4
|
-
|
|
5
|
-
not_found: string;
|
|
6
|
-
};
|
|
2
|
+
'sign_in_session.invalid': "Invalid sign-in session.";
|
|
3
|
+
'sign_in_session.not_found': "Sign-in session not found.";
|
|
7
4
|
not_authenticated: "Not authenticated.";
|
|
8
5
|
fetch_user_info_failed: "Unable to fetch user info. The access token may be invalid.";
|
|
9
6
|
}>;
|
|
10
|
-
export type LogtoClientErrorCode =
|
|
7
|
+
export type LogtoClientErrorCode = keyof typeof logtoClientErrorCodes;
|
|
11
8
|
export declare class LogtoClientError extends Error {
|
|
12
9
|
code: LogtoClientErrorCode;
|
|
13
10
|
data: unknown;
|
package/lib/errors.js
CHANGED
|
@@ -1,33 +1,15 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var get = require('lodash.get');
|
|
4
|
-
|
|
5
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
|
-
|
|
7
|
-
var get__default = /*#__PURE__*/_interopDefault(get);
|
|
8
|
-
|
|
9
1
|
const logtoClientErrorCodes = Object.freeze({
|
|
10
|
-
sign_in_session:
|
|
11
|
-
|
|
12
|
-
not_found: 'Sign-in session not found.',
|
|
13
|
-
},
|
|
2
|
+
'sign_in_session.invalid': 'Invalid sign-in session.',
|
|
3
|
+
'sign_in_session.not_found': 'Sign-in session not found.',
|
|
14
4
|
not_authenticated: 'Not authenticated.',
|
|
15
5
|
fetch_user_info_failed: 'Unable to fetch user info. The access token may be invalid.',
|
|
16
6
|
});
|
|
17
|
-
const getMessageByErrorCode = (errorCode) => {
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
19
|
-
const message = get__default.default(logtoClientErrorCodes, errorCode);
|
|
20
|
-
if (typeof message === 'string') {
|
|
21
|
-
return message;
|
|
22
|
-
}
|
|
23
|
-
return errorCode;
|
|
24
|
-
};
|
|
25
7
|
class LogtoClientError extends Error {
|
|
26
8
|
constructor(code, data) {
|
|
27
|
-
super(
|
|
9
|
+
super(logtoClientErrorCodes[code]);
|
|
28
10
|
this.code = code;
|
|
29
11
|
this.data = data;
|
|
30
12
|
}
|
|
31
13
|
}
|
|
32
14
|
|
|
33
|
-
|
|
15
|
+
export { LogtoClientError };
|
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var js = require('@logto/js');
|
|
6
|
+
var jose = require('jose');
|
|
7
|
+
var errors = require('./errors.cjs');
|
|
8
|
+
var index = require('./types/index.cjs');
|
|
9
|
+
var index$1 = require('./utils/index.cjs');
|
|
10
|
+
var once = require('./utils/once.cjs');
|
|
11
|
+
var requester = require('./utils/requester.cjs');
|
|
9
12
|
|
|
10
13
|
class LogtoClient {
|
|
11
14
|
constructor(logtoConfig, adapter) {
|
|
12
|
-
this.getOidcConfig = once(this._getOidcConfig);
|
|
13
|
-
this.getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);
|
|
15
|
+
this.getOidcConfig = once.once(this._getOidcConfig);
|
|
16
|
+
this.getJwtVerifyGetKey = once.once(this._getJwtVerifyGetKey);
|
|
14
17
|
this.accessTokenMap = new Map();
|
|
15
18
|
this.logtoConfig = {
|
|
16
19
|
...logtoConfig,
|
|
17
|
-
prompt: logtoConfig.prompt ?? Prompt.Consent,
|
|
18
|
-
scopes: withDefaultScopes(logtoConfig.scopes).split(' '),
|
|
20
|
+
prompt: logtoConfig.prompt ?? js.Prompt.Consent,
|
|
21
|
+
scopes: js.withDefaultScopes(logtoConfig.scopes).split(' '),
|
|
19
22
|
};
|
|
20
23
|
this.adapter = adapter;
|
|
21
24
|
void this.loadAccessTokenMap();
|
|
@@ -31,9 +34,9 @@ class LogtoClient {
|
|
|
31
34
|
}
|
|
32
35
|
async getAccessToken(resource) {
|
|
33
36
|
if (!(await this.getIdToken())) {
|
|
34
|
-
throw new LogtoClientError('not_authenticated');
|
|
37
|
+
throw new errors.LogtoClientError('not_authenticated');
|
|
35
38
|
}
|
|
36
|
-
const accessTokenKey = buildAccessTokenKey(resource);
|
|
39
|
+
const accessTokenKey = index$1.buildAccessTokenKey(resource);
|
|
37
40
|
const accessToken = this.accessTokenMap.get(accessTokenKey);
|
|
38
41
|
if (accessToken && accessToken.expiresAt > Date.now() / 1000) {
|
|
39
42
|
return accessToken.token;
|
|
@@ -50,17 +53,21 @@ class LogtoClient {
|
|
|
50
53
|
async getIdTokenClaims() {
|
|
51
54
|
const idToken = await this.getIdToken();
|
|
52
55
|
if (!idToken) {
|
|
53
|
-
throw new LogtoClientError('not_authenticated');
|
|
56
|
+
throw new errors.LogtoClientError('not_authenticated');
|
|
54
57
|
}
|
|
55
|
-
return decodeIdToken(idToken);
|
|
58
|
+
return js.decodeIdToken(idToken);
|
|
59
|
+
}
|
|
60
|
+
async getAccessTokenClaims(resource) {
|
|
61
|
+
const accessToken = await this.getAccessToken(resource);
|
|
62
|
+
return js.decodeAccessToken(accessToken);
|
|
56
63
|
}
|
|
57
64
|
async fetchUserInfo() {
|
|
58
65
|
const { userinfoEndpoint } = await this.getOidcConfig();
|
|
59
66
|
const accessToken = await this.getAccessToken();
|
|
60
67
|
if (!accessToken) {
|
|
61
|
-
throw new LogtoClientError('fetch_user_info_failed');
|
|
68
|
+
throw new errors.LogtoClientError('fetch_user_info_failed');
|
|
62
69
|
}
|
|
63
|
-
return fetchUserInfo(userinfoEndpoint, accessToken, this.adapter.requester);
|
|
70
|
+
return js.fetchUserInfo(userinfoEndpoint, accessToken, this.adapter.requester);
|
|
64
71
|
}
|
|
65
72
|
async signIn(redirectUri, interactionMode) {
|
|
66
73
|
const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;
|
|
@@ -68,7 +75,7 @@ class LogtoClient {
|
|
|
68
75
|
const codeVerifier = this.adapter.generateCodeVerifier();
|
|
69
76
|
const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);
|
|
70
77
|
const state = this.adapter.generateState();
|
|
71
|
-
const signInUri = generateSignInUri({
|
|
78
|
+
const signInUri = js.generateSignInUri({
|
|
72
79
|
authorizationEndpoint,
|
|
73
80
|
clientId,
|
|
74
81
|
redirectUri,
|
|
@@ -98,13 +105,13 @@ class LogtoClient {
|
|
|
98
105
|
const { requester } = adapter;
|
|
99
106
|
const signInSession = await this.getSignInSession();
|
|
100
107
|
if (!signInSession) {
|
|
101
|
-
throw new LogtoClientError('sign_in_session.not_found');
|
|
108
|
+
throw new errors.LogtoClientError('sign_in_session.not_found');
|
|
102
109
|
}
|
|
103
110
|
const { redirectUri, state, codeVerifier } = signInSession;
|
|
104
|
-
const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);
|
|
111
|
+
const code = js.verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);
|
|
105
112
|
const { appId: clientId } = logtoConfig;
|
|
106
113
|
const { tokenEndpoint } = await this.getOidcConfig();
|
|
107
|
-
const codeTokenResponse = await fetchTokenByAuthorizationCode({
|
|
114
|
+
const codeTokenResponse = await js.fetchTokenByAuthorizationCode({
|
|
108
115
|
clientId,
|
|
109
116
|
tokenEndpoint,
|
|
110
117
|
redirectUri,
|
|
@@ -121,13 +128,13 @@ class LogtoClient {
|
|
|
121
128
|
const refreshToken = await this.getRefreshToken();
|
|
122
129
|
if (refreshToken) {
|
|
123
130
|
try {
|
|
124
|
-
await revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester);
|
|
131
|
+
await js.revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester);
|
|
125
132
|
}
|
|
126
133
|
catch {
|
|
127
134
|
// Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed
|
|
128
135
|
}
|
|
129
136
|
}
|
|
130
|
-
const url = generateSignOutUri({
|
|
137
|
+
const url = js.generateSignOutUri({
|
|
131
138
|
endSessionEndpoint,
|
|
132
139
|
postLogoutRedirectUri,
|
|
133
140
|
clientId,
|
|
@@ -144,8 +151,8 @@ class LogtoClient {
|
|
|
144
151
|
return null;
|
|
145
152
|
}
|
|
146
153
|
const item = JSON.parse(jsonItem);
|
|
147
|
-
if (!isLogtoSignInSessionItem(item)) {
|
|
148
|
-
throw new LogtoClientError('sign_in_session.invalid');
|
|
154
|
+
if (!index.isLogtoSignInSessionItem(item)) {
|
|
155
|
+
throw new errors.LogtoClientError('sign_in_session.invalid');
|
|
149
156
|
}
|
|
150
157
|
return item;
|
|
151
158
|
}
|
|
@@ -174,12 +181,12 @@ class LogtoClient {
|
|
|
174
181
|
async getAccessTokenByRefreshToken(resource) {
|
|
175
182
|
const currentRefreshToken = await this.getRefreshToken();
|
|
176
183
|
if (!currentRefreshToken) {
|
|
177
|
-
throw new LogtoClientError('not_authenticated');
|
|
184
|
+
throw new errors.LogtoClientError('not_authenticated');
|
|
178
185
|
}
|
|
179
|
-
const accessTokenKey = buildAccessTokenKey(resource);
|
|
186
|
+
const accessTokenKey = index$1.buildAccessTokenKey(resource);
|
|
180
187
|
const { appId: clientId } = this.logtoConfig;
|
|
181
188
|
const { tokenEndpoint } = await this.getOidcConfig();
|
|
182
|
-
const { accessToken, refreshToken, idToken, scope, expiresIn } = await fetchTokenByRefreshToken({
|
|
189
|
+
const { accessToken, refreshToken, idToken, scope, expiresIn } = await js.fetchTokenByRefreshToken({
|
|
183
190
|
clientId,
|
|
184
191
|
tokenEndpoint,
|
|
185
192
|
refreshToken: currentRefreshToken,
|
|
@@ -200,24 +207,24 @@ class LogtoClient {
|
|
|
200
207
|
}
|
|
201
208
|
async _getOidcConfig() {
|
|
202
209
|
const { endpoint } = this.logtoConfig;
|
|
203
|
-
const discoveryEndpoint = getDiscoveryEndpoint(endpoint);
|
|
204
|
-
return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);
|
|
210
|
+
const discoveryEndpoint = index$1.getDiscoveryEndpoint(endpoint);
|
|
211
|
+
return js.fetchOidcConfig(discoveryEndpoint, this.adapter.requester);
|
|
205
212
|
}
|
|
206
213
|
async _getJwtVerifyGetKey() {
|
|
207
214
|
const { jwksUri } = await this.getOidcConfig();
|
|
208
|
-
return createRemoteJWKSet(new URL(jwksUri));
|
|
215
|
+
return jose.createRemoteJWKSet(new URL(jwksUri));
|
|
209
216
|
}
|
|
210
217
|
async verifyIdToken(idToken) {
|
|
211
218
|
const { appId } = this.logtoConfig;
|
|
212
219
|
const { issuer } = await this.getOidcConfig();
|
|
213
220
|
const jwtVerifyGetKey = await this.getJwtVerifyGetKey();
|
|
214
|
-
await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);
|
|
221
|
+
await js.verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);
|
|
215
222
|
}
|
|
216
223
|
async saveCodeToken({ refreshToken, idToken, scope, accessToken, expiresIn, }) {
|
|
217
224
|
await this.setRefreshToken(refreshToken ?? null);
|
|
218
225
|
await this.setIdToken(idToken);
|
|
219
226
|
// NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)
|
|
220
|
-
const accessTokenKey = buildAccessTokenKey();
|
|
227
|
+
const accessTokenKey = index$1.buildAccessTokenKey();
|
|
221
228
|
const expiresAt = Date.now() / 1000 + expiresIn;
|
|
222
229
|
this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });
|
|
223
230
|
await this.saveAccessTokenMap();
|
|
@@ -237,7 +244,7 @@ class LogtoClient {
|
|
|
237
244
|
}
|
|
238
245
|
try {
|
|
239
246
|
const json = JSON.parse(raw);
|
|
240
|
-
if (!isLogtoAccessTokenMap(json)) {
|
|
247
|
+
if (!index.isLogtoAccessTokenMap(json)) {
|
|
241
248
|
return;
|
|
242
249
|
}
|
|
243
250
|
this.accessTokenMap.clear();
|
|
@@ -251,4 +258,32 @@ class LogtoClient {
|
|
|
251
258
|
}
|
|
252
259
|
}
|
|
253
260
|
|
|
254
|
-
|
|
261
|
+
Object.defineProperty(exports, 'LogtoError', {
|
|
262
|
+
enumerable: true,
|
|
263
|
+
get: function () { return js.LogtoError; }
|
|
264
|
+
});
|
|
265
|
+
Object.defineProperty(exports, 'LogtoRequestError', {
|
|
266
|
+
enumerable: true,
|
|
267
|
+
get: function () { return js.LogtoRequestError; }
|
|
268
|
+
});
|
|
269
|
+
Object.defineProperty(exports, 'OidcError', {
|
|
270
|
+
enumerable: true,
|
|
271
|
+
get: function () { return js.OidcError; }
|
|
272
|
+
});
|
|
273
|
+
Object.defineProperty(exports, 'Prompt', {
|
|
274
|
+
enumerable: true,
|
|
275
|
+
get: function () { return js.Prompt; }
|
|
276
|
+
});
|
|
277
|
+
Object.defineProperty(exports, 'ReservedScope', {
|
|
278
|
+
enumerable: true,
|
|
279
|
+
get: function () { return js.ReservedScope; }
|
|
280
|
+
});
|
|
281
|
+
Object.defineProperty(exports, 'UserScope', {
|
|
282
|
+
enumerable: true,
|
|
283
|
+
get: function () { return js.UserScope; }
|
|
284
|
+
});
|
|
285
|
+
exports.LogtoClientError = errors.LogtoClientError;
|
|
286
|
+
exports.isLogtoAccessTokenMap = index.isLogtoAccessTokenMap;
|
|
287
|
+
exports.isLogtoSignInSessionItem = index.isLogtoSignInSessionItem;
|
|
288
|
+
exports.createRequester = requester.createRequester;
|
|
289
|
+
exports.default = LogtoClient;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type IdTokenClaims, type UserInfoResponse, type InteractionMode, type AccessTokenClaims } from '@logto/js';
|
|
2
2
|
import type { Nullable } from '@silverhand/essentials';
|
|
3
|
-
import type { ClientAdapter } from './adapter';
|
|
4
|
-
import type { AccessToken, LogtoConfig, LogtoSignInSessionItem } from './types';
|
|
3
|
+
import type { ClientAdapter } from './adapter.js';
|
|
4
|
+
import type { AccessToken, LogtoConfig, LogtoSignInSessionItem } from './types/index.js';
|
|
5
5
|
export type { IdTokenClaims, LogtoErrorCode, UserInfoResponse, InteractionMode } from '@logto/js';
|
|
6
6
|
export { LogtoError, OidcError, Prompt, LogtoRequestError, ReservedScope, UserScope, } from '@logto/js';
|
|
7
|
-
export * from './errors';
|
|
8
|
-
export type { Storage, StorageKey, ClientAdapter } from './adapter';
|
|
9
|
-
export { createRequester } from './utils';
|
|
10
|
-
export * from './types';
|
|
7
|
+
export * from './errors.js';
|
|
8
|
+
export type { Storage, StorageKey, ClientAdapter } from './adapter.js';
|
|
9
|
+
export { createRequester } from './utils/index.js';
|
|
10
|
+
export * from './types/index.js';
|
|
11
11
|
export default class LogtoClient {
|
|
12
12
|
protected readonly logtoConfig: LogtoConfig;
|
|
13
|
-
protected readonly getOidcConfig:
|
|
14
|
-
|
|
15
|
-
token_endpoint: string;
|
|
16
|
-
userinfo_endpoint: string;
|
|
17
|
-
end_session_endpoint: string;
|
|
18
|
-
revocation_endpoint: string;
|
|
19
|
-
jwks_uri: string;
|
|
20
|
-
issuer: string;
|
|
21
|
-
}>>;
|
|
22
|
-
protected readonly getJwtVerifyGetKey: () => Promise<(protectedHeader?: import("jose").JWSHeaderParameters | undefined, token?: import("jose").FlattenedJWSInput | undefined) => Promise<import("jose").KeyLike>>;
|
|
13
|
+
protected readonly getOidcConfig: typeof this._getOidcConfig;
|
|
14
|
+
protected readonly getJwtVerifyGetKey: (...args: unknown[]) => Promise<(protectedHeader?: import("jose").JWSHeaderParameters | undefined, token?: import("jose").FlattenedJWSInput | undefined) => Promise<import("jose").KeyLike>>;
|
|
23
15
|
protected readonly adapter: ClientAdapter;
|
|
24
16
|
protected readonly accessTokenMap: Map<string, AccessToken>;
|
|
25
17
|
constructor(logtoConfig: LogtoConfig, adapter: ClientAdapter);
|
|
@@ -28,6 +20,7 @@ export default class LogtoClient {
|
|
|
28
20
|
getIdToken(): Promise<Nullable<string>>;
|
|
29
21
|
getAccessToken(resource?: string): Promise<string>;
|
|
30
22
|
getIdTokenClaims(): Promise<IdTokenClaims>;
|
|
23
|
+
getAccessTokenClaims(resource?: string): Promise<AccessTokenClaims>;
|
|
31
24
|
fetchUserInfo(): Promise<UserInfoResponse>;
|
|
32
25
|
signIn(redirectUri: string, interactionMode?: InteractionMode): Promise<void>;
|
|
33
26
|
isSignInRedirected(url: string): Promise<boolean>;
|
package/lib/index.js
CHANGED
|
@@ -1,28 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var index = require('./types/index.js');
|
|
10
|
-
var index$1 = require('./utils/index.js');
|
|
11
|
-
var requester = require('./utils/requester.js');
|
|
12
|
-
|
|
13
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
|
-
|
|
15
|
-
var once__default = /*#__PURE__*/_interopDefault(once);
|
|
1
|
+
import { Prompt, withDefaultScopes, decodeIdToken, decodeAccessToken, fetchUserInfo, generateSignInUri, verifyAndParseCodeFromCallbackUri, fetchTokenByAuthorizationCode, revoke, generateSignOutUri, fetchTokenByRefreshToken, fetchOidcConfig, verifyIdToken } from '@logto/js';
|
|
2
|
+
export { LogtoError, LogtoRequestError, OidcError, Prompt, ReservedScope, UserScope } from '@logto/js';
|
|
3
|
+
import { createRemoteJWKSet } from 'jose';
|
|
4
|
+
import { LogtoClientError } from './errors.js';
|
|
5
|
+
import { isLogtoSignInSessionItem, isLogtoAccessTokenMap } from './types/index.js';
|
|
6
|
+
import { buildAccessTokenKey, getDiscoveryEndpoint } from './utils/index.js';
|
|
7
|
+
import { once } from './utils/once.js';
|
|
8
|
+
export { createRequester } from './utils/requester.js';
|
|
16
9
|
|
|
17
10
|
class LogtoClient {
|
|
18
11
|
constructor(logtoConfig, adapter) {
|
|
19
|
-
this.getOidcConfig =
|
|
20
|
-
this.getJwtVerifyGetKey =
|
|
12
|
+
this.getOidcConfig = once(this._getOidcConfig);
|
|
13
|
+
this.getJwtVerifyGetKey = once(this._getJwtVerifyGetKey);
|
|
21
14
|
this.accessTokenMap = new Map();
|
|
22
15
|
this.logtoConfig = {
|
|
23
16
|
...logtoConfig,
|
|
24
|
-
prompt: logtoConfig.prompt ??
|
|
25
|
-
scopes:
|
|
17
|
+
prompt: logtoConfig.prompt ?? Prompt.Consent,
|
|
18
|
+
scopes: withDefaultScopes(logtoConfig.scopes).split(' '),
|
|
26
19
|
};
|
|
27
20
|
this.adapter = adapter;
|
|
28
21
|
void this.loadAccessTokenMap();
|
|
@@ -38,9 +31,9 @@ class LogtoClient {
|
|
|
38
31
|
}
|
|
39
32
|
async getAccessToken(resource) {
|
|
40
33
|
if (!(await this.getIdToken())) {
|
|
41
|
-
throw new
|
|
34
|
+
throw new LogtoClientError('not_authenticated');
|
|
42
35
|
}
|
|
43
|
-
const accessTokenKey =
|
|
36
|
+
const accessTokenKey = buildAccessTokenKey(resource);
|
|
44
37
|
const accessToken = this.accessTokenMap.get(accessTokenKey);
|
|
45
38
|
if (accessToken && accessToken.expiresAt > Date.now() / 1000) {
|
|
46
39
|
return accessToken.token;
|
|
@@ -57,17 +50,21 @@ class LogtoClient {
|
|
|
57
50
|
async getIdTokenClaims() {
|
|
58
51
|
const idToken = await this.getIdToken();
|
|
59
52
|
if (!idToken) {
|
|
60
|
-
throw new
|
|
53
|
+
throw new LogtoClientError('not_authenticated');
|
|
61
54
|
}
|
|
62
|
-
return
|
|
55
|
+
return decodeIdToken(idToken);
|
|
56
|
+
}
|
|
57
|
+
async getAccessTokenClaims(resource) {
|
|
58
|
+
const accessToken = await this.getAccessToken(resource);
|
|
59
|
+
return decodeAccessToken(accessToken);
|
|
63
60
|
}
|
|
64
61
|
async fetchUserInfo() {
|
|
65
62
|
const { userinfoEndpoint } = await this.getOidcConfig();
|
|
66
63
|
const accessToken = await this.getAccessToken();
|
|
67
64
|
if (!accessToken) {
|
|
68
|
-
throw new
|
|
65
|
+
throw new LogtoClientError('fetch_user_info_failed');
|
|
69
66
|
}
|
|
70
|
-
return
|
|
67
|
+
return fetchUserInfo(userinfoEndpoint, accessToken, this.adapter.requester);
|
|
71
68
|
}
|
|
72
69
|
async signIn(redirectUri, interactionMode) {
|
|
73
70
|
const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;
|
|
@@ -75,7 +72,7 @@ class LogtoClient {
|
|
|
75
72
|
const codeVerifier = this.adapter.generateCodeVerifier();
|
|
76
73
|
const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier);
|
|
77
74
|
const state = this.adapter.generateState();
|
|
78
|
-
const signInUri =
|
|
75
|
+
const signInUri = generateSignInUri({
|
|
79
76
|
authorizationEndpoint,
|
|
80
77
|
clientId,
|
|
81
78
|
redirectUri,
|
|
@@ -105,13 +102,13 @@ class LogtoClient {
|
|
|
105
102
|
const { requester } = adapter;
|
|
106
103
|
const signInSession = await this.getSignInSession();
|
|
107
104
|
if (!signInSession) {
|
|
108
|
-
throw new
|
|
105
|
+
throw new LogtoClientError('sign_in_session.not_found');
|
|
109
106
|
}
|
|
110
107
|
const { redirectUri, state, codeVerifier } = signInSession;
|
|
111
|
-
const code =
|
|
108
|
+
const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);
|
|
112
109
|
const { appId: clientId } = logtoConfig;
|
|
113
110
|
const { tokenEndpoint } = await this.getOidcConfig();
|
|
114
|
-
const codeTokenResponse = await
|
|
111
|
+
const codeTokenResponse = await fetchTokenByAuthorizationCode({
|
|
115
112
|
clientId,
|
|
116
113
|
tokenEndpoint,
|
|
117
114
|
redirectUri,
|
|
@@ -128,13 +125,13 @@ class LogtoClient {
|
|
|
128
125
|
const refreshToken = await this.getRefreshToken();
|
|
129
126
|
if (refreshToken) {
|
|
130
127
|
try {
|
|
131
|
-
await
|
|
128
|
+
await revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester);
|
|
132
129
|
}
|
|
133
130
|
catch {
|
|
134
131
|
// Do nothing at this point, as we don't want to break the sign-out flow even if the revocation is failed
|
|
135
132
|
}
|
|
136
133
|
}
|
|
137
|
-
const url =
|
|
134
|
+
const url = generateSignOutUri({
|
|
138
135
|
endSessionEndpoint,
|
|
139
136
|
postLogoutRedirectUri,
|
|
140
137
|
clientId,
|
|
@@ -151,8 +148,8 @@ class LogtoClient {
|
|
|
151
148
|
return null;
|
|
152
149
|
}
|
|
153
150
|
const item = JSON.parse(jsonItem);
|
|
154
|
-
if (!
|
|
155
|
-
throw new
|
|
151
|
+
if (!isLogtoSignInSessionItem(item)) {
|
|
152
|
+
throw new LogtoClientError('sign_in_session.invalid');
|
|
156
153
|
}
|
|
157
154
|
return item;
|
|
158
155
|
}
|
|
@@ -181,12 +178,12 @@ class LogtoClient {
|
|
|
181
178
|
async getAccessTokenByRefreshToken(resource) {
|
|
182
179
|
const currentRefreshToken = await this.getRefreshToken();
|
|
183
180
|
if (!currentRefreshToken) {
|
|
184
|
-
throw new
|
|
181
|
+
throw new LogtoClientError('not_authenticated');
|
|
185
182
|
}
|
|
186
|
-
const accessTokenKey =
|
|
183
|
+
const accessTokenKey = buildAccessTokenKey(resource);
|
|
187
184
|
const { appId: clientId } = this.logtoConfig;
|
|
188
185
|
const { tokenEndpoint } = await this.getOidcConfig();
|
|
189
|
-
const { accessToken, refreshToken, idToken, scope, expiresIn } = await
|
|
186
|
+
const { accessToken, refreshToken, idToken, scope, expiresIn } = await fetchTokenByRefreshToken({
|
|
190
187
|
clientId,
|
|
191
188
|
tokenEndpoint,
|
|
192
189
|
refreshToken: currentRefreshToken,
|
|
@@ -207,24 +204,24 @@ class LogtoClient {
|
|
|
207
204
|
}
|
|
208
205
|
async _getOidcConfig() {
|
|
209
206
|
const { endpoint } = this.logtoConfig;
|
|
210
|
-
const discoveryEndpoint =
|
|
211
|
-
return
|
|
207
|
+
const discoveryEndpoint = getDiscoveryEndpoint(endpoint);
|
|
208
|
+
return fetchOidcConfig(discoveryEndpoint, this.adapter.requester);
|
|
212
209
|
}
|
|
213
210
|
async _getJwtVerifyGetKey() {
|
|
214
211
|
const { jwksUri } = await this.getOidcConfig();
|
|
215
|
-
return
|
|
212
|
+
return createRemoteJWKSet(new URL(jwksUri));
|
|
216
213
|
}
|
|
217
214
|
async verifyIdToken(idToken) {
|
|
218
215
|
const { appId } = this.logtoConfig;
|
|
219
216
|
const { issuer } = await this.getOidcConfig();
|
|
220
217
|
const jwtVerifyGetKey = await this.getJwtVerifyGetKey();
|
|
221
|
-
await
|
|
218
|
+
await verifyIdToken(idToken, appId, issuer, jwtVerifyGetKey);
|
|
222
219
|
}
|
|
223
220
|
async saveCodeToken({ refreshToken, idToken, scope, accessToken, expiresIn, }) {
|
|
224
221
|
await this.setRefreshToken(refreshToken ?? null);
|
|
225
222
|
await this.setIdToken(idToken);
|
|
226
223
|
// NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)
|
|
227
|
-
const accessTokenKey =
|
|
224
|
+
const accessTokenKey = buildAccessTokenKey();
|
|
228
225
|
const expiresAt = Date.now() / 1000 + expiresIn;
|
|
229
226
|
this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, expiresAt });
|
|
230
227
|
await this.saveAccessTokenMap();
|
|
@@ -244,7 +241,7 @@ class LogtoClient {
|
|
|
244
241
|
}
|
|
245
242
|
try {
|
|
246
243
|
const json = JSON.parse(raw);
|
|
247
|
-
if (!
|
|
244
|
+
if (!isLogtoAccessTokenMap(json)) {
|
|
248
245
|
return;
|
|
249
246
|
}
|
|
250
247
|
this.accessTokenMap.clear();
|
|
@@ -258,32 +255,4 @@ class LogtoClient {
|
|
|
258
255
|
}
|
|
259
256
|
}
|
|
260
257
|
|
|
261
|
-
|
|
262
|
-
enumerable: true,
|
|
263
|
-
get: function () { return js.LogtoError; }
|
|
264
|
-
});
|
|
265
|
-
Object.defineProperty(exports, 'LogtoRequestError', {
|
|
266
|
-
enumerable: true,
|
|
267
|
-
get: function () { return js.LogtoRequestError; }
|
|
268
|
-
});
|
|
269
|
-
Object.defineProperty(exports, 'OidcError', {
|
|
270
|
-
enumerable: true,
|
|
271
|
-
get: function () { return js.OidcError; }
|
|
272
|
-
});
|
|
273
|
-
Object.defineProperty(exports, 'Prompt', {
|
|
274
|
-
enumerable: true,
|
|
275
|
-
get: function () { return js.Prompt; }
|
|
276
|
-
});
|
|
277
|
-
Object.defineProperty(exports, 'ReservedScope', {
|
|
278
|
-
enumerable: true,
|
|
279
|
-
get: function () { return js.ReservedScope; }
|
|
280
|
-
});
|
|
281
|
-
Object.defineProperty(exports, 'UserScope', {
|
|
282
|
-
enumerable: true,
|
|
283
|
-
get: function () { return js.UserScope; }
|
|
284
|
-
});
|
|
285
|
-
exports.LogtoClientError = errors.LogtoClientError;
|
|
286
|
-
exports.isLogtoAccessTokenMap = index.isLogtoAccessTokenMap;
|
|
287
|
-
exports.isLogtoSignInSessionItem = index.isLogtoSignInSessionItem;
|
|
288
|
-
exports.createRequester = requester.createRequester;
|
|
289
|
-
exports.default = LogtoClient;
|
|
258
|
+
export { LogtoClientError, LogtoClient as default, isLogtoAccessTokenMap, isLogtoSignInSessionItem };
|
package/lib/mock.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/// <reference types="jest" />
|
|
2
2
|
import { Prompt } from '@logto/js';
|
|
3
3
|
import type { Nullable } from '@silverhand/essentials';
|
|
4
|
-
import type {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
4
|
+
import type { Storage } from './adapter.js';
|
|
5
|
+
import type { AccessToken, LogtoConfig, LogtoSignInSessionItem } from './index.js';
|
|
6
|
+
import LogtoClient from './index.js';
|
|
7
7
|
export declare const appId = "app_id_value";
|
|
8
8
|
export declare const endpoint = "https://logto.dev";
|
|
9
9
|
export declare class MockedStorage implements Storage {
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var js = require('@logto/js');
|
|
2
4
|
|
|
3
5
|
const isLogtoSignInSessionItem = (data) => {
|
|
4
|
-
if (!isArbitraryObject(data)) {
|
|
6
|
+
if (!js.isArbitraryObject(data)) {
|
|
5
7
|
return false;
|
|
6
8
|
}
|
|
7
9
|
return ['redirectUri', 'codeVerifier', 'state'].every((key) => typeof data[key] === 'string');
|
|
8
10
|
};
|
|
9
11
|
const isLogtoAccessTokenMap = (data) => {
|
|
10
|
-
if (!isArbitraryObject(data)) {
|
|
12
|
+
if (!js.isArbitraryObject(data)) {
|
|
11
13
|
return false;
|
|
12
14
|
}
|
|
13
15
|
return Object.values(data).every((value) => {
|
|
14
|
-
if (!isArbitraryObject(value)) {
|
|
16
|
+
if (!js.isArbitraryObject(value)) {
|
|
15
17
|
return false;
|
|
16
18
|
}
|
|
17
19
|
return (typeof value.token === 'string' &&
|
|
@@ -20,4 +22,5 @@ const isLogtoAccessTokenMap = (data) => {
|
|
|
20
22
|
});
|
|
21
23
|
};
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
exports.isLogtoAccessTokenMap = isLogtoAccessTokenMap;
|
|
26
|
+
exports.isLogtoSignInSessionItem = isLogtoSignInSessionItem;
|
package/lib/types/index.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var js = require('@logto/js');
|
|
1
|
+
import { isArbitraryObject } from '@logto/js';
|
|
4
2
|
|
|
5
3
|
const isLogtoSignInSessionItem = (data) => {
|
|
6
|
-
if (!
|
|
4
|
+
if (!isArbitraryObject(data)) {
|
|
7
5
|
return false;
|
|
8
6
|
}
|
|
9
7
|
return ['redirectUri', 'codeVerifier', 'state'].every((key) => typeof data[key] === 'string');
|
|
10
8
|
};
|
|
11
9
|
const isLogtoAccessTokenMap = (data) => {
|
|
12
|
-
if (!
|
|
10
|
+
if (!isArbitraryObject(data)) {
|
|
13
11
|
return false;
|
|
14
12
|
}
|
|
15
13
|
return Object.values(data).every((value) => {
|
|
16
|
-
if (!
|
|
14
|
+
if (!isArbitraryObject(value)) {
|
|
17
15
|
return false;
|
|
18
16
|
}
|
|
19
17
|
return (typeof value.token === 'string' &&
|
|
@@ -22,5 +20,4 @@ const isLogtoAccessTokenMap = (data) => {
|
|
|
22
20
|
});
|
|
23
21
|
};
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
exports.isLogtoSignInSessionItem = isLogtoSignInSessionItem;
|
|
23
|
+
export { isLogtoAccessTokenMap, isLogtoSignInSessionItem };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var js = require('@logto/js');
|
|
4
|
+
|
|
5
|
+
const buildAccessTokenKey = (resource = '', scopes = []) => `${scopes.slice().sort().join(' ')}@${resource}`;
|
|
6
|
+
const getDiscoveryEndpoint = (endpoint) => new URL(js.discoveryPath, endpoint).toString();
|
|
7
|
+
|
|
8
|
+
exports.buildAccessTokenKey = buildAccessTokenKey;
|
|
9
|
+
exports.getDiscoveryEndpoint = getDiscoveryEndpoint;
|
package/lib/utils/index.d.ts
CHANGED
package/lib/utils/index.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var js = require('@logto/js');
|
|
1
|
+
import { discoveryPath } from '@logto/js';
|
|
4
2
|
|
|
5
3
|
const buildAccessTokenKey = (resource = '', scopes = []) => `${scopes.slice().sort().join(' ')}@${resource}`;
|
|
6
|
-
const getDiscoveryEndpoint = (endpoint) => new URL(
|
|
4
|
+
const getDiscoveryEndpoint = (endpoint) => new URL(discoveryPath, endpoint).toString();
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
exports.getDiscoveryEndpoint = getDiscoveryEndpoint;
|
|
6
|
+
export { buildAccessTokenKey, getDiscoveryEndpoint };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// TODO @sijie move to essentials
|
|
4
|
+
/* eslint-disable @silverhand/fp/no-let */
|
|
5
|
+
/* eslint-disable @silverhand/fp/no-mutation */
|
|
6
|
+
function once(function_) {
|
|
7
|
+
let called = false;
|
|
8
|
+
let result;
|
|
9
|
+
return function (...args) {
|
|
10
|
+
if (!called) {
|
|
11
|
+
called = true;
|
|
12
|
+
result = function_.apply(this, args);
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/* eslint-enable @silverhand/fp/no-mutation */
|
|
18
|
+
/* eslint-enable @silverhand/fp/no-let */
|
|
19
|
+
|
|
20
|
+
exports.once = once;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// TODO @sijie move to essentials
|
|
2
|
+
/* eslint-disable @silverhand/fp/no-let */
|
|
3
|
+
/* eslint-disable @silverhand/fp/no-mutation */
|
|
4
|
+
function once(function_) {
|
|
5
|
+
let called = false;
|
|
6
|
+
let result;
|
|
7
|
+
return function (...args) {
|
|
8
|
+
if (!called) {
|
|
9
|
+
called = true;
|
|
10
|
+
result = function_.apply(this, args);
|
|
11
|
+
}
|
|
12
|
+
return result;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/* eslint-enable @silverhand/fp/no-mutation */
|
|
16
|
+
/* eslint-enable @silverhand/fp/no-let */
|
|
17
|
+
|
|
18
|
+
export { once };
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var js = require('@logto/js');
|
|
2
4
|
|
|
3
5
|
const createRequester = (fetchFunction) => {
|
|
4
6
|
return async (...args) => {
|
|
5
7
|
const response = await fetchFunction(...args);
|
|
6
8
|
if (!response.ok) {
|
|
7
9
|
const responseJson = await response.json();
|
|
8
|
-
if (!isLogtoRequestError(responseJson)) {
|
|
9
|
-
throw new LogtoError('unexpected_response_error', responseJson);
|
|
10
|
+
if (!js.isLogtoRequestError(responseJson)) {
|
|
11
|
+
throw new js.LogtoError('unexpected_response_error', responseJson);
|
|
10
12
|
}
|
|
11
13
|
// Expected request error from server
|
|
12
14
|
const { code, message } = responseJson;
|
|
13
|
-
throw new LogtoRequestError(code, message);
|
|
15
|
+
throw new js.LogtoRequestError(code, message);
|
|
14
16
|
}
|
|
15
17
|
return response.json();
|
|
16
18
|
};
|
|
17
19
|
};
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
exports.createRequester = createRequester;
|
package/lib/utils/requester.js
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var js = require('@logto/js');
|
|
1
|
+
import { isLogtoRequestError, LogtoError, LogtoRequestError } from '@logto/js';
|
|
4
2
|
|
|
5
3
|
const createRequester = (fetchFunction) => {
|
|
6
4
|
return async (...args) => {
|
|
7
5
|
const response = await fetchFunction(...args);
|
|
8
6
|
if (!response.ok) {
|
|
9
7
|
const responseJson = await response.json();
|
|
10
|
-
if (!
|
|
11
|
-
throw new
|
|
8
|
+
if (!isLogtoRequestError(responseJson)) {
|
|
9
|
+
throw new LogtoError('unexpected_response_error', responseJson);
|
|
12
10
|
}
|
|
13
11
|
// Expected request error from server
|
|
14
12
|
const { code, message } = responseJson;
|
|
15
|
-
throw new
|
|
13
|
+
throw new LogtoRequestError(code, message);
|
|
16
14
|
}
|
|
17
15
|
return response.json();
|
|
18
16
|
};
|
|
19
17
|
};
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
export { createRequester };
|
package/package.json
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/client",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"main": "./lib/index.
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./lib/index.cjs",
|
|
6
|
+
"module": "./lib/index.js",
|
|
7
|
+
"types": "./lib/index.d.ts",
|
|
6
8
|
"exports": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
+
"types": "./lib/index.d.ts",
|
|
10
|
+
"require": "./lib/index.cjs",
|
|
11
|
+
"import": "./lib/index.js",
|
|
12
|
+
"default": "./lib/index.js"
|
|
9
13
|
},
|
|
10
|
-
"module": "./lib/index.mjs",
|
|
11
|
-
"types": "./lib/index.d.ts",
|
|
12
14
|
"files": [
|
|
13
15
|
"lib"
|
|
14
16
|
],
|
|
@@ -18,33 +20,18 @@
|
|
|
18
20
|
"url": "https://github.com/logto-io/js.git",
|
|
19
21
|
"directory": "packages/client"
|
|
20
22
|
},
|
|
21
|
-
"scripts": {
|
|
22
|
-
"dev:tsc": "tsc -p tsconfig.build.json -w --preserveWatchOutput",
|
|
23
|
-
"precommit": "lint-staged",
|
|
24
|
-
"check": "tsc --noEmit",
|
|
25
|
-
"build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c",
|
|
26
|
-
"lint": "eslint --ext .ts src",
|
|
27
|
-
"test": "jest",
|
|
28
|
-
"test:coverage": "jest --silent --env=jsdom && jest --silent --coverage",
|
|
29
|
-
"prepack": "pnpm test"
|
|
30
|
-
},
|
|
31
23
|
"dependencies": {
|
|
32
|
-
"@logto/js": "^
|
|
33
|
-
"@silverhand/essentials": "^2.6.
|
|
24
|
+
"@logto/js": "^2.1.0",
|
|
25
|
+
"@silverhand/essentials": "^2.6.2",
|
|
34
26
|
"camelcase-keys": "^7.0.1",
|
|
35
|
-
"jose": "^4.13.2"
|
|
36
|
-
"lodash.get": "^4.4.2",
|
|
37
|
-
"lodash.once": "^4.1.1"
|
|
27
|
+
"jose": "^4.13.2"
|
|
38
28
|
},
|
|
39
29
|
"devDependencies": {
|
|
40
|
-
"@
|
|
41
|
-
"@silverhand/
|
|
42
|
-
"@silverhand/ts-config": "^1.0.0",
|
|
30
|
+
"@silverhand/eslint-config": "^3.0.1",
|
|
31
|
+
"@silverhand/ts-config": "^3.0.0",
|
|
43
32
|
"@swc/core": "^1.3.50",
|
|
44
33
|
"@swc/jest": "^0.2.24",
|
|
45
34
|
"@types/jest": "^29.5.0",
|
|
46
|
-
"@types/lodash.get": "^4.4.6",
|
|
47
|
-
"@types/lodash.once": "^4.1.7",
|
|
48
35
|
"@types/node": "^18.0.0",
|
|
49
36
|
"eslint": "^8.38.0",
|
|
50
37
|
"jest": "^29.5.0",
|
|
@@ -63,5 +50,13 @@
|
|
|
63
50
|
"publishConfig": {
|
|
64
51
|
"access": "public"
|
|
65
52
|
},
|
|
66
|
-
"
|
|
67
|
-
|
|
53
|
+
"scripts": {
|
|
54
|
+
"dev:tsc": "tsc -p tsconfig.build.json -w --preserveWatchOutput",
|
|
55
|
+
"precommit": "lint-staged",
|
|
56
|
+
"check": "tsc --noEmit",
|
|
57
|
+
"build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c",
|
|
58
|
+
"lint": "eslint --ext .ts src",
|
|
59
|
+
"test": "jest",
|
|
60
|
+
"test:coverage": "jest --silent --env=jsdom && jest --silent --coverage"
|
|
61
|
+
}
|
|
62
|
+
}
|
package/lib/errors.mjs
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import get from 'lodash.get';
|
|
2
|
-
|
|
3
|
-
const logtoClientErrorCodes = Object.freeze({
|
|
4
|
-
sign_in_session: {
|
|
5
|
-
invalid: 'Invalid sign-in session.',
|
|
6
|
-
not_found: 'Sign-in session not found.',
|
|
7
|
-
},
|
|
8
|
-
not_authenticated: 'Not authenticated.',
|
|
9
|
-
fetch_user_info_failed: 'Unable to fetch user info. The access token may be invalid.',
|
|
10
|
-
});
|
|
11
|
-
const getMessageByErrorCode = (errorCode) => {
|
|
12
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
13
|
-
const message = get(logtoClientErrorCodes, errorCode);
|
|
14
|
-
if (typeof message === 'string') {
|
|
15
|
-
return message;
|
|
16
|
-
}
|
|
17
|
-
return errorCode;
|
|
18
|
-
};
|
|
19
|
-
class LogtoClientError extends Error {
|
|
20
|
-
constructor(code, data) {
|
|
21
|
-
super(getMessageByErrorCode(code));
|
|
22
|
-
this.code = code;
|
|
23
|
-
this.data = data;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export { LogtoClientError };
|
package/lib/utils/index.mjs
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { discoveryPath } from '@logto/js';
|
|
2
|
-
|
|
3
|
-
const buildAccessTokenKey = (resource = '', scopes = []) => `${scopes.slice().sort().join(' ')}@${resource}`;
|
|
4
|
-
const getDiscoveryEndpoint = (endpoint) => new URL(discoveryPath, endpoint).toString();
|
|
5
|
-
|
|
6
|
-
export { buildAccessTokenKey, getDiscoveryEndpoint };
|